Skip to content

Commit cd1d5f8

Browse files
committed
ENH: Add custom validation functions for interpolator, wavelet, weightingNorm
Custom validation is needed for interpolator and weightingNorm, as regular Enum does not support a None value, causing validation to fail when user attempts to set None. By using custom validation, a None value will be accepted here. Additionally validate the wavelet setting against the list of possible values in pyWavelets, ensuring no errors arrise when pyWavelet does not have the current set, as well as enabling any newly added wavelets when they are added to pyWavelet. Update the documentation to reflect this.
1 parent 1c04fca commit cd1d5f8

File tree

4 files changed

+56
-19
lines changed

4 files changed

+56
-19
lines changed

data/paramSchema.yaml

Lines changed: 5 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -20,17 +20,8 @@ mapping:
2020
range:
2121
min-ex: 0
2222
interpolator:
23-
type: str
24-
enum: ['sitkNearestNeighbor',
25-
'sitkLinear',
26-
'sitkBSpline',
27-
'sitkGaussian',
28-
'sitkLabelGaussian',
29-
'sitkHammingWindowedSinc',
30-
'sitkCosineWindowedSinc',
31-
'sitkWelchWindowedSinc',
32-
'sitkLanczosWindowedSinc',
33-
'sitkBlackmanWindowedSinc']
23+
type: any
24+
func: checkInterpolator
3425
padDistance:
3526
type: int
3627
range:
@@ -50,14 +41,14 @@ mapping:
5041
min-ex: 0
5142
wavelet:
5243
type: str
53-
pattern: ((haar|dmey)|(rbio|bior)(1.1|1.3|1.5|2.2|2.4|2.6|2.8|3.1|3.3|3.5|3.7|3.9|4.4|5.5|6.8)|coif[1-5]|db[1-20|sym[2-20])$
44+
func: checkWavelet
5445
voxelArrayShift:
5546
type: int
5647
symmetricalGLCM:
5748
type: bool
5849
weightingNorm:
59-
type: str
60-
enum: ['infinity', 'euclidean', 'manhattan']
50+
type: any
51+
func: checkWeighting
6152
gldm_a:
6253
type: int
6354
range:

data/schemaFuncs.py

Lines changed: 43 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,43 @@
1+
import pywt
2+
3+
def checkWavelet(value, rule_obj, path):
4+
if not isinstance(value, basestring):
5+
raise TypeError('Wavelet not expected type (str)')
6+
wavelist = pywt.wavelist()
7+
if value not in wavelist:
8+
raise ValueError('Wavelet "%s" not available in pyWavelets %s' %(value, wavelist))
9+
return True
10+
11+
def checkInterpolator(value, rule_obj, path):
12+
if value is None:
13+
return True
14+
if isinstance(value, basestring):
15+
enum = {'sitkNearestNeighbor',
16+
'sitkLinear',
17+
'sitkBSpline',
18+
'sitkGaussian',
19+
'sitkLabelGaussian',
20+
'sitkHammingWindowedSinc',
21+
'sitkCosineWindowedSinc',
22+
'sitkWelchWindowedSinc',
23+
'sitkLanczosWindowedSinc',
24+
'sitkBlackmanWindowedSinc'}
25+
if value not in enum:
26+
raise ValueError('Interpolator value "%s" not valid, possible values: %s' %(value, enum))
27+
elif isinstance(value, int):
28+
if value < 1 or value > 10:
29+
raise ValueError('Intepolator value %i, must be in range of [1-10]' %(value))
30+
else:
31+
raise TypeError('Interpolator not expected type (str or int)')
32+
return True
33+
34+
def checkWeighting(value, rule_obj, path):
35+
if value is None:
36+
return True
37+
elif isinstance(value, basestring):
38+
enum = ['euclidean', 'manhattan', 'infinity', 'no_weighting']
39+
if value not in enum:
40+
raise ValueError('WeightingNorm value "%s" not valid, possible values: %s' % (value, enum))
41+
else:
42+
raise TypeError('WeightingNorm not expected type (str or None)')
43+
return True

radiomics/featureextractor.py

Lines changed: 7 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -127,8 +127,10 @@ def loadParams(self, paramsFile):
127127
128128
If supplied params file does not match the requirements, a pykwalify error is raised.
129129
"""
130-
schemafile = os.path.abspath(os.path.join(radiomics.__path__[0], '..', 'data', 'paramSchema.yaml'))
131-
c = pykwalify.core.Core(source_file=paramsFile, schema_files=[schemafile])
130+
dataDir = os.path.abspath(os.path.join(radiomics.__path__[0], '..', 'data'))
131+
schemaFile = os.path.join(dataDir, 'paramSchema.yaml')
132+
schemaFuncs = os.path.join(dataDir, 'schemaFuncs.py')
133+
c = pykwalify.core.Core(source_file=paramsFile, schema_files=[schemaFile], extensions=[schemaFuncs])
132134
params = c.validate()
133135

134136
inputImages = params.get('inputImage', {})
@@ -428,8 +430,9 @@ def generate_wavelet(self, image, mask, **kwargs):
428430
- start_level [0]: integer, 0 based level of wavelet which should be used as first set of decompositions
429431
from which a signature is calculated
430432
- level [1]: integer, number of levels of wavelet decompositions from which a signature is calculated.
431-
- wavelet ["coif1"]: string, type of wavelet decomposition. Enumerated value, possible values, where an
432-
aditional number is needed, range of values is indicated in []:
433+
- wavelet ["coif1"]: string, type of wavelet decomposition. Enumerated value, validated against possible values
434+
present in the ``pyWavelet.wavelist()``. Current possible values (pywavelet version 0.4.0) (where an
435+
aditional number is needed, range of values is indicated in []):
433436
434437
- haar
435438
- dmey

setup.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -13,7 +13,7 @@
1313
'PyWavelets>=0.4.0',
1414
'pykwalify>=1.5.2',
1515
'sphinx>=1.4'],
16-
data_files=[('data', ['data/paramSchema.yaml'])],
16+
data_files=[('data', ['data/paramSchema.yaml', 'data/schemaFuncs.py'])],
1717
description='Radiomics features library for python',
1818
url='http://github.com/Radiomics/pyradiomics',
1919
author='pyradiomics community',

0 commit comments

Comments
 (0)