diff --git a/eotimeseriesviewer/docks.py b/eotimeseriesviewer/docks.py
index 2eb6a1bd7eeddeade239e5b467ca762d7f2f5e61..39377bb4724d9cf84a91ebf9c78fd869a8c4b259 100644
--- a/eotimeseriesviewer/docks.py
+++ b/eotimeseriesviewer/docks.py
@@ -10,7 +10,7 @@ from eotimeseriesviewer.labeling import LabelWidget, gotoNextFeature, gotoPrevio
 
 class SpectralLibraryDockWidget(SpectralLibraryPanel):
     def __init__(self, speclib: SpectralLibrary, *args, **kwds):
-        super().__init__(*args, **kwds)
+        super().__init__(*args, speclib=speclib, **kwds)
         assert isinstance(self.SLW, SpectralLibraryWidget)
         self.mActionNextFeature = QAction('Next Feature', parent=self)
         self.mActionNextFeature.setIcon(QIcon(':/images/themes/default/mActionAtlasNext.svg'))
@@ -31,7 +31,7 @@ class SpectralLibraryDockWidget(SpectralLibraryPanel):
 
         self.SLW.mToolbar: QToolBar
         self.SLW.mToolbar.insertActions(self.SLW.mActionToggleEditing,
-                                                   [self.mActionPreviousFeature, self.mActionNextFeature])
+                                        [self.mActionPreviousFeature, self.mActionNextFeature])
         self.SLW.mToolbar.insertSeparator(self.SLW.mActionToggleEditing)
 
     def setVectorLayerTools(self, tools: QgsVectorLayerTools):
diff --git a/eotimeseriesviewer/externals/qps/__init__.py b/eotimeseriesviewer/externals/qps/__init__.py
index 2667579da0d75c8da976ec67f3c033c6db964869..c1fbe1fffcae5c3a9fed78dfe10ff15b3a61a30d 100644
--- a/eotimeseriesviewer/externals/qps/__init__.py
+++ b/eotimeseriesviewer/externals/qps/__init__.py
@@ -24,19 +24,24 @@
 ***************************************************************************
 """
 
-import sys, importlib, site, os, pathlib, typing
+import pathlib
+import sys
+import typing
+
 from qgis.core import QgsApplication
-from qgis.gui import QgisInterface, QgsMapLayerConfigWidgetFactory
+from qgis.gui import QgsMapLayerConfigWidgetFactory
+
 __version__ = '1.0'
 
-DIR_UI_FILES = pathlib.Path(__file__).parent / 'ui'
+DIR_QPS = pathlib.Path(__file__).parent
+DIR_UI_FILES = DIR_QPS / 'ui'
 DIR_ICONS = DIR_UI_FILES / 'icons'
-QPS_RESOURCE_FILE = pathlib.Path(__file__).parent / 'qpsresources_rc.py'
-
+QPS_RESOURCE_FILE = DIR_QPS / 'qpsresources_rc.py'
 
 MAPLAYER_CONFIGWIDGET_FACTORIES = list()
 
-def registerMapLayerConfigWidgetFactory(factory:QgsMapLayerConfigWidgetFactory):
+
+def registerMapLayerConfigWidgetFactory(factory: QgsMapLayerConfigWidgetFactory):
     """
     Register a new tab in the map layer properties dialog.
     :param factory: QgsMapLayerConfigWidgetFactory
@@ -48,7 +53,8 @@ def registerMapLayerConfigWidgetFactory(factory:QgsMapLayerConfigWidgetFactory):
     if factory not in MAPLAYER_CONFIGWIDGET_FACTORIES:
         MAPLAYER_CONFIGWIDGET_FACTORIES.append(factory)
 
-def unregisterMapLayerConfigWidgetFactory(factory:QgsMapLayerConfigWidgetFactory):
+
+def unregisterMapLayerConfigWidgetFactory(factory: QgsMapLayerConfigWidgetFactory):
     """
     Unregister a previously registered tab in the map layer properties dialog.
     :param factory:
@@ -60,6 +66,7 @@ def unregisterMapLayerConfigWidgetFactory(factory:QgsMapLayerConfigWidgetFactory
     while factory in MAPLAYER_CONFIGWIDGET_FACTORIES:
         MAPLAYER_CONFIGWIDGET_FACTORIES.remove(factory)
 
+
 def mapLayerConfigWidgetFactories() -> typing.List[QgsMapLayerConfigWidgetFactory]:
     """
     Returns registered QgsMapLayerConfigWidgetFactories
@@ -68,6 +75,7 @@ def mapLayerConfigWidgetFactories() -> typing.List[QgsMapLayerConfigWidgetFactor
     """
     return MAPLAYER_CONFIGWIDGET_FACTORIES[:]
 
+
 def registerEditorWidgets():
     """
     Call this function to register QgsEditorwidgetFactories to the QgsEditorWidgetRegistry
@@ -112,12 +120,13 @@ def registerMapLayerConfigWidgetFactories():
     registerMapLayerConfigWidgetFactory(RasterBandConfigWidgetFactory())
     registerMapLayerConfigWidgetFactory(GDALMetadataConfigWidgetFactory())
 
+
 def initResources():
     from .testing import initResourceFile
     initResourceFile(QPS_RESOURCE_FILE)
 
+
 def initAll():
     initResources()
     registerEditorWidgets()
     registerMapLayerConfigWidgetFactories()
-
diff --git a/eotimeseriesviewer/externals/qps/resources.py b/eotimeseriesviewer/externals/qps/resources.py
index 914aded28d11f2854e9a170451627f0dd038d8ee..4a10b3424b5ced417bb367cb131abc89a633dbb5 100644
--- a/eotimeseriesviewer/externals/qps/resources.py
+++ b/eotimeseriesviewer/externals/qps/resources.py
@@ -25,14 +25,21 @@
 ***************************************************************************
 """
 
-import sys, os, pathlib, typing, re
+import os
+import pathlib
+import re
+import sys
+import typing
+import site
+
+from qgis.PyQt.QtCore import *
 from qgis.PyQt.QtGui import *
+from qgis.PyQt.QtSvg import QGraphicsSvgItem
 from qgis.PyQt.QtWidgets import *
-from qgis.PyQt.QtCore import *
 from qgis.PyQt.QtXml import *
-from qgis.PyQt.QtSvg import QGraphicsSvgItem
 
 from .utils import file_search, findUpwardPath
+
 REGEX_FILEXTENSION_IMAGE = re.compile(r'\.([^.]+)$')
 
 
@@ -45,7 +52,8 @@ def getDOMAttributes(elem):
         values[str(attr.nodeName())] = attr.nodeValue()
     return values
 
-def compileResourceFiles(dirRoot:str, targetDir:str=None, suffix:str= '_rc.py'):
+
+def compileResourceFiles(dirRoot: str, targetDir: str = None, suffix: str = '_rc.py'):
     """
     Searches for *.ui files and compiles the *.qrc files they use.
     :param dirRoot: str, root directory, in which to search for *.qrc files or a list of *.ui file paths.
@@ -125,7 +133,8 @@ def compileResourceFiles(dirRoot:str, targetDir:str=None, suffix:str= '_rc.py'):
         for qrcFile in qrc_files_skipped:
             print(qrcFile.as_posix())
 
-def compileResourceFile(pathQrc, targetDir=None, suffix:str='_rc.py', compressLevel=7, compressThreshold=100):
+
+def compileResourceFile(pathQrc, targetDir=None, suffix: str = '_rc.py', compressLevel=7, compressThreshold=100):
     """
     Compiles a *.qrc file
     :param pathQrc:
@@ -145,7 +154,6 @@ def compileResourceFile(pathQrc, targetDir=None, suffix:str='_rc.py', compressLe
     assert isinstance(targetDir, pathlib.Path)
     targetDir = targetDir.resolve()
 
-
     cwd = pathlib.Path(pathQrc).parent
 
     pathPy = targetDir / (os.path.splitext(pathQrc.name)[0] + suffix)
@@ -155,7 +163,7 @@ def compileResourceFile(pathQrc, targetDir=None, suffix:str='_rc.py', compressLe
 
     cmd = 'pyrcc5 -compress {} -o {} {}'.format(compressLevel, pathPy, pathQrc)
     cmd2 = 'pyrcc5 -no-compress -o {} {}'.format(pathPy.as_posix(), pathQrc.name)
-    #print(cmd)
+    # print(cmd)
 
     import PyQt5.pyrcc_main
 
@@ -179,7 +187,7 @@ def compileResourceFile(pathQrc, targetDir=None, suffix:str='_rc.py', compressLe
     os.chdir(last_cwd)
 
 
-def compileQGISResourceFiles(qgis_repo:str, target:str=None):
+def compileQGISResourceFiles(qgis_repo: str, target: str = None):
     """
     Searches for *.qrc files in the QGIS repository and compile them to <target>
 
@@ -202,7 +210,8 @@ def compileQGISResourceFiles(qgis_repo:str, target:str=None):
         qgis_repo = pathlib.Path(qgis_repo)
     assert isinstance(qgis_repo, pathlib.Path)
     assert qgis_repo.is_dir()
-    assert (qgis_repo / 'images' /'images.qrc').is_file(), '{} is not the QGIS repository root'.format(qgis_repo.as_posix())
+    assert (qgis_repo / 'images' / 'images.qrc').is_file(), '{} is not the QGIS repository root'.format(
+        qgis_repo.as_posix())
 
     if target is None:
         DIR_REPO = findUpwardPath(__file__, '.git')
@@ -260,9 +269,9 @@ def initResourceFile(path):
     try:
         __import__(name)
         # spec = importlib.util.spec_from_file_location(name, path)
-        #rcModule = importlib.util.module_from_spec(spec)
-        #spec.loader.exec_module(rcModule)
-        #rcModule.qInitResources()
+        # rcModule = importlib.util.module_from_spec(spec)
+        # spec.loader.exec_module(rcModule)
+        # rcModule.qInitResources()
 
     except Exception as ex:
         print(ex, file=sys.stderr)
@@ -270,6 +279,7 @@ def initResourceFile(path):
     if add_path:
         sys.path.remove(path.parent.as_posix())
 
+
 def findQGISResourceFiles():
     """
     Tries to find a folder 'qgisresources'.
@@ -310,6 +320,7 @@ def scanResources(path=':') -> str:
         elif D.fileInfo().isFile():
             yield D.filePath()
 
+
 def printResources():
     print('Available resources:')
     res = sorted(list(scanResources()))
@@ -317,7 +328,6 @@ def printResources():
         print(r)
 
 
-
 class ResourceTableModel(QAbstractTableModel):
 
     def __init__(self, *args, **kwds):
@@ -381,14 +391,11 @@ class ResourceTableModel(QAbstractTableModel):
 class ResourceTableView(QTableView):
 
     def __init__(self, *args, **kwds):
-        super().__init__(*args ,**kwds)
-
+        super().__init__(*args, **kwds)
 
     def contextMenuEvent(self, event: QContextMenuEvent) -> None:
-
         idx = self.indexAt(event.pos())
         if isinstance(idx, QModelIndex) and idx.isValid():
-
             uri = idx.data(Qt.UserRole)
             m = QMenu()
             a = m.addAction('Copy Name')
@@ -420,7 +427,7 @@ class ResourceBrowser(QWidget):
         self.btnReload: QToolButton
         self.preview: QLabel
 
-        self.graphicsView:QGraphicsView
+        self.graphicsView: QGraphicsView
         self.graphicsScene = QGraphicsScene()
         self.graphicsView.setScene(self.graphicsScene)
 
@@ -460,8 +467,6 @@ class ResourceBrowser(QWidget):
             self.resourceProxyModel.setFilterRegExp(None)
             self.info.setText(expr.errorString())
 
-
-
     def onSelectionChanged(self, selected, deselected):
 
         selectedIdx = selected.indexes()
@@ -474,7 +479,7 @@ class ResourceBrowser(QWidget):
             uri = idx1.data(Qt.UserRole)
             self.updatePreview(uri)
 
-    def updatePreview(self, uri:str):
+    def updatePreview(self, uri: str):
 
         hasImage = False
         hasText = False
@@ -510,13 +515,10 @@ class ResourceBrowser(QWidget):
         self.tabWidget.setTabEnabled(self.tabWidget.indexOf(self.pageImage), hasImage)
         self.tabWidget.setTabEnabled(self.tabWidget.indexOf(self.pageText), hasText)
 
-
-
     def useFilterRegex(self) -> bool:
         return self.optionUseRegex.isChecked()
 
 
-
 def showResources() -> ResourceBrowser:
     """
     A simple way to list available Qt resources
@@ -530,4 +532,5 @@ def showResources() -> ResourceBrowser:
     browser.show()
     if needQApp:
         QApplication.instance().exec_()
-    return browser
\ No newline at end of file
+    return browser
+
diff --git a/eotimeseriesviewer/main.py b/eotimeseriesviewer/main.py
index 7ae4e186a8576b99e45c8085abe46f1ba7092c7d..2e69ed4266531f7736fa6f52a3ace102544b220b 100644
--- a/eotimeseriesviewer/main.py
+++ b/eotimeseriesviewer/main.py
@@ -1662,6 +1662,7 @@ class EOTimeSeriesViewer(QgisInterface, QObject):
         for field in SPECTRA_PROFILE_FIELDS:
             speclib.addAttribute(field)
         assert speclib.commitChanges()
+        QgsProject.instance().addMapLayer(speclib)
         self.showAttributeTable(speclib)
         self.addMapLayers(speclib)
 
diff --git a/eotimeseriesviewer/mapvisualization.py b/eotimeseriesviewer/mapvisualization.py
index 33e60f18fa715131a7836606b07a131f8ad61a87..e51587086654ae7a7d3d2187b9b24db25f130fef 100644
--- a/eotimeseriesviewer/mapvisualization.py
+++ b/eotimeseriesviewer/mapvisualization.py
@@ -626,16 +626,28 @@ class MapView(QFrame):
         assert isinstance(sensor, SensorInstrument)
         if sensor not in self.sensors():
             sensor.sigNameChanged.connect(self.sigCanvasAppearanceChanged)
+
             masterLayer: SensorProxyLayer = sensor.proxyRasterLayer()
             assert isinstance(masterLayer.renderer(), QgsRasterRenderer)
+
             self.mSensorLayerList.append((sensor, masterLayer))
             masterLayer.styleChanged.connect(lambda *args, v=self, l=masterLayer: self.onMasterStyleChanged(l))
+            masterLayer.nameChanged.connect(self.onMasterLyrNameChanged)
             layerTreeLayer: QgsLayerTreeLayer = self.mLayerTreeSensorNode.addLayer(masterLayer)
             layerTreeLayer.setCustomProperty(KEY_LOCKED_LAYER, True)
             layerTreeLayer.setCustomProperty(KEY_SENSOR_LAYER, True)
 
+            dummyLayers = self.mDummyCanvas.layers() + [masterLayer]
+            self.mDummyCanvas.setLayers(dummyLayers)
+
             self.mLayerStyleInitialized[sensor] = False
 
+    def onMasterLyrNameChanged(self, *args):
+        lyr = self.sender()
+        newname = lyr.name()
+        ltn = self.mLayerTreeSensorNode.findLayer(lyr)
+        #print(ltn.name())
+
     def onMasterStyleChanged(self, masterLayer: SensorProxyLayer):
 
         sensor: SensorInstrument = masterLayer.sensor()
@@ -694,7 +706,7 @@ class MapView(QFrame):
             self.mLayerTreeSensorNode.removeLayer(t[1])
             self.mSensorLayerList.remove(t)
 
-    def hasSensor(self, sensor) -> bool:
+    def hasSensor(self, sensor: SensorInstrument) -> bool:
         """
         :param sensor:
         :return:
@@ -777,9 +789,10 @@ class MapViewLayerTreeViewMenuProvider(QgsLayerTreeViewMenuProvider):
 
         model = self.layerTreeModel()
         ltree = self.layerTree()
-        view = self.layerTreeView()
+        view: QgsLayerTreeView = self.layerTreeView()
         currentGroup = view.currentGroupNode()
         currentLayer = view.currentLayer()
+        currentIndex = view.currentIndex()
 
         currentCanvas = self.mapView().currentMapCanvas()
         isSensorGroup = isinstance(currentGroup, QgsLayerTreeGroup) and currentGroup.customProperty(
@@ -799,6 +812,10 @@ class MapViewLayerTreeViewMenuProvider(QgsLayerTreeViewMenuProvider):
         menu = QMenu(view)
         assert isinstance(mw, MapWidget)
         if isinstance(currentLayer, QgsMapLayer):
+            a = menu.addAction('Rename')
+            a.triggered.connect(lambda *args, cidx=currentIndex: view.edit(cidx))
+            menu.addSeparator()
+
             # zoom to layer
             menu.addAction(eotsv.actionZoomToLayer())
 
@@ -856,8 +873,8 @@ class MapViewLayerTreeViewMenuProvider(QgsLayerTreeViewMenuProvider):
             menu.addAction(eotsv.actionCopyLayerStyle())
 
             # Properties
-            menu.addAction(eotsv.actionLayerProperties())
             menu.addSeparator()
+            menu.addAction(eotsv.actionLayerProperties())
 
         menu.addSeparator()
         return menu
diff --git a/eotimeseriesviewer/timeseries.py b/eotimeseriesviewer/timeseries.py
index b3d1136b05faa85f9384494d36d30e7a00d88168..1c52c45997a1872cb2e4576947b396ca89777048 100644
--- a/eotimeseriesviewer/timeseries.py
+++ b/eotimeseriesviewer/timeseries.py
@@ -299,7 +299,7 @@ class SensorInstrument(QObject):
         :return: QgsRasterLayer
         """
         lyr = SensorProxyLayer(self.mMockupDS.GetFileList()[0], name=self.name(), sensor=self)
-        lyr.nameChanged.connect(lambda l=lyr: self.setName(l.name()))
+        lyr.nameChanged.connect(lambda *args, l=lyr: self.setName(l.name()))
         lyr.setCustomProperty('eotsv/sensorid', self.id())
         self.sigNameChanged.connect(lyr.setName)
         return lyr