0
0
mirror of https://github.com/bec-project/bec_widgets.git synced 2025-07-14 03:31:50 +02:00

feat(color_map_selector): added colormap selector with plugin

This commit is contained in:
2024-07-14 22:33:15 +02:00
parent d5c5e12589
commit b98fd00ade
7 changed files with 229 additions and 0 deletions

Binary file not shown.

After

Width:  |  Height:  |  Size: 12 KiB

View File

@ -0,0 +1,111 @@
import pyqtgraph as pg
from qtpy.QtCore import Property, Signal, Slot
from qtpy.QtGui import QColor, QFontMetrics, QImage
from qtpy.QtWidgets import QApplication, QComboBox, QStyledItemDelegate, QVBoxLayout, QWidget
class ColormapDelegate(QStyledItemDelegate):
def __init__(self, parent=None):
super(ColormapDelegate, self).__init__(parent)
self.image_width = 25
self.image_height = 10
self.gap = 10
def paint(self, painter, option, index):
text = index.data()
colormap = pg.colormap.get(text)
colors = colormap.getLookupTable(start=0.0, stop=1.0, alpha=False)
font_metrics = QFontMetrics(painter.font())
text_width = font_metrics.width(text)
text_height = font_metrics.height()
total_height = max(text_height, self.image_height)
image = QImage(self.image_width, self.image_height, QImage.Format_RGB32)
for i in range(self.image_width):
color = QColor(*colors[int(i * (len(colors) - 1) / (self.image_width - 1))])
for j in range(self.image_height):
image.setPixel(i, j, color.rgb())
painter.drawImage(
option.rect.x(), option.rect.y() + (total_height - self.image_height) // 2, image
)
painter.drawText(
option.rect.x() + self.image_width + self.gap,
option.rect.y() + (total_height - text_height) // 2 + font_metrics.ascent(),
text,
)
class ColormapSelector(QWidget):
"""
Simple colormap combobox widget. By default it loads all the available colormaps in pyqtgraph.
"""
colormap_changed_signal = Signal(str)
def __init__(self, parent=None, default_colormaps=None):
super().__init__(parent)
self._colormaps = []
self.initUI(default_colormaps)
def initUI(self, default_colormaps=None):
self.layout = QVBoxLayout(self)
self.combo = QComboBox()
self.combo.setItemDelegate(ColormapDelegate())
self.combo.currentTextChanged.connect(self.colormap_changed)
self.available_colormaps = pg.colormap.listMaps()
if default_colormaps is None:
default_colormaps = self.available_colormaps
self.add_color_maps(default_colormaps)
self.layout.addWidget(self.combo)
@Slot()
def colormap_changed(self):
"""
Emit the colormap changed signal with the current colormap selected in the combobox.
"""
self.colormap_changed_signal.emit(self.combo.currentText())
def add_color_maps(self, colormaps=None):
"""
Add colormaps to the combobox.
Args:
colormaps(list): List of colormaps to add to the combobox. If None, all available colormaps are added.
"""
self.combo.clear()
if colormaps is not None:
for name in colormaps:
if name in self.available_colormaps:
self.combo.addItem(name)
else:
for name in self.available_colormaps:
self.combo.addItem(name)
self._colormaps = colormaps if colormaps is not None else self.available_colormaps
@Property("QStringList")
def colormaps(self):
"""
Property to get and set the colormaps in the combobox.
"""
return self._colormaps
@colormaps.setter
def colormaps(self, value):
"""
Set the colormaps in the combobox.
"""
if self._colormaps != value:
self._colormaps = value
self.add_color_maps(value)
if __name__ == "__main__": # pragma: no cover
import sys
app = QApplication(sys.argv)
ex = ColormapSelector()
ex.show()
sys.exit(app.exec_())

View File

@ -0,0 +1 @@
{'files': ['color_map_selector.py']}

View File

@ -0,0 +1,57 @@
# Copyright (C) 2022 The Qt Company Ltd.
# SPDX-License-Identifier: LicenseRef-Qt-Commercial OR BSD-3-Clause
import os
from qtpy.QtDesigner import QDesignerCustomWidgetInterface
from qtpy.QtGui import QIcon
from bec_widgets.widgets.color_map_selector.color_map_selector import ColormapSelector
DOM_XML = """
<ui language='c++'>
<widget class='ColormapSelector' name='color_map_selector'>
</widget>
</ui>
"""
class ColormapSelectorPlugin(QDesignerCustomWidgetInterface): # pragma: no cover
def __init__(self):
super().__init__()
self._form_editor = None
def createWidget(self, parent):
t = ColormapSelector(parent)
return t
def domXml(self):
return DOM_XML
def group(self):
return "BEC Buttons"
def icon(self):
current_path = os.path.dirname(__file__)
icon_path = os.path.join(current_path, "assets", "color_map_selector_icon.png")
return QIcon(icon_path)
def includeFile(self):
return "color_map_selector"
def initialize(self, form_editor):
self._form_editor = form_editor
def isContainer(self):
return False
def isInitialized(self):
return self._form_editor is not None
def name(self):
return "ColormapSelector"
def toolTip(self):
return "A custom QComboBox widget for selecting colormaps."
def whatsThis(self):
return self.toolTip()

View File

@ -0,0 +1,17 @@
def main(): # pragma: no cover
from qtpy import PYSIDE6
if not PYSIDE6:
print("PYSIDE6 is not available in the environment. Cannot patch designer.")
return
from PySide6.QtDesigner import QPyDesignerCustomWidgetCollection
from bec_widgets.widgets.color_map_selector.color_map_selector_plugin import (
ColormapSelectorPlugin,
)
QPyDesignerCustomWidgetCollection.addCustomWidget(ColormapSelectorPlugin())
if __name__ == "__main__": # pragma: no cover
main()

View File

@ -0,0 +1,43 @@
import pyqtgraph as pg
import pytest
from bec_widgets.widgets.color_map_selector.color_map_selector import ColormapSelector
@pytest.fixture
def color_map_selector(qtbot):
widget = ColormapSelector()
qtbot.addWidget(widget)
qtbot.waitExposed(widget)
yield widget
widget.close()
def test_color_map_selector_init(color_map_selector):
assert color_map_selector is not None
assert isinstance(color_map_selector, ColormapSelector)
all_maps = pg.colormap.listMaps()
loaded_maps = [
color_map_selector.combo.itemText(i) for i in range(color_map_selector.combo.count())
]
assert len(loaded_maps) > 0
assert all_maps == loaded_maps
def test_color_map_selector_add_color_maps(color_map_selector):
color_map_selector.add_color_maps(["cividis", "viridis"])
assert color_map_selector.combo.count() == 2
assert color_map_selector.combo.itemText(0) == "cividis"
assert color_map_selector.combo.itemText(1) == "viridis"
assert color_map_selector.combo.itemText(2) != "cividis"
assert color_map_selector.combo.itemText(2) != "viridis"
def test_colormap_add_maps_by_property(color_map_selector):
color_map_selector.colormaps = ["cividis", "viridis"]
assert color_map_selector.combo.count() == 2
assert color_map_selector.combo.itemText(0) == "cividis"
assert color_map_selector.combo.itemText(1) == "viridis"
assert color_map_selector.combo.itemText(2) != "cividis"
assert color_map_selector.combo.itemText(2) != "viridis"