Skip to content

Commit df70dff

Browse files
committed
Implement min/max combo box
1 parent cf72102 commit df70dff

4 files changed

Lines changed: 75 additions & 63 deletions

File tree

openmc_plotter/docks.py

Lines changed: 31 additions & 33 deletions
Original file line numberDiff line numberDiff line change
@@ -773,17 +773,12 @@ class ColorForm(QWidget):
773773
Selector for colormap
774774
dataIndicatorCheckBox : QCheckBox
775775
Inidcates whether or not the data indicator will appear on the colorbar
776-
userMinMaxBox : QCheckBox
777-
Indicates whether or not the user defined values in the min and max
778-
will be used to set the bounds of the colorbar.
776+
minMaxTypeBox : QComboBox
777+
Dropdown to select min/max type: "Full data", "Visible data", or "Custom"
779778
maxBox : ScientificDoubleSpinBox
780-
Max value of the colorbar. If the userMinMaxBox is checked, this will be
781-
the user's input. If the userMinMaxBox is not checked, this box will
782-
hold the max value of the visible data.
779+
Max value of the colorbar. Only visible when minMaxTypeBox is set to "Custom".
783780
minBox : ScientificDoubleSpinBox
784-
Min value of the colorbar. If the userMinMaxBox is checked, this will be
785-
the user's input. If the userMinMaxBox is not checked, this box will
786-
hold the max value of the visible data.
781+
Min value of the colorbar. Only visible when minMaxTypeBox is set to "Custom".
787782
scaleBox : QCheckBox
788783
Indicates whether or not the data is displayed on a log or linear
789784
scale
@@ -844,10 +839,13 @@ def __init__(self, model, main_window, field, colormaps=None):
844839
self.dataIndicatorCheckBox.stateChanged.connect(
845840
data_indicator_connector)
846841

847-
# User specified min/max check box
848-
self.userMinMaxBox = QCheckBox()
849-
minmax_connector = partial(main_window.toggleTallyDataUserMinMax)
850-
self.userMinMaxBox.stateChanged.connect(minmax_connector)
842+
# Min/max type dropdown
843+
self.minMaxTypeBox = QComboBox()
844+
self.minMaxTypeBox.addItem("Full data")
845+
self.minMaxTypeBox.addItem("Visible data")
846+
self.minMaxTypeBox.addItem("Custom")
847+
minmax_type_connector = partial(main_window.setTallyMinMaxType)
848+
self.minMaxTypeBox.currentIndexChanged.connect(minmax_type_connector)
851849

852850
# Data min spin box
853851
self.minBox = ScientificDoubleSpinBox()
@@ -861,10 +859,9 @@ def __init__(self, model, main_window, field, colormaps=None):
861859
max_connector = partial(main_window.editTallyDataMax)
862860
self.maxBox.valueChanged.connect(max_connector)
863861

864-
# Auto rescale check box
865-
self.autoRescaleBox = QCheckBox()
866-
auto_rescale_connector = partial(main_window.toggleTallyAutoRescale)
867-
self.autoRescaleBox.stateChanged.connect(auto_rescale_connector)
862+
# Labels for min/max (so we can show/hide them)
863+
self.minLabel = QLabel("Min: ")
864+
self.maxLabel = QLabel("Max: ")
868865

869866
# Linear/Log scaling check box
870867
self.scaleBox = QCheckBox()
@@ -899,10 +896,9 @@ def __init__(self, model, main_window, field, colormaps=None):
899896
self.layout.addRow("Colormap: ", self.colormapBox)
900897
self.layout.addRow("Reverse colormap: ", self.reverseCmapBox)
901898
self.layout.addRow("Data Indicator: ", self.dataIndicatorCheckBox)
902-
self.layout.addRow("Custom Min/Max: ", self.userMinMaxBox)
903-
self.layout.addRow("Min: ", self.minBox)
904-
self.layout.addRow("Max: ", self.maxBox)
905-
self.layout.addRow("Auto rescale: ", self.autoRescaleBox)
899+
self.layout.addRow("Min/max: ", self.minMaxTypeBox)
900+
self.layout.addRow(self.minLabel, self.minBox)
901+
self.layout.addRow(self.maxLabel, self.maxBox)
906902
self.layout.addRow("Log Scale: ", self.scaleBox)
907903
self.layout.addRow("Clip Data: ", self.clipDataBox)
908904
self.layout.addRow("Mask Zeros: ", self.maskZeroBox)
@@ -920,22 +916,26 @@ def updateDataIndicator(self):
920916
cv = self.model.currentView
921917
self.dataIndicatorCheckBox.setChecked(cv.tallyDataIndicator)
922918

923-
def updateAutoRescale(self):
919+
def updateMinMaxType(self):
920+
"""Update the min/max type dropdown and show/hide min/max inputs."""
924921
cv = self.model.currentView
925-
self.autoRescaleBox.setChecked(cv.tallyDataAutoRescale)
926-
self.autoRescaleBox.setEnabled(not cv.tallyDataUserMinMax)
927-
928-
def setMinMaxEnabled(self, enable):
929-
enable = bool(enable)
930-
self.minBox.setEnabled(enable)
931-
self.maxBox.setEnabled(enable)
932-
self.autoRescaleBox.setEnabled(not enable)
922+
type_map = {'full': 0, 'visible': 1, 'custom': 2}
923+
idx = type_map.get(cv.tallyDataMinMaxType, 0)
924+
self.minMaxTypeBox.blockSignals(True)
925+
self.minMaxTypeBox.setCurrentIndex(idx)
926+
self.minMaxTypeBox.blockSignals(False)
927+
# Show/hide min/max inputs based on whether custom is selected
928+
show_custom = (cv.tallyDataMinMaxType == 'custom')
929+
self.minLabel.setVisible(show_custom)
930+
self.minBox.setVisible(show_custom)
931+
self.maxLabel.setVisible(show_custom)
932+
self.maxBox.setVisible(show_custom)
933933

934934
def updateMinMax(self):
935935
cv = self.model.currentView
936936
self.minBox.setValue(cv.tallyDataMin)
937937
self.maxBox.setValue(cv.tallyDataMax)
938-
self.setMinMaxEnabled(cv.tallyDataUserMinMax)
938+
self.updateMinMaxType()
939939

940940
def updateTallyVisibility(self):
941941
cv = self.model.currentView
@@ -963,13 +963,11 @@ def update(self):
963963

964964
self.alphaBox.setValue(cv.tallyDataAlpha)
965965
self.visibilityBox.setChecked(cv.tallyDataVisible)
966-
self.userMinMaxBox.setChecked(cv.tallyDataUserMinMax)
967966
self.scaleBox.setChecked(cv.tallyDataLogScale)
968967

969968
self.updateMinMax()
970969
self.updateMaskZeros()
971970
self.updateVolumeNorm()
972971
self.updateDataClip()
973-
self.updateAutoRescale()
974972
self.updateDataIndicator()
975973
self.updateTallyContours()

openmc_plotter/main_window.py

Lines changed: 21 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -1037,23 +1037,29 @@ def toggleTallyDataClip(self, state):
10371037
av = self.model.activeView
10381038
av.clipTallyData = bool(state)
10391039

1040-
def toggleTallyAutoRescale(self, state, apply=False):
1041-
av = self.model.activeView
1042-
if av.tallyDataUserMinMax:
1043-
av.tallyDataAutoRescale = False
1044-
self.tallyDock.tallyColorForm.updateAutoRescale()
1045-
return
1046-
av.tallyDataAutoRescale = bool(state)
1047-
if apply:
1048-
self.applyChanges()
1040+
def setTallyMinMaxType(self, index, apply=False):
1041+
"""Set the min/max type for tally data.
10491042
1050-
def toggleTallyDataUserMinMax(self, state, apply=False):
1043+
Parameters
1044+
----------
1045+
index : int
1046+
Index of the selected option: 0='full', 1='visible', 2='custom'
1047+
apply : bool
1048+
Whether to apply changes immediately
1049+
"""
10511050
av = self.model.activeView
1052-
av.tallyDataUserMinMax = bool(state)
1053-
if av.tallyDataUserMinMax:
1054-
av.tallyDataAutoRescale = False
1055-
self.tallyDock.tallyColorForm.setMinMaxEnabled(bool(state))
1056-
self.tallyDock.tallyColorForm.updateAutoRescale()
1051+
type_map = {0: 'full', 1: 'visible', 2: 'custom'}
1052+
new_type = type_map.get(index, 'full')
1053+
av.tallyDataMinMaxType = new_type
1054+
1055+
# Immediately update visibility of min/max fields based on selection
1056+
show_custom = (new_type == 'custom')
1057+
form = self.tallyDock.tallyColorForm
1058+
form.minLabel.setVisible(show_custom)
1059+
form.minBox.setVisible(show_custom)
1060+
form.maxLabel.setVisible(show_custom)
1061+
form.maxBox.setVisible(show_custom)
1062+
10571063
if apply:
10581064
self.applyChanges()
10591065

openmc_plotter/plotgui.py

Lines changed: 12 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -559,7 +559,7 @@ def updatePixmap(self):
559559
# draw tally image
560560
if image_data is not None:
561561

562-
if not cv.tallyDataUserMinMax:
562+
if cv.tallyDataMinMaxType != 'custom':
563563
cv.tallyDataMin = data_min
564564
cv.tallyDataMax = data_max
565565
else:
@@ -583,16 +583,19 @@ def updatePixmap(self):
583583
image_data = np.ma.masked_where(image_mask, image_data)
584584

585585
# auto-rescale based on displayed (imshow) data
586-
if cv.tallyDataAutoRescale and not cv.tallyContours and not cv.tallyDataUserMinMax:
586+
if cv.tallyDataMinMaxType == 'visible' and not cv.tallyContours:
587587
displayed = image_data.compressed()
588588
if displayed.size:
589-
data_min = float(displayed.min())
590-
data_max = float(displayed.max())
591-
cv.tallyDataMin = data_min
592-
cv.tallyDataMax = data_max
593-
else:
594-
data_min = cv.tallyDataMin
595-
data_max = cv.tallyDataMax
589+
visible_min = float(displayed.min())
590+
visible_max = float(displayed.max())
591+
# Fall back to full data range if visible range is invalid for log scale
592+
if cv.tallyDataLogScale and visible_min <= 0:
593+
pass # keep the full data range
594+
else:
595+
data_min = visible_min
596+
data_max = visible_max
597+
cv.tallyDataMin = data_min
598+
cv.tallyDataMax = data_max
596599

597600
if extents is None:
598601
extents = data_bounds

openmc_plotter/plotmodel.py

Lines changed: 11 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -937,8 +937,8 @@ class PlotViewIndependent:
937937
Minimum scale value for tally data
938938
tallyDataLogScale : bool
939939
Indicator of logarithmic scale for tally data
940-
tallyDataAutoRescale : bool
941-
Indicator of whether tally colorbar range auto-rescales
940+
tallyDataMinMaxType : str
941+
Type of min/max scaling for tally data: 'full', 'visible', or 'custom'
942942
tallyMaskZeroValues : bool
943943
Indicates whether or not zero values in tally data should be masked
944944
clipTallyData: bool
@@ -982,11 +982,10 @@ def __init__(self):
982982
self.tallyDataVisible = True
983983
self.tallyDataAlpha = 1.0
984984
self.tallyDataIndicator = False
985-
self.tallyDataUserMinMax = False
985+
self.tallyDataMinMaxType = 'full' # 'full', 'visible', or 'custom'
986986
self.tallyDataMin = 0.0
987987
self.tallyDataMax = np.inf
988988
self.tallyDataLogScale = False
989-
self.tallyDataAutoRescale = False
990989
self.tallyMaskZeroValues = False
991990
self.tallyVolumeNorm = False
992991
self.clipTallyData = False
@@ -1002,8 +1001,14 @@ def __setstate__(self, state):
10021001
self.outlinesCell = False
10031002
if not hasattr(self, 'outlinesMat'):
10041003
self.outlinesMat = False
1005-
if not hasattr(self, 'tallyDataAutoRescale'):
1006-
self.tallyDataAutoRescale = False
1004+
# Migrate old boolean attributes to new tallyDataMinMaxType
1005+
if not hasattr(self, 'tallyDataMinMaxType'):
1006+
if getattr(self, 'tallyDataUserMinMax', False):
1007+
self.tallyDataMinMaxType = 'custom'
1008+
else:
1009+
self.tallyDataMinMaxType = 'full'
1010+
# Remove old attributes if present
1011+
self.__dict__.pop('tallyDataUserMinMax', None)
10071012

10081013
def getDataLimits(self):
10091014
return self.data_minmax

0 commit comments

Comments
 (0)