Skip to content

Commit

Permalink
HeatMap: Allow setting the center when using diverging palettes
Browse files Browse the repository at this point in the history
  • Loading branch information
janezd committed May 24, 2020
1 parent a0381fb commit 984f1e1
Show file tree
Hide file tree
Showing 2 changed files with 49 additions and 5 deletions.
44 changes: 40 additions & 4 deletions Orange/widgets/utils/colorgradientselection.py
Original file line number Diff line number Diff line change
Expand Up @@ -2,26 +2,29 @@

from AnyQt.QtCore import Qt, QSize, QAbstractItemModel, Property
from AnyQt.QtWidgets import (
QWidget, QSlider, QFormLayout, QComboBox, QStyle
)
QWidget, QSlider, QFormLayout, QComboBox, QStyle,
QHBoxLayout, QLineEdit, QLabel)
from AnyQt.QtCore import Signal
from AnyQt.QtGui import QFontMetrics, QDoubleValidator

from Orange.widgets.utils import itemmodels
from Orange.widgets.utils import itemmodels, colorpalettes


class ColorGradientSelection(QWidget):
activated = Signal(int)

currentIndexChanged = Signal(int)
thresholdsChanged = Signal(float, float)
centerChanged = Signal(float)

def __init__(self, *args, thresholds=(0.0, 1.0), **kwargs):
def __init__(self, *args, thresholds=(0.0, 1.0), center=0, **kwargs):
super().__init__(*args, **kwargs)

low = round(clip(thresholds[0], 0., 1.), 2)
high = round(clip(thresholds[1], 0., 1.), 2)
high = max(low, high)
self.__threshold_low, self.__threshold_high = low, high
self.__center = center
form = QFormLayout(
formAlignment=Qt.AlignLeft,
labelAlignment=Qt.AlignLeft,
Expand All @@ -42,6 +45,21 @@ def __init__(self, *args, thresholds=(0.0, 1.0), **kwargs):
self.gradient_cb.setModel(model)
self.gradient_cb.activated[int].connect(self.activated)
self.gradient_cb.currentIndexChanged.connect(self.currentIndexChanged)
self.gradient_cb.currentIndexChanged.connect(self.__on_palette_changed)

self.center_box = QWidget()
center_layout = QHBoxLayout()
self.center_box.setLayout(center_layout)
width = QFontMetrics(self.font()).boundingRect("9999999").width()
self.center_edit = QLineEdit(
text=f"{self.__center}",
maximumWidth=width, placeholderText="0", alignment=Qt.AlignRight)
self.center_edit.setValidator(QDoubleValidator())
self.center_edit.editingFinished.connect(self.__on_center_changed)
center_layout.setContentsMargins(0, 0, 0, 0)
center_layout.addStretch(1)
center_layout.addWidget(QLabel("Centered at"))
center_layout.addWidget(self.center_edit)

slider_low = QSlider(
objectName="threshold-low-slider", minimum=0, maximum=100,
Expand All @@ -60,6 +78,7 @@ def __init__(self, *args, thresholds=(0.0, 1.0), **kwargs):
"gradient from the higher end")
)
form.setWidget(0, QFormLayout.SpanningRole, self.gradient_cb)
form.setWidget(1, QFormLayout.FieldRole, self.center_box)
form.addRow(self.tr("Low:"), slider_low)
form.addRow(self.tr("High:"), slider_high)
self.slider_low = slider_low
Expand Down Expand Up @@ -109,6 +128,14 @@ def thresholdHigh(self) -> float:
def setThresholdHigh(self, high: float) -> None:
self.setThresholds(min(self.__threshold_low, high), high)

def center(self) -> float:
return self.__center

def setCenter(self, center: float) -> None:
self.__center = center
self.center_edit.setText(f"{center}")
self.centerChanged.emit(center)

thresholdHigh_ = Property(
float, thresholdLow, setThresholdLow, notify=thresholdsChanged)

Expand Down Expand Up @@ -146,6 +173,15 @@ def setThresholds(self, low: float, high: float) -> None:
self.slider_high.setSliderPosition(high * 100)
self.thresholdsChanged.emit(high, low)

def __on_palette_changed(self):
palette = self.currentData()
self.center_box.setVisible(
isinstance(palette, colorpalettes.Palette)
and palette.flags & palette.Flags.Diverging)

def __on_center_changed(self):
self.__center = float(self.center_edit.text() or "0")
self.centerChanged.emit(self.__center)

def clip(a, amin, amax):
return min(max(a, amin), amax)
10 changes: 9 additions & 1 deletion Orange/widgets/visualize/owheatmap.py
Original file line number Diff line number Diff line change
Expand Up @@ -155,6 +155,7 @@ class Outputs:

threshold_low = settings.Setting(0.0)
threshold_high = settings.Setting(1.0)
color_center = settings.Setting(0)

merge_kmeans = settings.Setting(False)
merge_kmeans_k = settings.Setting(50)
Expand Down Expand Up @@ -244,6 +245,7 @@ def _():

self.color_map_widget = cmw = ColorGradientSelection(
thresholds=(self.threshold_low, self.threshold_high),
center=self.color_center
)
model = itemmodels.ContinuousPalettesModel(parent=self)
cmw.setModel(model)
Expand All @@ -257,6 +259,12 @@ def _set_thresholds(low, high):
self.threshold_low, self.threshold_high = low, high
self.update_color_schema()
cmw.thresholdsChanged.connect(_set_thresholds)

def _set_centering(center):
self.color_center = center
self.update_color_schema()
cmw.centerChanged.connect(_set_centering)

colorbox.layout().addWidget(self.color_map_widget)

mergebox = gui.vBox(self.controlArea, "Merge",)
Expand Down Expand Up @@ -449,7 +457,7 @@ def color_palette(self):
def color_map(self) -> GradientColorMap:
return GradientColorMap(
self.color_palette(), (self.threshold_low, self.threshold_high),
0 if self.center_palette else None
self.color_map_widget.center() if self.center_palette else None
)

def clear(self):
Expand Down

0 comments on commit 984f1e1

Please sign in to comment.