Skip to content

Commit

Permalink
Merge pull request #605 from markotoplak/spectra-params2
Browse files Browse the repository at this point in the history
[ENH] Visualization parameters dialog for Spectra and HyperSpectra
  • Loading branch information
markotoplak authored Apr 14, 2023
2 parents f76b0ea + 5c6bc9f commit db227c5
Show file tree
Hide file tree
Showing 5 changed files with 396 additions and 106 deletions.
41 changes: 28 additions & 13 deletions orangecontrib/spectroscopy/tests/test_owhyper.py
Original file line number Diff line number Diff line change
Expand Up @@ -433,6 +433,34 @@ def last_called_array(m):
target = [data.X[0, :3], data.X[1, :3]], [data.X[2, :3], data.X[3, :3]]
np.testing.assert_equal(called, target)

def test_migrate_visual_setttings(self):
settings = {"curveplot":
{"label_title": "title",
"label_xaxis": "x",
"label_yaxis": "y"}
}
OWHyper.migrate_settings(settings, 6)
self.assertEqual(settings["visual_settings"],
{('Annotations', 'Title', 'Title'): 'title',
('Annotations', 'x-axis title', 'Title'): 'x',
('Annotations', 'y-axis title', 'Title'): 'y'})
settings = {}
OWHyper.migrate_settings(settings, 6)
self.assertNotIn("visual_settings", settings)

def test_compat_no_group(self):
settings = {}
OWHyper.migrate_settings(settings, 6)
self.assertEqual(settings, {})
self.widget = self.create_widget(OWHyper, stored_settings=settings)
self.assertFalse(self.widget.compat_no_group)

settings = {}
OWHyper.migrate_settings(settings, 5)
self.assertEqual(settings, {"compat_no_group": True})
self.widget = self.create_widget(OWHyper, stored_settings=settings)
self.assertTrue(self.widget.compat_no_group)


class TestVisibleImage(WidgetTest):

Expand Down Expand Up @@ -637,16 +665,3 @@ def test_visible_image_img_size(self):
self.assert_same_visible_image(data.attributes["visible_images"][0],
w.imageplot.vis_img,
mock_rect)

def test_compat_no_group(self):
settings = {}
OWHyper.migrate_settings(settings, 6)
self.assertEqual(settings, {})
self.widget = self.create_widget(OWHyper, stored_settings=settings)
self.assertFalse(self.widget.compat_no_group)

settings = {}
OWHyper.migrate_settings(settings, 5)
self.assertEqual(settings, {"compat_no_group": True})
self.widget = self.create_widget(OWHyper, stored_settings=settings)
self.assertTrue(self.widget.compat_no_group)
116 changes: 108 additions & 8 deletions orangecontrib/spectroscopy/tests/test_owspectra.py
Original file line number Diff line number Diff line change
@@ -1,7 +1,9 @@
import os
import unittest
from unittest.mock import Mock, patch

from AnyQt.QtCore import QRectF, Qt
from AnyQt.QtGui import QFont
from AnyQt.QtTest import QSignalSpy
import numpy as np
import pyqtgraph as pg
Expand Down Expand Up @@ -231,14 +233,6 @@ def numcurves(curves):
curves_plotted = self.widget.curveplot.curves_plotted
self.assertEqual(numcurves(curves_plotted), 150)

def test_limits(self):
self.send_signal("Data", self.iris)
vr = self.widget.curveplot.plot.viewRect()
# there should ne no change
self.widget.curveplot.set_limits()
vr2 = self.widget.curveplot.plot.viewRect()
self.assertEqual(vr, vr2)

def test_line_intersection(self):
data = self.collagen
x = getx(data)
Expand Down Expand Up @@ -564,3 +558,109 @@ def test_compat_no_group(self):
self.assertTrue(self.widget.compat_no_group)
# We decided to remove the info box
# self.assertTrue(self.widget.Information.compat_no_group.is_shown())

def test_visual_settings(self, timeout=5):
graph = self.widget.curveplot
font = QFont()
font.setItalic(True)
font.setFamily("Helvetica")

self.send_signal(self.widget.Inputs.data, self.iris)
self.wait_until_finished(timeout=timeout)
graph.cycle_color_attr()
self.assertEqual(graph.feature_color, self.iris.domain.class_var)

key, value = ("Fonts", "Font family", "Font family"), "Helvetica"
self.widget.set_visual_settings(key, value)

key, value = ("Fonts", "Title", "Font size"), 20
self.widget.set_visual_settings(key, value)
key, value = ("Fonts", "Title", "Italic"), True
self.widget.set_visual_settings(key, value)
font.setPointSize(20)
self.assertFontEqual(graph.parameter_setter.title_item.item.font(), font)

key, value = ("Fonts", "Axis title", "Font size"), 14
self.widget.set_visual_settings(key, value)
key, value = ("Fonts", "Axis title", "Italic"), True
self.widget.set_visual_settings(key, value)
font.setPointSize(14)
for ax in ["bottom", "left"]:
axis = graph.parameter_setter.getAxis(ax)
self.assertFontEqual(axis.label.font(), font)

key, value = ('Fonts', 'Axis ticks', 'Font size'), 15
self.widget.set_visual_settings(key, value)
key, value = ('Fonts', 'Axis ticks', 'Italic'), True
self.widget.set_visual_settings(key, value)
font.setPointSize(15)
for ax in ["bottom", "left"]:
axis = graph.parameter_setter.getAxis(ax)
self.assertFontEqual(axis.style["tickFont"], font)

key, value = ("Fonts", "Legend", "Font size"), 16
self.widget.set_visual_settings(key, value)
key, value = ("Fonts", "Legend", "Italic"), True
self.widget.set_visual_settings(key, value)
font.setPointSize(16)
legend_item = list(graph.parameter_setter.legend_items)[0]
self.assertFontEqual(legend_item[1].item.font(), font)

key, value = ("Annotations", "Title", "Title"), "Foo"
self.widget.set_visual_settings(key, value)
self.assertEqual(graph.parameter_setter.title_item.item.toPlainText(), "Foo")
self.assertEqual(graph.parameter_setter.title_item.text, "Foo")

key, value = ("Annotations", "x-axis title", "Title"), "Foo2"
self.widget.set_visual_settings(key, value)
axis = graph.parameter_setter.getAxis("bottom")
self.assertEqual(axis.label.toPlainText().strip(), "Foo2")
self.assertEqual(axis.labelText, "Foo2")

key, value = ("Annotations", "y-axis title", "Title"), "Foo3"
self.widget.set_visual_settings(key, value)
axis = graph.parameter_setter.getAxis("left")
self.assertEqual(axis.label.toPlainText().strip(), "Foo3")
self.assertEqual(axis.labelText, "Foo3")

self.assertFalse(self.widget.Information.view_locked.is_shown())
key, value = ("View Range", "X", "xMin"), 1.
self.widget.set_visual_settings(key, value)
key, value = ("View Range", "X", "xMax"), 3.
self.widget.set_visual_settings(key, value)
vr = graph.plot.vb.viewRect()
self.assertEqual(vr.left(), 1)
self.assertEqual(vr.right(), 3)
self.assertTrue(self.widget.Information.view_locked.is_shown())

key, value = ("View Range", "Y", "yMin"), 2.
self.widget.set_visual_settings(key, value)
key, value = ("View Range", "Y", "yMax"), 42.
self.widget.set_visual_settings(key, value)
vr = graph.plot.vb.viewRect()
self.assertEqual(vr.top(), 2)
self.assertEqual(vr.bottom(), 42)

def assertFontEqual(self, font1, font2):
self.assertEqual(font1.family(), font2.family())
self.assertEqual(font1.pointSize(), font2.pointSize())
self.assertEqual(font1.italic(), font2.italic())

def test_migrate_visual_setttings(self):
settings = {"curveplot":
{"label_title": "title",
"label_xaxis": "x",
"label_yaxis": "y"}
}
OWSpectra.migrate_settings(settings, 4)
self.assertEqual(settings["visual_settings"],
{('Annotations', 'Title', 'Title'): 'title',
('Annotations', 'x-axis title', 'Title'): 'x',
('Annotations', 'y-axis title', 'Title'): 'y'})
settings = {}
OWSpectra.migrate_settings(settings, 4)
self.assertNotIn("visual_settings", settings)


if __name__ == "__main__":
unittest.main()
78 changes: 76 additions & 2 deletions orangecontrib/spectroscopy/widgets/owhyper.py
Original file line number Diff line number Diff line change
Expand Up @@ -23,6 +23,7 @@
import Orange.data
from Orange.preprocess.transformation import Identity
from Orange.data import Domain, DiscreteVariable, ContinuousVariable
from Orange.widgets.visualize.utils.customizableplot import CommonParameterSetter
from Orange.widgets.widget import OWWidget, Msg, OWComponent, Input
from Orange.widgets import gui
from Orange.widgets.settings import \
Expand All @@ -32,12 +33,15 @@
from Orange.widgets.utils.concurrent import TaskState, ConcurrentMixin
from Orange.widgets.visualize.utils.plotutils import GraphicsView, PlotItem, AxisItem

from orangewidget.utils.visual_settings_dlg import VisualSettingsDialog

from orangecontrib.spectroscopy.preprocess import Integrate
from orangecontrib.spectroscopy.utils import values_to_linspace, index_values_nan, split_to_size

from orangecontrib.spectroscopy.widgets.owspectra import InteractiveViewBox, \
MenuFocus, CurvePlot, SELECTONE, SELECTMANY, INDIVIDUAL, AVERAGE, \
HelpEventDelegate, selection_modifiers
HelpEventDelegate, selection_modifiers, \
ParameterSetter as SpectraParameterSetter

from orangecontrib.spectroscopy.widgets.gui import MovableVline, lineEditDecimalOrNone,\
pixels_to_decimals, float_to_str_decimals
Expand Down Expand Up @@ -572,6 +576,42 @@ def update_rect(self):
self.rect.setBrush(QBrush(self.gradient))


class ImageParameterSetter(CommonParameterSetter):
IMAGE_ANNOT_BOX = "Image annotations"

def __init__(self, master):
super().__init__()
self.master = master

def update_setters(self):
self.initial_settings = {
self.IMAGE_ANNOT_BOX: {
self.TITLE_LABEL: {self.TITLE_LABEL: ("", "")},
self.X_AXIS_LABEL: {self.TITLE_LABEL: ("", "")},
self.Y_AXIS_LABEL: {self.TITLE_LABEL: ("", "")},
},
}

self._setters[self.IMAGE_ANNOT_BOX] = self._setters[self.ANNOT_BOX]

@property
def title_item(self):
return self.master.plot.titleLabel

@property
def axis_items(self):
return [value["item"] for value in self.master.plot.axes.values()] \
+ [self.master.legend.axis]

@property
def getAxis(self):
return self.master.plot.getAxis

@property
def legend_items(self):
return []


class ImagePlot(QWidget, OWComponent, SelectionGroupMixin,
ImageColorSettingMixin, ImageRGBSettingMixin,
ImageZoomMixin, ConcurrentMixin):
Expand All @@ -592,6 +632,8 @@ def __init__(self, parent):
ConcurrentMixin.__init__(self)
self.parent = parent

self.parameter_setter = ImageParameterSetter(self)

self.selection_type = SELECTMANY
self.saving_enabled = True
self.selection_enabled = True
Expand Down Expand Up @@ -970,7 +1012,7 @@ class Outputs(SelectionOutputsMixin.Outputs):
replaces = ["orangecontrib.infrared.widgets.owhyper.OWHyper"]
keywords = ["image", "spectral", "chemical", "imaging"]

settings_version = 6
settings_version = 7
settingsHandler = DomainContextHandler()

imageplot = SettingProvider(ImagePlot)
Expand All @@ -995,6 +1037,8 @@ class Outputs(SelectionOutputsMixin.Outputs):
lowlimb = Setting(None)
highlimb = Setting(None)

visual_settings = Setting({}, schema_only=True)

graph_name = "imageplot.plotview" # defined so that the save button is shown

class Warning(OWWidget.Warning):
Expand All @@ -1005,6 +1049,7 @@ class Error(OWWidget.Error):

class Information(SelectionOutputsMixin.Information):
not_shown = Msg("Undefined positions: {} data point(s) are not shown.")
view_locked = Msg("Axes are locked in the visual settings dialog.")

@classmethod
def migrate_settings(cls, settings_, version):
Expand All @@ -1029,6 +1074,10 @@ def migrate_settings(cls, settings_, version):
if version < 6:
settings_["compat_no_group"] = True

if version < 7:
from orangecontrib.spectroscopy.widgets.owspectra import OWSpectra
OWSpectra.migrate_to_visual_settings(settings_)

@classmethod
def migrate_context(cls, context, version):
if version <= 3 and "curveplot" in context.values:
Expand Down Expand Up @@ -1101,6 +1150,8 @@ def __init__(self):
splitter.addWidget(self.imageplot)
splitter.addWidget(self.curveplot)
self.mainArea.layout().addWidget(splitter)
self.curveplot.locked_axes_changed.connect(
lambda locked: self.Information.view_locked(shown=locked))

self.line1 = MovableVline(position=self.lowlim, label="", report=self.curveplot)
self.line1.sigMoved.connect(lambda v: setattr(self, "lowlim", v))
Expand Down Expand Up @@ -1130,6 +1181,18 @@ def __init__(self):
# prepare interface according to the new context
self.contextAboutToBeOpened.connect(lambda x: self.init_interface_data(x[0]))

self._setup_plot_parameters()

def _setup_plot_parameters(self):
parts_from_spectra = [SpectraParameterSetter.ANNOT_BOX,
SpectraParameterSetter.LABELS_BOX,
SpectraParameterSetter.VIEW_RANGE_BOX]
for cp in parts_from_spectra:
self.imageplot.parameter_setter.initial_settings[cp] = \
self.curveplot.parameter_setter.initial_settings[cp]

VisualSettingsDialog(self, self.imageplot.parameter_setter.initial_settings)

def setup_visible_image_controls(self):
self.visbox = gui.widgetBox(self.controlArea, True)

Expand Down Expand Up @@ -1347,6 +1410,17 @@ def valid_context(data):
self.output_image_selection()
self.update_visible_image()

def set_visual_settings(self, key, value):
im_setter = self.imageplot.parameter_setter
cv_setter = self.curveplot.parameter_setter
skip_im_setter = [SpectraParameterSetter.ANNOT_BOX,
SpectraParameterSetter.VIEW_RANGE_BOX]
if key[0] not in skip_im_setter and key[0] in im_setter.initial_settings:
im_setter.set_parameter(key, value)
if key[0] in cv_setter.initial_settings:
cv_setter.set_parameter(key, value)
self.visual_settings[key] = value

def _init_integral_boundaries(self):
# requires data in curveplot
self.disable_integral_range = True
Expand Down
Loading

0 comments on commit db227c5

Please sign in to comment.