zlevelsetter.py 9.27 KB
Newer Older
1 2 3 4 5 6
# -*- coding: utf-8 -*-
"""
Created on Fri Oct 25 09:39:14 2019

@author: brandt
"""
Josef Brandt's avatar
Josef Brandt committed
7
from PyQt5 import QtWidgets, QtCore
8
import numpy as np
9
import math
10 11 12 13 14 15 16


class ZLevelSetter(QtWidgets.QLabel):
    """
    Allows refining settings for the focus-z-stacking
    :return:
    """
Josef Brandt's avatar
Josef Brandt committed
17 18 19

    sizeChanged = QtCore.pyqtSignal()

20 21 22 23
    def __init__(self):
        super(ZLevelSetter, self).__init__()
        layout = QtWidgets.QVBoxLayout()
        self.setLayout(layout)
24

25
        self.radioGroup = QtWidgets.QButtonGroup()
26

27 28 29 30
        layout.addWidget(self._createRangeGroupBox())
        layout.addLayout(self._createLevelSelectionLayout())

        self._addRadioBtnsToGroup()
Josef Brandt's avatar
Josef Brandt committed
31
        self._updateLevels()
32 33 34 35 36 37 38

    def _createRangeGroupBox(self):
        """
        Creates Widgets for setting range of z-levels
        :return:
        """
        rangeGroupBox = QtWidgets.QGroupBox('Select Range of z-steps')
39
        rangeGroupBox.setMinimumHeight(80)
40 41
        rangesLayout = QtWidgets.QHBoxLayout()
        rangeGroupBox.setLayout(rangesLayout)
42

43 44 45 46 47 48 49 50
        self.minLevelSpinbox = QtWidgets.QSpinBox()
        self.minLevelSpinbox.setMinimum(-1000)
        self.minLevelSpinbox.setMaximum(1000)
        self.minLevelSpinbox.setValue(0)
        self.minLevelSpinbox.valueChanged.connect(self._minLevelBoxChanged)
        self.maxLevelSpinbox = QtWidgets.QSpinBox()
        self.maxLevelSpinbox.setValue(50)
        self._minLevelBoxChanged()
51

52 53 54 55
        self.numLevelsSpinbox = QtWidgets.QSpinBox()
        self.numLevelsSpinbox.setMinimum(1)
        self.numLevelsSpinbox.setMaximum(100)
        self.numLevelsSpinbox.setValue(5)
56

57 58
        for box in [self.minLevelSpinbox, self.maxLevelSpinbox, self.numLevelsSpinbox]:
            box.valueChanged.connect(self._updateLevels)
59 60 61 62 63 64

        minLabel = QtWidgets.QLabel('z_min\n(µm): ')
        maxLabel = QtWidgets.QLabel(', z_max\n(µm): ')
        numLabel = QtWidgets.QLabel(', Num.\nsteps: ')

        rangesLayout.addWidget(minLabel)
65
        rangesLayout.addWidget(self.minLevelSpinbox)
66
        rangesLayout.addWidget(maxLabel)
67
        rangesLayout.addWidget(self.maxLevelSpinbox)
68
        rangesLayout.addWidget(numLabel)
69
        rangesLayout.addWidget(self.numLevelsSpinbox)
70

71
        return rangeGroupBox
72

73 74 75 76 77 78 79 80 81 82
    def _createLevelSelectionLayout(self):
        """
        Creates the Parent Group for selecting mode of level distribution
        :return:
        """
        modeLayout = QtWidgets.QHBoxLayout()
        modeLayout.addWidget(self._createLinGroup())
        modeLayout.addWidget(self._createLogGroup())
        modeLayout.addWidget(self._createCustomGroup())
        return modeLayout
83

84 85 86 87 88 89 90 91 92
    def _createLinGroup(self):
        """
        Creates Widget group for linear level distribution
        :return:
        """
        linGroup = QtWidgets.QGroupBox()
        linLayout = QtWidgets.QVBoxLayout()
        linGroup.setLayout(linLayout)
        linGroup.sizePolicy().setVerticalPolicy(QtWidgets.QSizePolicy.Expanding)
93

94 95 96 97
        self.linChecker = QtWidgets.QRadioButton('Linear')
        self.linChecker.setChecked(True)
        self.linChecker.toggled.connect(self._updateLevels)
        linLayout.addWidget(self.linChecker)
98

99 100 101 102 103
        self.linPreviewLayout = QtWidgets.QVBoxLayout()
        linLayout.addLayout(self.linPreviewLayout)
        self.linPreviewSteps = []
        self._updateLinPreview()
        return linGroup
104

105 106 107 108 109 110 111 112 113
    def _createLogGroup(self):
        """
        Creates Widget group for logarithmic level distribution
        :return:
        """
        logGroup = QtWidgets.QGroupBox()
        logLayout = QtWidgets.QVBoxLayout()
        logGroup.setLayout(logLayout)
        logGroup.sizePolicy().setVerticalPolicy(QtWidgets.QSizePolicy.Expanding)
114

115 116 117 118
        self.logChecker = QtWidgets.QRadioButton('Logarithmic')
        self.logChecker.setChecked(False)
        self.logChecker.toggled.connect(self._updateLevels)
        logLayout.addWidget(self.logChecker)
119

120 121
        self.logPreviewLayout = QtWidgets.QVBoxLayout()
        logLayout.addLayout(self.logPreviewLayout)
122

123 124 125
        self.logPreviewSteps = []
        self._updateLogPreview()
        return logGroup
126

127 128 129 130 131 132 133 134 135
    def _createCustomGroup(self):
        """
        Creates Widget group for custom level distribution
        :return:
        """
        customGroup = QtWidgets.QGroupBox()
        customLayout = QtWidgets.QVBoxLayout()
        customGroup.setLayout(customLayout)
        customGroup.sizePolicy().setVerticalPolicy(QtWidgets.QSizePolicy.Expanding)
136

137 138 139 140
        self.customChecker = QtWidgets.QRadioButton('Custom')
        self.customChecker.setChecked(False)
        self.customChecker.toggled.connect(self._updateLevels)
        customLayout.addWidget(self.customChecker)
141

142 143 144 145 146
        self.customPreviewLayout = QtWidgets.QVBoxLayout()
        customLayout.addLayout(self.customPreviewLayout)
        self.customPreviewSteps = []
        self._updateCustomPreview()
        return customGroup
147

148 149 150 151 152 153 154 155
    def _updateLevels(self):
        """
        Updates the previewed levels for all modes
        :return:
        """
        self._updateLinPreview()
        self._updateLogPreview()
        self._updateCustomPreview()
Josef Brandt's avatar
Josef Brandt committed
156
        self._updateSize()
157

158 159 160 161 162 163 164 165
    def _updateLinPreview(self):
        """
        Updates linear level preview
        :return:
        """
        for entry in self.linPreviewSteps:
            entry.setParent(None)
        zRange = np.linspace(self.minLevelSpinbox.value(), self.maxLevelSpinbox.value(), self.numLevelsSpinbox.value())
166

167 168 169 170 171 172
        self.linPreviewSteps = []
        for val in zRange:
            newLabel = QtWidgets.QLabel(str(round(val, 1)))
            newLabel.setEnabled(self.linChecker.isChecked())
            self.linPreviewSteps.append(newLabel)
            self.linPreviewLayout.addWidget(newLabel)
173

174 175 176 177 178
    def _updateLogPreview(self):
        """
        Updates logarithmic level preview
        :return:
        """
179
        base = 2
180 181 182
        for entry in self.logPreviewSteps:
            entry.setParent(None)
        zmin = self.minLevelSpinbox.value()
183 184 185 186 187 188
        zmax = self.maxLevelSpinbox.value()
        diff = -(zmin-1)
        zmin = math.log((zmin+diff), base)
        zmax = math.log((zmax+diff), base)

        zRange = np.logspace(zmin, zmax, self.numLevelsSpinbox.value(), base=base)
189 190 191

        self.logPreviewSteps = []
        for val in zRange:
192
            val -= diff
193 194 195 196
            newLabel = QtWidgets.QLabel(str(round(val, 1)))
            newLabel.setEnabled(self.logChecker.isChecked())
            self.logPreviewSteps.append(newLabel)
            self.logPreviewLayout.addWidget(newLabel)
197

198 199 200 201 202 203 204
    def _updateCustomPreview(self):
        """
        Updates custom level preview
        :return:
        """
        numCurrentEntries = len(self.customPreviewSteps)
        numDesiredEntries = self.numLevelsSpinbox.value()
205 206
        indicesToRemove = []

207 208
        for i in range(max([numCurrentEntries, numDesiredEntries])):
            if i < numCurrentEntries:
209 210
                self.customPreviewSteps[i].setEnabled(self.customChecker.isChecked())

211 212 213 214 215
            elif i >= numCurrentEntries:
                newEntry = QtWidgets.QLineEdit()
                newEntry.setEnabled(self.customChecker.isChecked())
                self.customPreviewSteps.append(newEntry)
                self.customPreviewLayout.addWidget(newEntry)
216

217
            if i >= numDesiredEntries:
218 219 220 221 222 223
                indicesToRemove.append(i)

        for i in sorted(indicesToRemove, reverse=True):
            entry = self.customPreviewSteps[i]
            entry.setParent(None)
            self.customPreviewSteps.remove(entry)
224

Josef Brandt's avatar
Josef Brandt committed
225 226 227 228 229 230
    def _updateSize(self):
        """
        Updates the size so that all entries are well visible
        :return:
        """
        width = 400
231
        height = 170 + self.numLevelsSpinbox.value()*23
Josef Brandt's avatar
Josef Brandt committed
232 233 234
        self.setFixedSize(width, height)
        self.sizeChanged.emit()

235 236 237 238 239 240 241
    def _minLevelBoxChanged(self):
        """
        Adjusts maxLevelSpinbox to show always values larger then minLevelSpinbox
        :return:
        """
        self.maxLevelSpinbox.setMinimum(self.minLevelSpinbox.value()+1)
        self.maxLevelSpinbox.setMaximum(self.maxLevelSpinbox.value()+1000)
242

243 244 245 246 247 248 249 250
    def _addRadioBtnsToGroup(self):
        """
        Group Radio Buttons to have them in exclusive check mode
        :return:
        """
        self.radioGroup.addButton(self.linChecker)
        self.radioGroup.addButton(self.logChecker)
        self.radioGroup.addButton(self.customChecker)
251

252 253 254 255 256 257 258 259 260 261 262 263 264
    def getZLevels(self):
        """
        retrieves the z-levels according to the chosen settings
        :return:
        """
        zLevels = []
        if self.linChecker.isChecked():
            zLevels = [float(entry.text()) for entry in self.linPreviewSteps]
        elif self.logChecker.isChecked():
            zLevels = [float(entry.text()) for entry in self.logPreviewSteps]
        elif self.customChecker.isChecked():
            try:
                zLevels = self._getCustomLevels()
Josef Brandt's avatar
Josef Brandt committed
265
            except ValueError:
266
                QtWidgets.QMessageBox.critical(self, 'Error', 'Invalid entry in custom level selection')
Josef Brandt's avatar
Josef Brandt committed
267
                raise ValueError
268 269 270 271 272 273 274 275 276 277 278 279
        return np.array(zLevels)

    def _getCustomLevels(self):
        """
        Reads out the custom level range
        :return:
        """
        levels = []
        for lineEdit in self.customPreviewSteps:
            try:
                levels.append(float(lineEdit.text()))
            except:
Josef Brandt's avatar
Josef Brandt committed
280
                raise ValueError
281
        return sorted(levels)