Skip to content

Commit

Permalink
Add percentile getter methods to CILViewerBase and CILViewer (#336)
Browse files Browse the repository at this point in the history
* Add percentile getters

* Add CILViewerBase test

* update changelog and add skipping of tests in gh-actions

* Automated autoyapf fixes

* add hack for skipping viewer test on gh-a docker build
  • Loading branch information
lauramurgatroyd authored Jan 26, 2023
1 parent d1d29f9 commit 2c619c7
Show file tree
Hide file tree
Showing 6 changed files with 195 additions and 1 deletion.
2 changes: 1 addition & 1 deletion .github/workflows/docker_build_test_publish.yml
Original file line number Diff line number Diff line change
Expand Up @@ -33,5 +33,5 @@ jobs:
- name: Run docker container with tests
shell: bash -l {0}
run: |
docker run --rm --entrypoint /bin/bash -v /home/runner/work/CILViewer/CILViewer:/root/source_code cil-viewer -c "source ./mambaforge/etc/profile.d/conda.sh && conda activate cilviewer_webapp && conda install cil-data pytest -c ccpi && python -m pytest /root/source_code/Wrappers/Python -k 'not test_version and not test_cli_resample'"
docker run --rm --entrypoint /bin/bash -v /home/runner/work/CILViewer/CILViewer:/root/source_code cil-viewer -c "source ./mambaforge/etc/profile.d/conda.sh && conda activate cilviewer_webapp && conda install cil-data pytest -c ccpi && python -m pytest /root/source_code/Wrappers/Python -k 'not test_version and not test_cli_resample and not test_CILViewerBase and not test_CILViewer3D'"
# TODO: publish to come later
6 changes: 6 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,12 @@
do this for some hdf5 formats.
- Fix bug with returning HDF5 attributes from HDF5Reader
- Move code for resetting camera out of TrameViewer3D and into CILViewer
- Adds the following methods to CILViewer (and corresponding unit tests):
- getGradientOpacityPercentiles
- getScalarOpacityPercentiles
- getVolumeColorPercentiles
- Adds to CILViewerBase (and corresponding unit tests):
- getSliceColorPercentiles
- setup.py:
- Always normalise the version from git describe to pep440

Expand Down
45 changes: 45 additions & 0 deletions Wrappers/Python/ccpi/viewer/CILViewer.py
Original file line number Diff line number Diff line change
Expand Up @@ -749,6 +749,21 @@ def setGradientOpacityPercentiles(self, min, max, update_pipeline=True):
go_min, go_max = self.getImageMapRange((min, max), 'gradient')
self.setGradientOpacityRange(go_min, go_max, update_pipeline)

def getGradientOpacityPercentiles(self):
'''
Returns
-----------
min, max: float, default: (80., 99.)
the percentiles on the image gradient values that the
opacity will be mapped to if setVolumeRenderOpacityMethod
has been set to 'gradient'.
'''
go_min, go_max = self.getGradientOpacityRange()
value_min, value_max = self.getImageMapWholeRange('gradient')
min_percentage = (go_min - value_min) / (value_max - value_min) * 100
max_percentage = (go_max - value_min) / (value_max - value_min) * 100
return min_percentage, max_percentage

def setScalarOpacityPercentiles(self, min, max, update_pipeline=True):
'''
min, max: float, default: (80., 99.)
Expand All @@ -759,14 +774,44 @@ def setScalarOpacityPercentiles(self, min, max, update_pipeline=True):
so_min, so_max = self.getImageMapRange((min, max), 'scalar')
self.setScalarOpacityRange(so_min, so_max, update_pipeline)

def getScalarOpacityPercentiles(self):
'''
Returns
-----------
min, max: float, default: (80., 99.)
the percentiles on the image values that the
opacity will be mapped to if setVolumeRenderOpacityMethod
has been set to 'scalar'.
'''
so_min, so_max = self.getScalarOpacityRange()
value_min, value_max = self.getImageMapWholeRange('scalar')
min_percentage = (so_min - value_min) / (value_max - value_min) * 100
max_percentage = (so_max - value_min) / (value_max - value_min) * 100
return min_percentage, max_percentage

def setVolumeColorPercentiles(self, min, max, update_pipeline=True):
'''
Parameters
-----------
min, max: int, default: (85., 95.)
the percentiles on the image values upon which the colours will be mapped to
'''
cmin, cmax = self.getImageMapRange((min, max), 'scalar')
self.setVolumeColorRange(cmin, cmax, update_pipeline)

def getVolumeColorPercentiles(self):
'''
Returns
-----------
min, max: int, default: (85., 95.)
the percentiles on the image values upon which the colours will be mapped to
'''
cmin, cmax = self.getVolumeColorRange()
value_min, value_max = self.getImageMapWholeRange('scalar')
min_percentage = (cmin - value_min) / (value_max - value_min) * 100
max_percentage = (cmax - value_min) / (value_max - value_min) * 100
return min_percentage, max_percentage

def setGradientOpacityRange(self, min, max, update_pipeline=True):
'''
Parameters
Expand Down
7 changes: 7 additions & 0 deletions Wrappers/Python/ccpi/viewer/CILViewerBase.py
Original file line number Diff line number Diff line change
Expand Up @@ -266,6 +266,13 @@ def setSliceColorPercentiles(self, min_percentage, max_percentage):
min_val, max_val = self.getSliceMapRange((min_percentage, max_percentage), 'scalar')
self.setSliceMapRange(min_val, max_val)

def getSliceColorPercentiles(self):
min_val, max_val = self.getSliceMapWholeRange('scalar')
min_color, max_color = self.getSliceMapRange()
min_percentage = (min_color - min_val) / (max_val - min_val) * 100
max_percentage = (max_color - min_val) / (max_val - min_val) * 100
return min_percentage, max_percentage

def setSliceColorWindow(self, window):
'''
Set the window for the 2D slice of the 3D image.
Expand Down
82 changes: 82 additions & 0 deletions Wrappers/Python/test/test_CILViewer3D.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,82 @@
# Copyright 2023 STFC, United Kingdom Research and Innovation
#
# Author 2023 Laura Murgatroyd
#
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at
#
# http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.
#
import os
import unittest
from unittest import mock

from ccpi.viewer.CILViewer import CILViewer

# skip the tests on GitHub actions
if os.environ.get('CONDA_BUILD', '0') == '1':
skip_test = True
else:
skip_test = False

print("skip_test is set to ", skip_test)


@unittest.skipIf(skip_test, "Skipping tests on GitHub Actions")
class CILViewer3DTest(unittest.TestCase):

def setUp(self):
self.cil_viewer = CILViewer()

def test_getGradientOpacityPercentiles_returns_correct_percentiles_when_image_values_start_at_zero(self):
self.cil_viewer.gradient_opacity_limits = [40, 50]
self.cil_viewer.getImageMapWholeRange = mock.MagicMock(return_value=[0, 50])
expected_percentages = (80.0, 100.0)
actual_percentages = self.cil_viewer.getGradientOpacityPercentiles()
self.assertEqual(expected_percentages, actual_percentages)

def test_getGradientOpacityPercentiles_returns_correct_percentiles_when_image_values_start_at_non_zero(self):
self.cil_viewer.gradient_opacity_limits = [40, 50]
self.cil_viewer.getImageMapWholeRange = mock.MagicMock(return_value=[10, 50])
expected_percentages = (75.0, 100.0)
actual_percentages = self.cil_viewer.getGradientOpacityPercentiles()
self.assertEqual(expected_percentages, actual_percentages)

def test_getScalarOpacityPercentiles_returns_correct_percentiles_when_image_values_start_at_zero(self):
self.cil_viewer.scalar_opacity_limits = [40, 50]
self.cil_viewer.getImageMapWholeRange = mock.MagicMock(return_value=[0, 50])
expected_percentages = (80.0, 100.0)
actual_percentages = self.cil_viewer.getScalarOpacityPercentiles()
self.assertEqual(expected_percentages, actual_percentages)

def test_getScalarOpacityPercentiles_returns_correct_percentiles_when_image_values_start_at_non_zero(self):
self.cil_viewer.scalar_opacity_limits = [40, 50]
self.cil_viewer.getImageMapWholeRange = mock.MagicMock(return_value=[10, 50])
expected_percentages = (75.0, 100.0)
actual_percentages = self.cil_viewer.getScalarOpacityPercentiles()
self.assertEqual(expected_percentages, actual_percentages)

def test_getVolumeColorPercentiles_returns_correct_percentiles_when_image_values_start_at_zero(self):
self.cil_viewer.volume_colormap_limits = [40, 50]
self.cil_viewer.getImageMapWholeRange = mock.MagicMock(return_value=[0, 50])
expected_percentages = (80.0, 100.0)
actual_percentages = self.cil_viewer.getVolumeColorPercentiles()
self.assertEqual(expected_percentages, actual_percentages)

def test_getVolumeColorPercentiles_returns_correct_percentiles_when_image_values_start_at_non_zero(self):
self.cil_viewer.volume_colormap_limits = [40, 50]
self.cil_viewer.getImageMapWholeRange = mock.MagicMock(return_value=[10, 50])
expected_percentages = (75.0, 100.0)
actual_percentages = self.cil_viewer.getVolumeColorPercentiles()
self.assertEqual(expected_percentages, actual_percentages)


if __name__ == '__main__':
unittest.main()
54 changes: 54 additions & 0 deletions Wrappers/Python/test/test_CILViewerBase.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,54 @@
# Copyright 2023 STFC, United Kingdom Research and Innovation
#
# Author 2023 Laura Murgatroyd
#
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at
#
# http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.
#
import unittest
from unittest import mock
import os

from ccpi.viewer.CILViewer import CILViewerBase

# skip the tests on GitHub actions
if os.environ.get('CONDA_BUILD', '0') == '1':
skip_test = True
else:
skip_test = False

print("skip_test is set to ", skip_test)


@unittest.skipIf(skip_test, "Skipping tests on GitHub Actions")
class CILViewer3DTest(unittest.TestCase):

def setUp(self):
self.cil_viewer = CILViewerBase()

def test_getSliceColorPercentiles_returns_correct_percentiles_when_slice_values_start_at_zero(self):
self.cil_viewer.getSliceMapRange = mock.MagicMock(return_value=[40, 50])
self.cil_viewer.getSliceMapWholeRange = mock.MagicMock(return_value=[0, 50])
expected_percentages = (80.0, 100.0)
actual_percentages = self.cil_viewer.getSliceColorPercentiles()
self.assertEqual(expected_percentages, actual_percentages)

def test_getSliceColorPercentiles_returns_correct_percentiles_when_slice_values_start_at_non_zero(self):
self.cil_viewer.getSliceMapRange = mock.MagicMock(return_value=[40, 50])
self.cil_viewer.getSliceMapWholeRange = mock.MagicMock(return_value=[10, 50])
expected_percentages = (75.0, 100.0)
actual_percentages = self.cil_viewer.getSliceColorPercentiles()
self.assertEqual(expected_percentages, actual_percentages)


if __name__ == '__main__':
unittest.main()

0 comments on commit 2c619c7

Please sign in to comment.