diff --git a/.coverage b/.coverage deleted file mode 100644 index a1b2956e..00000000 --- a/.coverage +++ /dev/null @@ -1 +0,0 @@ -!coverage.py: This is a private format, don't read it directly!{"lines":{"/home/martijn/git/WORC/WORC/processing/RTStructReader.py":[],"/home/martijn/git/WORC/WORC/WORC.py":[976,304,99,324,101,842,972,301,845,144,977,18,19,20,21,22,23,24,25,28,965],"/home/martijn/git/WORC/WORC/IOparser/config_segmentix.py":[],"/home/martijn/git/WORC/WORC/addexceptions.py":[35,73,95,76,80,81,20,87,88,84,91,94,31],"/home/martijn/git/WORC/WORC/tools/Evaluate.py":[203,204,205,61,18,19,20,25,26,27,28,29,255],"/home/martijn/git/WORC/WORC/processing/ExtractNLargestBlobsn.py":[],"/home/martijn/git/WORC/WORC/__init__.py":[1,2],"/home/martijn/git/WORC/WORC/IOparser/__init__.py":[1],"/home/martijn/git/WORC/WORC/IOparser/config_WORC.py":[19,22],"/home/martijn/git/WORC/WORC/processing/__init__.py":[1],"/home/martijn/git/WORC/WORC/IOparser/config_preprocessing.py":[],"/home/martijn/git/WORC/WORC/tools/Elastix.py":[194,212,46,240,18,19,20,21,22,87,25,26],"/home/martijn/git/WORC/WORC/tools/Transformix.py":[],"/home/martijn/git/WORC/WORC/processing/classes.py":[],"/home/martijn/git/WORC/WORC/tools/__init__.py":[1]}} \ No newline at end of file diff --git a/.eggs/PyWavelets-1.0.0-py3.7-linux-x86_64.egg/EGG-INFO/PKG-INFO b/.eggs/PyWavelets-1.0.0-py3.7-linux-x86_64.egg/EGG-INFO/PKG-INFO deleted file mode 100644 index 55cb6e16..00000000 --- a/.eggs/PyWavelets-1.0.0-py3.7-linux-x86_64.egg/EGG-INFO/PKG-INFO +++ /dev/null @@ -1,44 +0,0 @@ -Metadata-Version: 2.1 -Name: PyWavelets -Version: 1.0.0 -Summary: PyWavelets, wavelet transform module -Home-page: https://github.com/PyWavelets/pywt -Maintainer: The PyWavelets Developers -Maintainer-email: pywavelets@googlegroups.com -License: MIT -Download-URL: https://github.com/PyWavelets/pywt/releases -Keywords: wavelets,wavelet transform,DWT,SWT,CWT,scientific -Platform: Windows -Platform: Linux -Platform: Solaris -Platform: Mac OS-X -Platform: Unix -Classifier: Development Status :: 5 - Production/Stable -Classifier: Intended Audience :: Developers -Classifier: Intended Audience :: Education -Classifier: Intended Audience :: Science/Research -Classifier: License :: OSI Approved :: MIT License -Classifier: Operating System :: OS Independent -Classifier: Programming Language :: C -Classifier: Programming Language :: Python -Classifier: Programming Language :: Python :: 3 -Classifier: Programming Language :: Python :: 2.7 -Classifier: Programming Language :: Python :: 3.5 -Classifier: Programming Language :: Python :: 3.6 -Classifier: Programming Language :: Python :: 3.7 -Classifier: Topic :: Software Development :: Libraries :: Python Modules -Requires-Dist: numpy (>=1.9.1) - -PyWavelets is a Python wavelet transforms module that includes: - -* nD Forward and Inverse Discrete Wavelet Transform (DWT and IDWT) -* 1D and 2D Forward and Inverse Stationary Wavelet Transform (Undecimated Wavelet Transform) -* 1D and 2D Wavelet Packet decomposition and reconstruction -* 1D Continuous Wavelet Tranfsorm -* Computing Approximations of wavelet and scaling functions -* Over 100 built-in wavelet filters and support for custom wavelets -* Single and double precision calculations -* Real and complex calculations -* Results compatible with Matlab Wavelet Toolbox (TM) - - diff --git a/.eggs/PyWavelets-1.0.0-py3.7-linux-x86_64.egg/EGG-INFO/RECORD b/.eggs/PyWavelets-1.0.0-py3.7-linux-x86_64.egg/EGG-INFO/RECORD deleted file mode 100644 index 7f261c5b..00000000 --- a/.eggs/PyWavelets-1.0.0-py3.7-linux-x86_64.egg/EGG-INFO/RECORD +++ /dev/null @@ -1,55 +0,0 @@ -pywt/_swt.py,sha256=1RIJMRKbp5UhsCBR2YAPtc_DSYs7gGC2qMPVibY4ZWM,19624 -pywt/_multidim.py,sha256=TE562UFNeNbeBR2b1BJG6Fvml-AzbEJ1vifEmXcwZ54,10897 -pywt/_cwt.py,sha256=3OR5RZaOeHY90N5kGS0JSa0M4bEn4uSNkCmWMorPtQY,4038 -pywt/_wavelet_packets.py,sha256=6LTs4Ft2cNH5g2RxrYglOg6x0UgYqBj2xJrXSkua84o,24286 -pywt/__init__.py,sha256=vi7HuOCXrFugIjMpwf4SdkrwQgdrh2P-5Q1s3xd4YYA,1267 -pywt/_thresholding.py,sha256=z2u-7EZT3fJ9RhuhPry8NBDqoqaEdoKMaEH7SE-TPU4,8636 -pywt/version.py,sha256=s2fc0l59372892RGx3Uau-BHLyv9GKkn-jnWC4RwDfc,233 -pywt/_dwt.py,sha256=QOKv7Pf21e8wIWU_Nn-OfnhbwWs-IjOCdIMQMCCnJ18,12327 -pywt/_utils.py,sha256=NAe-KEOH7g_LTY3XbA860O0bgJDVaaPUz2WwYgS72k0,4028 -pywt/_c99_config.py,sha256=LrMSEmGvgjoA5sE-BdpF7pUOXSNCfLfNUy6RG5z-6Bo,80 -pywt/_multilevel.py,sha256=tkaAWvbuVdGDY2zCN36BABCJLmDOfL7HmqUdlY2joeI,54480 -pywt/_doc_utils.py,sha256=aUdX1dIzCLitHsHx2N0Gz5SZQi1baMQvP4BYgJEjS1Y,9759 -pywt/_functions.py,sha256=hvOQb4tn01j1s5_lNhbBBoCMeOvF1_3Q9mt0aEA1bI8,6999 -pywt/_extensions/_dwt.cpython-37m-x86_64-linux-gnu.so,sha256=AIMtLj87MoDiujSITKilJTJWlAqYkXSIybpIMOVEFe4,475104 -pywt/_extensions/_cwt.cpython-37m-x86_64-linux-gnu.so,sha256=r1UXLXcwCSyeLB_4YSo6Bjn5HObPhhTW7WYpQ28nYOs,290400 -pywt/_extensions/_pywt.cpython-37m-x86_64-linux-gnu.so,sha256=UtMABFSN4zn4sZIPIhTXSNQp1WRSFCjfdQ1Q1oQdHrU,525344 -pywt/_extensions/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0 -pywt/_extensions/_swt.cpython-37m-x86_64-linux-gnu.so,sha256=GFCZGU36V7GQOy-znZuG1WWSmKCzQaTkZ93gm_6gmrE,367808 -pywt/tests/test_dwt_idwt.py,sha256=Wgyv_q3b-kvrtjFBo_r4xv49u3uNb1kPA804ZbXBKvc,6684 -pywt/tests/test_modes.py,sha256=zOI5bio5CyPNzD_-YwKWz4zi9LijMVBv1rjd-FHL6TQ,4947 -pywt/tests/test_multilevel.py,sha256=OLNRoZh9oNxpfEQWhixJiZnjy-LJkMNnwFKlpIsTrj4,35728 -pywt/tests/test_functions.py,sha256=R0WqvfAGvmSQ1KIg9J3qIxh6vVBLFPiN7RUx_Q-VpCs,1262 -pywt/tests/test_cwt_wavelets.py,sha256=vPv7c62puMUTWbqnu34F-SKvzcpkTnNb9jL9Xst9Gjo,10730 -pywt/tests/test_data.py,sha256=fh667448ThGV2N_CCptqAtvVhptkvfulKqfZN68-xTI,2365 -pywt/tests/test_wp2d.py,sha256=SgbajDJ1mds0UnXenRweb9hHuEV7hPsFjuUdoPcRgAs,6547 -pywt/tests/test_wavelet.py,sha256=d-ToUH7iUjkhqBt6sF6ZttRNweMDa8lca6JUlGhgvME,11270 -pywt/tests/test_swt.py,sha256=2_zZe7FFXH2F-aNexwntNF1bDGvgp1qK385Ra6gzHEA,16561 -pywt/tests/test_matlab_compatibility.py,sha256=6B8O6FqfRHxPmeA2y3nzhB0Ch4uwvqSLrfN-Bj2vh7Y,6595 -pywt/tests/test_thresholding.py,sha256=fd3WN37wv_Tw2EWGmdYnQRMT9KleZTvIfbtOjOpNOX8,6632 -pywt/tests/test_matlab_compatibility_cwt.py,sha256=OC7hOFIn1rUQQEMRh4T_Ykbt8Vh1-RpaoWmoDsroVqk,6592 -pywt/tests/test__pywt.py,sha256=Q5fajcmem0AK_Uw0eqU0wpLH8I6zvkR7jPvalAsui5A,5568 -pywt/tests/test_perfect_reconstruction.py,sha256=y1x5dfY02-P1Yg-_PxOnWHpMnA8HLWyrsvFKi8B45Ig,1871 -pywt/tests/test_deprecations.py,sha256=iMCKWVcweJsJsYCuO7PhhEhcSrWcNzQ3LT5wtud2-LY,2290 -pywt/tests/test_concurrent.py,sha256=ZChpcQIiIosAMmAmfSmwChnaSOfmVfPzLK6rCyYpldQ,4385 -pywt/tests/test_doc.py,sha256=MNv2zeKOjNnqazIa4YL-7Y-jvkuNwKammH_ReWjjUO8,528 -pywt/tests/test_multidim.py,sha256=kEgEVLl6UqyAuM7W_IY-iwo7Supb-O0lOlzbJ_-CdOo,14531 -pywt/tests/test_wp.py,sha256=okUlJFwVBaX-5pTxIzVGO4yy9uyCcK_0HpLimDqG9MI,6284 -pywt/tests/data/dwt_matlabR2012a_result.npz,sha256=H3zj71AxK1VbM7HZArX5El_qnfH_LLHAlVWj9eLhMmM,3590870 -pywt/tests/data/generate_matlab_data.py,sha256=Spz3yi0kYJF9B1-nDTHhRDBwRexvyjoCT3iuNx7T4xc,3957 -pywt/tests/data/generate_matlab_data_cwt.py,sha256=GJ7dW31zW2CmiLUzQP96uQ3CK2yTU4k4TF3tMEtFDWE,3238 -pywt/tests/data/wavelab_test_signals.npz,sha256=-cx0ne9JdTcq6LiKBacjM_0_En72TAiKvvFUW1yiZYE,184818 -pywt/tests/data/cwt_matlabR2015b_result.npz,sha256=FA1Tx-q_1k74bb7yERH_lq4hgZEVwdNP3RVm8lu-_Zw,1819506 -pywt/data/_readers.py,sha256=PSkP5ejSNiHCtZkvv8xwjOVznIo_p-hixsq_oF_UloQ,4530 -pywt/data/aero.npz,sha256=34YmNXmLrJQia4ko8iTajO-LDQBJLB_fSPrG36-XqUs,227784 -pywt/data/__init__.py,sha256=qoDFVHX0RNi91n3UwC7UwYU3UGzbgdGD2OCH9zGJ8mo,96 -pywt/data/ascent.npz,sha256=ptVryOllcdYSTzTO3rpJ8dNZlQf2yJCtm6U4VERU6Pc,170883 -pywt/data/camera.npz,sha256=CfIDuSct94Yvk3GR4d897-G0VSeL6SG3omdrbmaGyoA,160418 -pywt/data/create_dat.py,sha256=8BsF3dCoixafNSi5jxZnHdvK69FTH6dIGNJNIlv6c60,625 -pywt/data/_wavelab_signals.py,sha256=7ay4VKhYkMsdrmrMm_FeBKrewzGzrwuoy6sO_RkR8vY,9476 -pywt/data/ecg.npy,sha256=iS9GVe4jRwWTxs8c4X8Of0f2ywMBJKkvVQ5bFyrUPTk,4176 -pywt/data/sst_nino3.npz,sha256=-vMX2TEULdISSSkMpmevDecdiZ5_I4Zk3zC2xB0Qz1c,64200 -PyWavelets-1.0.0.dist-info/WHEEL,sha256=AhV6RMqZ2IDfreRJKo44QWYxYeP-0Jr0bezzBLQ1eog,109 -PyWavelets-1.0.0.dist-info/top_level.txt,sha256=j3eDFZWsDkiyrSwsdc1H0AjhXkTzsuJLSx-blZUoOVo,5 -PyWavelets-1.0.0.dist-info/METADATA,sha256=Nn1vdyBpGZ448eq3RP56sS8HO-Kcv8yo85fAvoI3G_s,1750 -PyWavelets-1.0.0.dist-info/RECORD,, diff --git a/.eggs/PyWavelets-1.0.0-py3.7-linux-x86_64.egg/EGG-INFO/WHEEL b/.eggs/PyWavelets-1.0.0-py3.7-linux-x86_64.egg/EGG-INFO/WHEEL deleted file mode 100644 index 697e4324..00000000 --- a/.eggs/PyWavelets-1.0.0-py3.7-linux-x86_64.egg/EGG-INFO/WHEEL +++ /dev/null @@ -1,5 +0,0 @@ -Wheel-Version: 1.0 -Generator: bdist_wheel (0.31.1) -Root-Is-Purelib: false -Tag: cp37-cp37m-manylinux1_x86_64 - diff --git a/.eggs/PyWavelets-1.0.0-py3.7-linux-x86_64.egg/EGG-INFO/requires.txt b/.eggs/PyWavelets-1.0.0-py3.7-linux-x86_64.egg/EGG-INFO/requires.txt deleted file mode 100644 index 5f73dd4f..00000000 --- a/.eggs/PyWavelets-1.0.0-py3.7-linux-x86_64.egg/EGG-INFO/requires.txt +++ /dev/null @@ -1 +0,0 @@ -numpy>=1.9.1 diff --git a/.eggs/PyWavelets-1.0.0-py3.7-linux-x86_64.egg/EGG-INFO/top_level.txt b/.eggs/PyWavelets-1.0.0-py3.7-linux-x86_64.egg/EGG-INFO/top_level.txt deleted file mode 100644 index ce977543..00000000 --- a/.eggs/PyWavelets-1.0.0-py3.7-linux-x86_64.egg/EGG-INFO/top_level.txt +++ /dev/null @@ -1 +0,0 @@ -pywt diff --git a/.eggs/PyWavelets-1.0.0-py3.7-linux-x86_64.egg/pywt/__init__.py b/.eggs/PyWavelets-1.0.0-py3.7-linux-x86_64.egg/pywt/__init__.py deleted file mode 100644 index 13f196f0..00000000 --- a/.eggs/PyWavelets-1.0.0-py3.7-linux-x86_64.egg/pywt/__init__.py +++ /dev/null @@ -1,45 +0,0 @@ -# flake8: noqa - -# Copyright (c) 2006-2012 Filip Wasilewski -# Copyright (c) 2012-2016 The PyWavelets Developers -# -# See COPYING for license details. - -""" -Discrete forward and inverse wavelet transform, stationary wavelet transform, -wavelet packets signal decomposition and reconstruction module. -""" - -from __future__ import division, print_function, absolute_import -from distutils.version import LooseVersion - -from ._extensions._pywt import * -from ._functions import * -from ._multilevel import * -from ._multidim import * -from ._thresholding import * -from ._wavelet_packets import * -from ._dwt import * -from ._swt import * -from ._cwt import * - -from . import data - -__all__ = [s for s in dir() if not s.startswith('_')] -try: - # In Python 2.x the name of the tempvar leaks out of the list - # comprehension. Delete it to not make it show up in the main namespace. - del s -except NameError: - pass - -from pywt.version import version as __version__ - -import numpy as np -if np.lib.NumpyVersion(np.__version__) >= '1.14.0': - from ._utils import is_nose_running - if is_nose_running(): - np.set_printoptions(legacy='1.13') - -from numpy.testing import Tester -test = Tester().test diff --git a/.eggs/PyWavelets-1.0.0-py3.7-linux-x86_64.egg/pywt/_c99_config.py b/.eggs/PyWavelets-1.0.0-py3.7-linux-x86_64.egg/pywt/_c99_config.py deleted file mode 100644 index a969ba3e..00000000 --- a/.eggs/PyWavelets-1.0.0-py3.7-linux-x86_64.egg/pywt/_c99_config.py +++ /dev/null @@ -1,3 +0,0 @@ -# Autogenerated file containing compile-time definitions - -_have_c99_complex = 1 diff --git a/.eggs/PyWavelets-1.0.0-py3.7-linux-x86_64.egg/pywt/_cwt.py b/.eggs/PyWavelets-1.0.0-py3.7-linux-x86_64.egg/pywt/_cwt.py deleted file mode 100644 index 82d7efd6..00000000 --- a/.eggs/PyWavelets-1.0.0-py3.7-linux-x86_64.egg/pywt/_cwt.py +++ /dev/null @@ -1,107 +0,0 @@ -import numpy as np - -from ._extensions._pywt import (DiscreteContinuousWavelet, ContinuousWavelet, - Wavelet, _check_dtype) -from ._functions import integrate_wavelet, scale2frequency - -__all__ = ["cwt"] - - -def cwt(data, scales, wavelet, sampling_period=1.): - """ - cwt(data, scales, wavelet) - - One dimensional Continuous Wavelet Transform. - - Parameters - ---------- - data : array_like - Input signal - scales : array_like - The wavelet scales to use. One can use - ``f = scale2frequency(scale, wavelet)/sampling_period`` to determine - what physical frequency, ``f``. Here, ``f`` is in hertz when the - ``sampling_period`` is given in seconds. - wavelet : Wavelet object or name - Wavelet to use - sampling_period : float - Sampling period for the frequencies output (optional). - The values computed for ``coefs`` are independent of the choice of - ``sampling_period`` (i.e. ``scales`` is not scaled by the sampling - period). - - Returns - ------- - coefs : array_like - Continuous wavelet transform of the input signal for the given scales - and wavelet - frequencies : array_like - If the unit of sampling period are seconds and given, than frequencies - are in hertz. Otherwise, a sampling period of 1 is assumed. - - Notes - ----- - Size of coefficients arrays depends on the length of the input array and - the length of given scales. - - Examples - -------- - >>> import pywt - >>> import numpy as np - >>> import matplotlib.pyplot as plt - >>> x = np.arange(512) - >>> y = np.sin(2*np.pi*x/32) - >>> coef, freqs=pywt.cwt(y,np.arange(1,129),'gaus1') - >>> plt.matshow(coef) # doctest: +SKIP - >>> plt.show() # doctest: +SKIP - ---------- - >>> import pywt - >>> import numpy as np - >>> import matplotlib.pyplot as plt - >>> t = np.linspace(-1, 1, 200, endpoint=False) - >>> sig = np.cos(2 * np.pi * 7 * t) + np.real(np.exp(-7*(t-0.4)**2)*np.exp(1j*2*np.pi*2*(t-0.4))) - >>> widths = np.arange(1, 31) - >>> cwtmatr, freqs = pywt.cwt(sig, widths, 'mexh') - >>> plt.imshow(cwtmatr, extent=[-1, 1, 1, 31], cmap='PRGn', aspect='auto', - ... vmax=abs(cwtmatr).max(), vmin=-abs(cwtmatr).max()) # doctest: +SKIP - >>> plt.show() # doctest: +SKIP - """ - - # accept array_like input; make a copy to ensure a contiguous array - dt = _check_dtype(data) - data = np.array(data, dtype=dt) - if not isinstance(wavelet, (ContinuousWavelet, Wavelet)): - wavelet = DiscreteContinuousWavelet(wavelet) - if np.isscalar(scales): - scales = np.array([scales]) - if data.ndim == 1: - if wavelet.complex_cwt: - out = np.zeros((np.size(scales), data.size), dtype=complex) - else: - out = np.zeros((np.size(scales), data.size)) - precision = 10 - int_psi, x = integrate_wavelet(wavelet, precision=precision) - for i in np.arange(np.size(scales)): - step = x[1] - x[0] - j = np.floor( - np.arange(scales[i] * (x[-1] - x[0]) + 1) / (scales[i] * step)) - if np.max(j) >= np.size(int_psi): - j = np.delete(j, np.where((j >= np.size(int_psi)))[0]) - coef = - np.sqrt(scales[i]) * np.diff( - np.convolve(data, int_psi[j.astype(np.int)][::-1])) - d = (coef.size - data.size) / 2. - if d > 0: - out[i, :] = coef[int(np.floor(d)):int(-np.ceil(d))] - elif d == 0.: - out[i, :] = coef - else: - raise ValueError( - "Selected scale of {} too small.".format(scales[i])) - frequencies = scale2frequency(wavelet, scales, precision) - if np.isscalar(frequencies): - frequencies = np.array([frequencies]) - for i in np.arange(len(frequencies)): - frequencies[i] /= sampling_period - return out, frequencies - else: - raise ValueError("Only dim == 1 supportet") diff --git a/.eggs/PyWavelets-1.0.0-py3.7-linux-x86_64.egg/pywt/_doc_utils.py b/.eggs/PyWavelets-1.0.0-py3.7-linux-x86_64.egg/pywt/_doc_utils.py deleted file mode 100644 index 9e8ff3ed..00000000 --- a/.eggs/PyWavelets-1.0.0-py3.7-linux-x86_64.egg/pywt/_doc_utils.py +++ /dev/null @@ -1,287 +0,0 @@ -"""Utilities used to generate various figures in the documentation.""" -from itertools import product - -import numpy as np -from matplotlib import pyplot as plt - -__all__ = ['wavedec_keys', 'wavedec2_keys', 'draw_2d_wp_basis', - 'draw_2d_fswavedecn_basis', 'pad', 'boundary_mode_subplot'] - - -def wavedec_keys(level): - """Subband keys corresponding to a wavedec decomposition.""" - approx = '' - coeffs = {} - for lev in range(level): - for k in ['a', 'd']: - coeffs[approx + k] = None - approx = 'a' * (lev + 1) - if lev < level - 1: - coeffs.pop(approx) - return list(coeffs.keys()) - - -def wavedec2_keys(level): - """Subband keys corresponding to a wavedec2 decomposition.""" - approx = '' - coeffs = {} - for lev in range(level): - for k in ['a', 'h', 'v', 'd']: - coeffs[approx + k] = None - approx = 'a' * (lev + 1) - if lev < level - 1: - coeffs.pop(approx) - return list(coeffs.keys()) - - -def _box(bl, ur): - """(x, y) coordinates for the 4 lines making up a rectangular box. - - Parameters - ========== - bl : float - The bottom left corner of the box - ur : float - The upper right corner of the box - - Returns - ======= - coords : 2-tuple - The first and second elements of the tuple are the x and y coordinates - of the box. - """ - xl, xr = bl[0], ur[0] - yb, yt = bl[1], ur[1] - box_x = [xl, xr, - xr, xr, - xr, xl, - xl, xl] - box_y = [yb, yb, - yb, yt, - yt, yt, - yt, yb] - return (box_x, box_y) - - -def _2d_wp_basis_coords(shape, keys): - # Coordinates of the lines to be drawn by draw_2d_wp_basis - coords = [] - centers = {} # retain center of boxes for use in labeling - for key in keys: - offset_x = offset_y = 0 - for n, char in enumerate(key): - if char in ['h', 'd']: - offset_x += shape[0] // 2**(n + 1) - if char in ['v', 'd']: - offset_y += shape[1] // 2**(n + 1) - sx = shape[0] // 2**(n + 1) - sy = shape[1] // 2**(n + 1) - xc, yc = _box((offset_x, -offset_y), - (offset_x + sx, -offset_y - sy)) - coords.append((xc, yc)) - centers[key] = (offset_x + sx // 2, -offset_y - sy // 2) - return coords, centers - - -def draw_2d_wp_basis(shape, keys, fmt='k', plot_kwargs={}, ax=None, - label_levels=0): - """Plot a 2D representation of a WaveletPacket2D basis.""" - coords, centers = _2d_wp_basis_coords(shape, keys) - if ax is None: - fig, ax = plt.subplots(1, 1) - else: - fig = ax.get_figure() - for coord in coords: - ax.plot(coord[0], coord[1], fmt) - ax.set_axis_off() - ax.axis('square') - if label_levels > 0: - for key, c in centers.items(): - if len(key) <= label_levels: - ax.text(c[0], c[1], key, - horizontalalignment='center', - verticalalignment='center') - return fig, ax - - -def _2d_fswavedecn_coords(shape, levels): - coords = [] - centers = {} # retain center of boxes for use in labeling - for key in product(wavedec_keys(levels), repeat=2): - (key0, key1) = key - offsets = [0, 0] - widths = list(shape) - for n0, char in enumerate(key0): - if char in ['d']: - offsets[0] += shape[0] // 2**(n0 + 1) - for n1, char in enumerate(key1): - if char in ['d']: - offsets[1] += shape[1] // 2**(n1 + 1) - widths[0] = shape[0] // 2**(n0 + 1) - widths[1] = shape[1] // 2**(n1 + 1) - xc, yc = _box((offsets[0], -offsets[1]), - (offsets[0] + widths[0], -offsets[1] - widths[1])) - coords.append((xc, yc)) - centers[(key0, key1)] = (offsets[0] + widths[0] / 2, - -offsets[1] - widths[1] / 2) - return coords, centers - - -def draw_2d_fswavedecn_basis(shape, levels, fmt='k', plot_kwargs={}, ax=None, - label_levels=0): - """Plot a 2D representation of a WaveletPacket2D basis.""" - coords, centers = _2d_fswavedecn_coords(shape, levels) - if ax is None: - fig, ax = plt.subplots(1, 1) - else: - fig = ax.get_figure() - for coord in coords: - ax.plot(coord[0], coord[1], fmt) - ax.set_axis_off() - ax.axis('square') - if label_levels > 0: - for key, c in centers.items(): - lev = np.max([len(k) for k in key]) - if lev <= label_levels: - ax.text(c[0], c[1], key, - horizontalalignment='center', - verticalalignment='center') - return fig, ax - - -def pad(x, pad_widths, mode): - """Extend a 1D signal using a given boundary mode. - - Like numpy.pad but supports all PyWavelets boundary modes. - """ - if np.isscalar(pad_widths): - pad_widths = (pad_widths, pad_widths) - - if x.ndim > 1: - raise ValueError("This padding function is only for 1D signals.") - - if mode in ['symmetric', 'reflect']: - xp = np.pad(x, pad_widths, mode=mode) - elif mode in ['periodic', 'periodization']: - if mode == 'periodization' and x.size % 2 == 1: - raise ValueError("periodization expects an even length signal.") - xp = np.pad(x, pad_widths, mode='wrap') - elif mode == 'zeros': - xp = np.pad(x, pad_widths, mode='constant', constant_values=0) - elif mode == 'constant': - xp = np.pad(x, pad_widths, mode='edge') - elif mode == 'smooth': - xp = np.pad(x, pad_widths, mode='linear_ramp', - end_values=(x[0] + pad_widths[0] * (x[0] - x[1]), - x[-1] + pad_widths[1] * (x[-1] - x[-2]))) - elif mode == 'antisymmetric': - # implement by flipping portions symmetric padding - npad_l, npad_r = pad_widths - xp = np.pad(x, pad_widths, mode='symmetric') - r_edge = npad_l + x.size - 1 - l_edge = npad_l - # width of each reflected segment - seg_width = x.size - # flip reflected segments on the right of the original signal - n = 1 - while r_edge <= xp.size: - segment_slice = slice(r_edge + 1, - min(r_edge + 1 + seg_width, xp.size)) - if n % 2: - xp[segment_slice] *= -1 - r_edge += seg_width - n += 1 - - # flip reflected segments on the left of the original signal - n = 1 - while l_edge >= 0: - segment_slice = slice(max(0, l_edge - seg_width), l_edge) - if n % 2: - xp[segment_slice] *= -1 - l_edge -= seg_width - n += 1 - elif mode == 'antireflect': - npad_l, npad_r = pad_widths - # pad with zeros to get final size - xp = np.pad(x, pad_widths, mode='constant', constant_values=0) - - # right and left edge of the original signal within the padded one - r_edge = npad_l + x.size - 1 - l_edge = npad_l - # values of the right and left edge of the original signal - rv1 = x[-1] - lv1 = x[0] - # width of each reflected segment - seg_width = x.size - 1 - - # Generate all reflected segments on the right of the signal. - # odd reflections of the signal involve these coefficients - xr_odd = x[-2::-1] - # even reflections of the signal involve these coefficients - xr_even = x[1:] - n = 1 - while r_edge <= xp.size: - segment_slice = slice(r_edge + 1, - min(r_edge + 1 + seg_width, xp.size)) - orig_sl = slice(segment_slice.stop - segment_slice.start) - rv = xp[r_edge] - if n % 2: - xp[segment_slice] = rv - (xr_odd[orig_sl] - rv1) - else: - xp[segment_slice] = rv + (xr_even[orig_sl] - lv1) - r_edge += seg_width - n += 1 - - # Generate all reflected segments on the left of the signal. - # odd reflections of the signal involve these coefficients - xl_odd = x[-1:0:-1] - # even reflections of the signal involve these coefficients - xl_even = x[:-1] - n = 1 - while l_edge >= 0: - segment_slice = slice(max(0, l_edge - seg_width), l_edge) - orig_sl = slice(segment_slice.start - segment_slice.stop, None) - lv = xp[l_edge] - if n % 2: - xp[segment_slice] = lv - (xl_odd[orig_sl] - lv1) - else: - xp[segment_slice] = lv + (xl_even[orig_sl] - rv1) - l_edge -= seg_width - n += 1 - return xp - - -def boundary_mode_subplot(x, mode, ax, symw=True): - """Plot an illustration of the boundary mode in a subplot axis.""" - - # if odd-length, periodization replicates the last sample to make it even - if mode == 'periodization' and len(x) % 2 == 1: - x = np.concatenate((x, (x[-1], ))) - - npad = 2 * len(x) - t = np.arange(len(x) + 2 * npad) - xp = pad(x, (npad, npad), mode=mode) - - ax.plot(t, xp, 'k.') - ax.set_title(mode) - - # plot the original signal in red - if mode == 'periodization': - ax.plot(t[npad:npad + len(x) - 1], x[:-1], 'r.') - else: - ax.plot(t[npad:npad + len(x)], x, 'r.') - - # add vertical bars indicating points of symmetry or boundary extension - o2 = np.ones(2) - left = npad - if symw: - step = len(x) - 1 - rng = range(-2, 4) - else: - left -= 0.5 - step = len(x) - rng = range(-2, 4) - if mode in ['smooth', 'constant', 'zeros']: - rng = range(0, 2) - for rep in rng: - ax.plot((left + rep * step) * o2, [xp.min() - .5, xp.max() + .5], 'k-') diff --git a/.eggs/PyWavelets-1.0.0-py3.7-linux-x86_64.egg/pywt/_dwt.py b/.eggs/PyWavelets-1.0.0-py3.7-linux-x86_64.egg/pywt/_dwt.py deleted file mode 100644 index a780f7d6..00000000 --- a/.eggs/PyWavelets-1.0.0-py3.7-linux-x86_64.egg/pywt/_dwt.py +++ /dev/null @@ -1,399 +0,0 @@ -from numbers import Number - -import numpy as np - -from ._c99_config import _have_c99_complex -from ._extensions._pywt import Wavelet, Modes, _check_dtype, wavelist -from ._extensions._dwt import (dwt_single, dwt_axis, idwt_single, idwt_axis, - upcoef as _upcoef, downcoef as _downcoef, - dwt_max_level as _dwt_max_level, - dwt_coeff_len as _dwt_coeff_len) -from ._utils import string_types, _as_wavelet - - -__all__ = ["dwt", "idwt", "downcoef", "upcoef", "dwt_max_level", - "dwt_coeff_len"] - - -def dwt_max_level(data_len, filter_len): - r""" - dwt_max_level(data_len, filter_len) - - Compute the maximum useful level of decomposition. - - Parameters - ---------- - data_len : int - Input data length. - filter_len : int, str or Wavelet - The wavelet filter length. Alternatively, the name of a discrete - wavelet or a Wavelet object can be specified. - - Returns - ------- - max_level : int - Maximum level. - - Notes - ----- - The rational for the choice of levels is the maximum level where at least - one coefficient in the output is uncorrupted by edge effects caused by - signal extension. Put another way, decomposition stops when the signal - becomes shorter than the FIR filter length for a given wavelet. This - corresponds to: - - .. max_level = floor(log2(data_len/(filter_len - 1))) - - .. math:: - \mathtt{max\_level} = \left\lfloor\log_2\left(\mathtt{ - \frac{data\_len}{filter\_len - 1}}\right)\right\rfloor - - Examples - -------- - >>> import pywt - >>> w = pywt.Wavelet('sym5') - >>> pywt.dwt_max_level(data_len=1000, filter_len=w.dec_len) - 6 - >>> pywt.dwt_max_level(1000, w) - 6 - >>> pywt.dwt_max_level(1000, 'sym5') - 6 - """ - if isinstance(filter_len, Wavelet): - filter_len = filter_len.dec_len - elif isinstance(filter_len, string_types): - if filter_len in wavelist(kind='discrete'): - filter_len = Wavelet(filter_len).dec_len - else: - raise ValueError( - ("'{}', is not a recognized discrete wavelet. A list of " - "supported wavelet names can be obtained via " - "pywt.wavelist(kind='discrete')").format(filter_len)) - elif not (isinstance(filter_len, Number) and filter_len % 1 == 0): - raise ValueError( - "filter_len must be an integer, discrete Wavelet object, or the " - "name of a discrete wavelet.") - - if filter_len < 2: - raise ValueError("invalid wavelet filter length") - - return _dwt_max_level(data_len, filter_len) - - -def dwt_coeff_len(data_len, filter_len, mode): - """ - dwt_coeff_len(data_len, filter_len, mode='symmetric') - - Returns length of dwt output for given data length, filter length and mode - - Parameters - ---------- - data_len : int - Data length. - filter_len : int - Filter length. - mode : str, optional (default: 'symmetric') - Signal extension mode, see Modes - - Returns - ------- - len : int - Length of dwt output. - - Notes - ----- - For all modes except periodization:: - - len(cA) == len(cD) == floor((len(data) + wavelet.dec_len - 1) / 2) - - for periodization mode ("per"):: - - len(cA) == len(cD) == ceil(len(data) / 2) - - """ - if isinstance(filter_len, Wavelet): - filter_len = filter_len.dec_len - - return _dwt_coeff_len(data_len, filter_len, Modes.from_object(mode)) - - -def dwt(data, wavelet, mode='symmetric', axis=-1): - """ - dwt(data, wavelet, mode='symmetric', axis=-1) - - Single level Discrete Wavelet Transform. - - Parameters - ---------- - data : array_like - Input signal - wavelet : Wavelet object or name - Wavelet to use - mode : str, optional - Signal extension mode, see Modes - axis: int, optional - Axis over which to compute the DWT. If not given, the - last axis is used. - - - Returns - ------- - (cA, cD) : tuple - Approximation and detail coefficients. - - Notes - ----- - Length of coefficients arrays depends on the selected mode. - For all modes except periodization: - - ``len(cA) == len(cD) == floor((len(data) + wavelet.dec_len - 1) / 2)`` - - For periodization mode ("per"): - - ``len(cA) == len(cD) == ceil(len(data) / 2)`` - - Examples - -------- - >>> import pywt - >>> (cA, cD) = pywt.dwt([1, 2, 3, 4, 5, 6], 'db1') - >>> cA - array([ 2.12132034, 4.94974747, 7.77817459]) - >>> cD - array([-0.70710678, -0.70710678, -0.70710678]) - - """ - if not _have_c99_complex and np.iscomplexobj(data): - data = np.asarray(data) - cA_r, cD_r = dwt(data.real, wavelet, mode, axis) - cA_i, cD_i = dwt(data.imag, wavelet, mode, axis) - return (cA_r + 1j*cA_i, cD_r + 1j*cD_i) - - # accept array_like input; make a copy to ensure a contiguous array - dt = _check_dtype(data) - data = np.asarray(data, dtype=dt, order='C') - mode = Modes.from_object(mode) - wavelet = _as_wavelet(wavelet) - - if axis < 0: - axis = axis + data.ndim - if not 0 <= axis < data.ndim: - raise ValueError("Axis greater than data dimensions") - - if data.ndim == 1: - cA, cD = dwt_single(data, wavelet, mode) - # TODO: Check whether this makes a copy - cA, cD = np.asarray(cA, dt), np.asarray(cD, dt) - else: - cA, cD = dwt_axis(data, wavelet, mode, axis=axis) - - return (cA, cD) - - -def idwt(cA, cD, wavelet, mode='symmetric', axis=-1): - """ - idwt(cA, cD, wavelet, mode='symmetric', axis=-1) - - Single level Inverse Discrete Wavelet Transform. - - Parameters - ---------- - cA : array_like or None - Approximation coefficients. If None, will be set to array of zeros - with same shape as `cD`. - cD : array_like or None - Detail coefficients. If None, will be set to array of zeros - with same shape as `cA`. - wavelet : Wavelet object or name - Wavelet to use - mode : str, optional (default: 'symmetric') - Signal extension mode, see Modes - axis: int, optional - Axis over which to compute the inverse DWT. If not given, the - last axis is used. - - - Returns - ------- - rec: array_like - Single level reconstruction of signal from given coefficients. - - Examples - -------- - >>> import pywt - >>> (cA, cD) = pywt.dwt([1,2,3,4,5,6], 'db2', 'smooth') - >>> pywt.idwt(cA, cD, 'db2', 'smooth') - array([ 1., 2., 3., 4., 5., 6.]) - - One of the neat features of `idwt` is that one of the ``cA`` and ``cD`` - arguments can be set to None. In that situation the reconstruction will be - performed using only the other one. Mathematically speaking, this is - equivalent to passing a zero-filled array as one of the arguments. - - >>> (cA, cD) = pywt.dwt([1,2,3,4,5,6], 'db2', 'smooth') - >>> A = pywt.idwt(cA, None, 'db2', 'smooth') - >>> D = pywt.idwt(None, cD, 'db2', 'smooth') - >>> A + D - array([ 1., 2., 3., 4., 5., 6.]) - - """ - # TODO: Lots of possible allocations to eliminate (zeros_like, asarray(rec)) - # accept array_like input; make a copy to ensure a contiguous array - - if cA is None and cD is None: - raise ValueError("At least one coefficient parameter must be " - "specified.") - - # for complex inputs: compute real and imaginary separately then combine - if not _have_c99_complex and (np.iscomplexobj(cA) or np.iscomplexobj(cD)): - if cA is None: - cD = np.asarray(cD) - cA = np.zeros_like(cD) - elif cD is None: - cA = np.asarray(cA) - cD = np.zeros_like(cA) - return (idwt(cA.real, cD.real, wavelet, mode, axis) + - 1j*idwt(cA.imag, cD.imag, wavelet, mode, axis)) - - if cA is not None: - dt = _check_dtype(cA) - cA = np.asarray(cA, dtype=dt, order='C') - if cD is not None: - dt = _check_dtype(cD) - cD = np.asarray(cD, dtype=dt, order='C') - - if cA is not None and cD is not None: - if cA.dtype != cD.dtype: - # need to upcast to common type - cA = cA.astype(np.float64) - cD = cD.astype(np.float64) - elif cA is None: - cA = np.zeros_like(cD) - elif cD is None: - cD = np.zeros_like(cA) - - # cA and cD should be same dimension by here - ndim = cA.ndim - - mode = Modes.from_object(mode) - wavelet = _as_wavelet(wavelet) - - if axis < 0: - axis = axis + ndim - if not 0 <= axis < ndim: - raise ValueError("Axis greater than coefficient dimensions") - - if ndim == 1: - rec = idwt_single(cA, cD, wavelet, mode) - else: - rec = idwt_axis(cA, cD, wavelet, mode, axis=axis) - - return rec - - -def downcoef(part, data, wavelet, mode='symmetric', level=1): - """ - downcoef(part, data, wavelet, mode='symmetric', level=1) - - Partial Discrete Wavelet Transform data decomposition. - - Similar to `pywt.dwt`, but computes only one set of coefficients. - Useful when you need only approximation or only details at the given level. - - Parameters - ---------- - part : str - Coefficients type: - - * 'a' - approximations reconstruction is performed - * 'd' - details reconstruction is performed - - data : array_like - Input signal. - wavelet : Wavelet object or name - Wavelet to use - mode : str, optional - Signal extension mode, see `Modes`. Default is 'symmetric'. - level : int, optional - Decomposition level. Default is 1. - - Returns - ------- - coeffs : ndarray - 1-D array of coefficients. - - See Also - -------- - upcoef - - """ - if not _have_c99_complex and np.iscomplexobj(data): - return (downcoef(part, data.real, wavelet, mode, level) + - 1j*downcoef(part, data.imag, wavelet, mode, level)) - # accept array_like input; make a copy to ensure a contiguous array - dt = _check_dtype(data) - data = np.asarray(data, dtype=dt, order='C') - if data.ndim > 1: - raise ValueError("downcoef only supports 1d data.") - if part not in 'ad': - raise ValueError("Argument 1 must be 'a' or 'd', not '%s'." % part) - mode = Modes.from_object(mode) - wavelet = _as_wavelet(wavelet) - return np.asarray(_downcoef(part == 'a', data, wavelet, mode, level)) - - -def upcoef(part, coeffs, wavelet, level=1, take=0): - """ - upcoef(part, coeffs, wavelet, level=1, take=0) - - Direct reconstruction from coefficients. - - Parameters - ---------- - part : str - Coefficients type: - * 'a' - approximations reconstruction is performed - * 'd' - details reconstruction is performed - coeffs : array_like - Coefficients array to recontruct - wavelet : Wavelet object or name - Wavelet to use - level : int, optional - Multilevel reconstruction level. Default is 1. - take : int, optional - Take central part of length equal to 'take' from the result. - Default is 0. - - Returns - ------- - rec : ndarray - 1-D array with reconstructed data from coefficients. - - See Also - -------- - downcoef - - Examples - -------- - >>> import pywt - >>> data = [1,2,3,4,5,6] - >>> (cA, cD) = pywt.dwt(data, 'db2', 'smooth') - >>> pywt.upcoef('a', cA, 'db2') + pywt.upcoef('d', cD, 'db2') - array([-0.25 , -0.4330127 , 1. , 2. , 3. , - 4. , 5. , 6. , 1.78589838, -1.03108891]) - >>> n = len(data) - >>> pywt.upcoef('a', cA, 'db2', take=n) + pywt.upcoef('d', cD, 'db2', take=n) - array([ 1., 2., 3., 4., 5., 6.]) - - """ - if not _have_c99_complex and np.iscomplexobj(coeffs): - return (upcoef(part, coeffs.real, wavelet, level, take) + - 1j*upcoef(part, coeffs.imag, wavelet, level, take)) - # accept array_like input; make a copy to ensure a contiguous array - dt = _check_dtype(coeffs) - coeffs = np.asarray(coeffs, dtype=dt, order='C') - if coeffs.ndim > 1: - raise ValueError("upcoef only supports 1d coeffs.") - wavelet = _as_wavelet(wavelet) - if part not in 'ad': - raise ValueError("Argument 1 must be 'a' or 'd', not '%s'." % part) - return np.asarray(_upcoef(part == 'a', coeffs, wavelet, level, take)) diff --git a/.eggs/PyWavelets-1.0.0-py3.7-linux-x86_64.egg/pywt/_extensions/_cwt.cpython-37m-x86_64-linux-gnu.so b/.eggs/PyWavelets-1.0.0-py3.7-linux-x86_64.egg/pywt/_extensions/_cwt.cpython-37m-x86_64-linux-gnu.so deleted file mode 100644 index 5683c644..00000000 Binary files a/.eggs/PyWavelets-1.0.0-py3.7-linux-x86_64.egg/pywt/_extensions/_cwt.cpython-37m-x86_64-linux-gnu.so and /dev/null differ diff --git a/.eggs/PyWavelets-1.0.0-py3.7-linux-x86_64.egg/pywt/_extensions/_dwt.cpython-37m-x86_64-linux-gnu.so b/.eggs/PyWavelets-1.0.0-py3.7-linux-x86_64.egg/pywt/_extensions/_dwt.cpython-37m-x86_64-linux-gnu.so deleted file mode 100644 index 261e77fd..00000000 Binary files a/.eggs/PyWavelets-1.0.0-py3.7-linux-x86_64.egg/pywt/_extensions/_dwt.cpython-37m-x86_64-linux-gnu.so and /dev/null differ diff --git a/.eggs/PyWavelets-1.0.0-py3.7-linux-x86_64.egg/pywt/_extensions/_pywt.cpython-37m-x86_64-linux-gnu.so b/.eggs/PyWavelets-1.0.0-py3.7-linux-x86_64.egg/pywt/_extensions/_pywt.cpython-37m-x86_64-linux-gnu.so deleted file mode 100644 index ba141c83..00000000 Binary files a/.eggs/PyWavelets-1.0.0-py3.7-linux-x86_64.egg/pywt/_extensions/_pywt.cpython-37m-x86_64-linux-gnu.so and /dev/null differ diff --git a/.eggs/PyWavelets-1.0.0-py3.7-linux-x86_64.egg/pywt/_extensions/_swt.cpython-37m-x86_64-linux-gnu.so b/.eggs/PyWavelets-1.0.0-py3.7-linux-x86_64.egg/pywt/_extensions/_swt.cpython-37m-x86_64-linux-gnu.so deleted file mode 100644 index b82bcb2b..00000000 Binary files a/.eggs/PyWavelets-1.0.0-py3.7-linux-x86_64.egg/pywt/_extensions/_swt.cpython-37m-x86_64-linux-gnu.so and /dev/null differ diff --git a/.eggs/PyWavelets-1.0.0-py3.7-linux-x86_64.egg/pywt/_functions.py b/.eggs/PyWavelets-1.0.0-py3.7-linux-x86_64.egg/pywt/_functions.py deleted file mode 100644 index 86033967..00000000 --- a/.eggs/PyWavelets-1.0.0-py3.7-linux-x86_64.egg/pywt/_functions.py +++ /dev/null @@ -1,240 +0,0 @@ -# Copyright (c) 2006-2012 Filip Wasilewski -# Copyright (c) 2012-2016 The PyWavelets Developers -# -# See COPYING for license details. - -""" -Other wavelet related functions. -""" - -from __future__ import division, print_function, absolute_import - -import warnings - -import numpy as np -from numpy.fft import fft - -from ._extensions._pywt import DiscreteContinuousWavelet, Wavelet, ContinuousWavelet - - -__all__ = ["integrate_wavelet", "central_frequency", "scale2frequency", "qmf", - "orthogonal_filter_bank", - "intwave", "centrfrq", "scal2frq", "orthfilt"] - - -_DEPRECATION_MSG = ("`{old}` has been renamed to `{new}` and will " - "be removed in a future version of pywt.") - - -def _integrate(arr, step): - integral = np.cumsum(arr) - integral *= step - return integral - - -def intwave(*args, **kwargs): - msg = _DEPRECATION_MSG.format(old='intwave', new='integrate_wavelet') - warnings.warn(msg, DeprecationWarning) - return integrate_wavelet(*args, **kwargs) - - -def centrfrq(*args, **kwargs): - msg = _DEPRECATION_MSG.format(old='centrfrq', new='central_frequency') - warnings.warn(msg, DeprecationWarning) - return central_frequency(*args, **kwargs) - - -def scal2frq(*args, **kwargs): - msg = _DEPRECATION_MSG.format(old='scal2frq', new='scale2frequency') - warnings.warn(msg, DeprecationWarning) - return scale2frequency(*args, **kwargs) - - -def orthfilt(*args, **kwargs): - msg = _DEPRECATION_MSG.format(old='orthfilt', new='orthogonal_filter_bank') - warnings.warn(msg, DeprecationWarning) - return orthogonal_filter_bank(*args, **kwargs) - - -def integrate_wavelet(wavelet, precision=8): - """ - Integrate `psi` wavelet function from -Inf to x using the rectangle - integration method. - - Parameters - ---------- - wavelet : Wavelet instance or str - Wavelet to integrate. If a string, should be the name of a wavelet. - precision : int, optional - Precision that will be used for wavelet function - approximation computed with the wavefun(level=precision) - Wavelet's method (default: 8). - - Returns - ------- - [int_psi, x] : - for orthogonal wavelets - [int_psi_d, int_psi_r, x] : - for other wavelets - - - Examples - -------- - >>> from pywt import Wavelet, integrate_wavelet - >>> wavelet1 = Wavelet('db2') - >>> [int_psi, x] = integrate_wavelet(wavelet1, precision=5) - >>> wavelet2 = Wavelet('bior1.3') - >>> [int_psi_d, int_psi_r, x] = integrate_wavelet(wavelet2, precision=5) - - """ - # FIXME: this function should really use scipy.integrate.quad - - if type(wavelet) in (tuple, list): - msg = ("Integration of a general signal is deprecated " - "and will be removed in a future version of pywt.") - warnings.warn(msg, DeprecationWarning) - elif not isinstance(wavelet, (Wavelet, ContinuousWavelet)): - wavelet = DiscreteContinuousWavelet(wavelet) - - if type(wavelet) in (tuple, list): - psi, x = np.asarray(wavelet[0]), np.asarray(wavelet[1]) - step = x[1] - x[0] - return _integrate(psi, step), x - - functions_approximations = wavelet.wavefun(precision) - - if len(functions_approximations) == 2: # continuous wavelet - psi, x = functions_approximations - step = x[1] - x[0] - return _integrate(psi, step), x - - elif len(functions_approximations) == 3: # orthogonal wavelet - phi, psi, x = functions_approximations - step = x[1] - x[0] - return _integrate(psi, step), x - - else: # biorthogonal wavelet - phi_d, psi_d, phi_r, psi_r, x = functions_approximations - step = x[1] - x[0] - return _integrate(psi_d, step), _integrate(psi_r, step), x - - -def central_frequency(wavelet, precision=8): - """ - Computes the central frequency of the `psi` wavelet function. - - Parameters - ---------- - wavelet : Wavelet instance, str or tuple - Wavelet to integrate. If a string, should be the name of a wavelet. - precision : int, optional - Precision that will be used for wavelet function - approximation computed with the wavefun(level=precision) - Wavelet's method (default: 8). - - Returns - ------- - scalar - - """ - - if not isinstance(wavelet, (Wavelet, ContinuousWavelet)): - wavelet = DiscreteContinuousWavelet(wavelet) - - functions_approximations = wavelet.wavefun(precision) - - if len(functions_approximations) == 2: - psi, x = functions_approximations - else: - # (psi, x) for (phi, psi, x) - # (psi_d, x) for (phi_d, psi_d, phi_r, psi_r, x) - psi, x = functions_approximations[1], functions_approximations[-1] - - domain = float(x[-1] - x[0]) - assert domain > 0 - - index = np.argmax(abs(fft(psi)[1:])) + 2 - if index > len(psi) / 2: - index = len(psi) - index + 2 - - return 1.0 / (domain / (index - 1)) - - -def scale2frequency(wavelet, scale, precision=8): - """ - - Parameters - ---------- - wavelet : Wavelet instance or str - Wavelet to integrate. If a string, should be the name of a wavelet. - scale : scalar - precision : int, optional - Precision that will be used for wavelet function approximation computed - with ``wavelet.wavefun(level=precision)``. Default is 8. - - Returns - ------- - freq : scalar - - """ - return central_frequency(wavelet, precision=precision) / scale - - -def qmf(filt): - """ - Returns the Quadrature Mirror Filter(QMF). - - The magnitude response of QMF is mirror image about `pi/2` of that of the - input filter. - - Parameters - ---------- - filt : array_like - Input filter for which QMF needs to be computed. - - Returns - ------- - qm_filter : ndarray - Quadrature mirror of the input filter. - - """ - qm_filter = np.array(filt)[::-1] - qm_filter[1::2] = -qm_filter[1::2] - return qm_filter - - -def orthogonal_filter_bank(scaling_filter): - """ - Returns the orthogonal filter bank. - - The orthogonal filter bank consists of the HPFs and LPFs at - decomposition and reconstruction stage for the input scaling filter. - - Parameters - ---------- - scaling_filter : array_like - Input scaling filter (father wavelet). - - Returns - ------- - orth_filt_bank : tuple of 4 ndarrays - The orthogonal filter bank of the input scaling filter in the order : - 1] Decomposition LPF - 2] Decomposition HPF - 3] Reconstruction LPF - 4] Reconstruction HPF - - """ - if not (len(scaling_filter) % 2 == 0): - raise ValueError("`scaling_filter` length has to be even.") - - scaling_filter = np.asarray(scaling_filter, dtype=np.float64) - - rec_lo = np.sqrt(2) * scaling_filter / np.sum(scaling_filter) - dec_lo = rec_lo[::-1] - - rec_hi = qmf(rec_lo) - dec_hi = rec_hi[::-1] - - orth_filt_bank = (dec_lo, dec_hi, rec_lo, rec_hi) - return orth_filt_bank diff --git a/.eggs/PyWavelets-1.0.0-py3.7-linux-x86_64.egg/pywt/_multidim.py b/.eggs/PyWavelets-1.0.0-py3.7-linux-x86_64.egg/pywt/_multidim.py deleted file mode 100644 index ae70e499..00000000 --- a/.eggs/PyWavelets-1.0.0-py3.7-linux-x86_64.egg/pywt/_multidim.py +++ /dev/null @@ -1,303 +0,0 @@ -# Copyright (c) 2006-2012 Filip Wasilewski -# Copyright (c) 2012-2016 The PyWavelets Developers -# -# See COPYING for license details. - -""" -2D and nD Discrete Wavelet Transforms and Inverse Discrete Wavelet Transforms. -""" - -from __future__ import division, print_function, absolute_import - -from itertools import product - -import numpy as np - -from ._c99_config import _have_c99_complex -from ._extensions._dwt import dwt_axis, idwt_axis -from ._utils import _wavelets_per_axis, _modes_per_axis - - -__all__ = ['dwt2', 'idwt2', 'dwtn', 'idwtn'] - - -def dwt2(data, wavelet, mode='symmetric', axes=(-2, -1)): - """ - 2D Discrete Wavelet Transform. - - Parameters - ---------- - data : array_like - 2D array with input data - wavelet : Wavelet object or name string, or 2-tuple of wavelets - Wavelet to use. This can also be a tuple containing a wavelet to - apply along each axis in ``axes``. - mode : str or 2-tuple of strings, optional - Signal extension mode, see Modes (default: 'symmetric'). This can - also be a tuple of modes specifying the mode to use on each axis in - ``axes``. - axes : 2-tuple of ints, optional - Axes over which to compute the DWT. Repeated elements mean the DWT will - be performed multiple times along these axes. - - Returns - ------- - (cA, (cH, cV, cD)) : tuple - Approximation, horizontal detail, vertical detail and diagonal - detail coefficients respectively. Horizontal refers to array axis 0 - (or ``axes[0]`` for user-specified ``axes``). - - Examples - -------- - >>> import numpy as np - >>> import pywt - >>> data = np.ones((4,4), dtype=np.float64) - >>> coeffs = pywt.dwt2(data, 'haar') - >>> cA, (cH, cV, cD) = coeffs - >>> cA - array([[ 2., 2.], - [ 2., 2.]]) - >>> cV - array([[ 0., 0.], - [ 0., 0.]]) - - """ - axes = tuple(axes) - data = np.asarray(data) - if len(axes) != 2: - raise ValueError("Expected 2 axes") - if data.ndim < len(np.unique(axes)): - raise ValueError("Input array has fewer dimensions than the specified " - "axes") - - coefs = dwtn(data, wavelet, mode, axes) - return coefs['aa'], (coefs['da'], coefs['ad'], coefs['dd']) - - -def idwt2(coeffs, wavelet, mode='symmetric', axes=(-2, -1)): - """ - 2-D Inverse Discrete Wavelet Transform. - - Reconstructs data from coefficient arrays. - - Parameters - ---------- - coeffs : tuple - (cA, (cH, cV, cD)) A tuple with approximation coefficients and three - details coefficients 2D arrays like from `dwt2`. If any of these - components are set to ``None``, it will be treated as zeros. - wavelet : Wavelet object or name string, or 2-tuple of wavelets - Wavelet to use. This can also be a tuple containing a wavelet to - apply along each axis in ``axes``. - mode : str or 2-tuple of strings, optional - Signal extension mode, see Modes (default: 'symmetric'). This can - also be a tuple of modes specifying the mode to use on each axis in - ``axes``. - axes : 2-tuple of ints, optional - Axes over which to compute the IDWT. Repeated elements mean the IDWT - will be performed multiple times along these axes. - - Examples - -------- - >>> import numpy as np - >>> import pywt - >>> data = np.array([[1,2], [3,4]], dtype=np.float64) - >>> coeffs = pywt.dwt2(data, 'haar') - >>> pywt.idwt2(coeffs, 'haar') - array([[ 1., 2.], - [ 3., 4.]]) - - """ - # L -low-pass data, H - high-pass data - LL, (HL, LH, HH) = coeffs - axes = tuple(axes) - if len(axes) != 2: - raise ValueError("Expected 2 axes") - - coeffs = {'aa': LL, 'da': HL, 'ad': LH, 'dd': HH} - return idwtn(coeffs, wavelet, mode, axes) - - -def dwtn(data, wavelet, mode='symmetric', axes=None): - """ - Single-level n-dimensional Discrete Wavelet Transform. - - Parameters - ---------- - data : array_like - n-dimensional array with input data. - wavelet : Wavelet object or name string, or tuple of wavelets - Wavelet to use. This can also be a tuple containing a wavelet to - apply along each axis in ``axes``. - mode : str or tuple of string, optional - Signal extension mode used in the decomposition, - see Modes (default: 'symmetric'). This can also be a tuple of modes - specifying the mode to use on each axis in ``axes``. - axes : sequence of ints, optional - Axes over which to compute the DWT. Repeated elements mean the DWT will - be performed multiple times along these axes. A value of ``None`` (the - default) selects all axes. - - Axes may be repeated, but information about the original size may be - lost if it is not divisible by ``2 ** nrepeats``. The reconstruction - will be larger, with additional values derived according to the - ``mode`` parameter. ``pywt.wavedecn`` should be used for multilevel - decomposition. - - Returns - ------- - coeffs : dict - Results are arranged in a dictionary, where key specifies - the transform type on each dimension and value is a n-dimensional - coefficients array. - - For example, for a 2D case the result will look something like this:: - - {'aa': # A(LL) - approx. on 1st dim, approx. on 2nd dim - 'ad': # V(LH) - approx. on 1st dim, det. on 2nd dim - 'da': # H(HL) - det. on 1st dim, approx. on 2nd dim - 'dd': # D(HH) - det. on 1st dim, det. on 2nd dim - } - - For user-specified ``axes``, the order of the characters in the - dictionary keys map to the specified ``axes``. - - """ - data = np.asarray(data) - if not _have_c99_complex and np.iscomplexobj(data): - real = dwtn(data.real, wavelet, mode, axes) - imag = dwtn(data.imag, wavelet, mode, axes) - return dict((k, real[k] + 1j * imag[k]) for k in real.keys()) - - if data.dtype == np.dtype('object'): - raise TypeError("Input must be a numeric array-like") - if data.ndim < 1: - raise ValueError("Input data must be at least 1D") - - if axes is None: - axes = range(data.ndim) - axes = [a + data.ndim if a < 0 else a for a in axes] - - modes = _modes_per_axis(mode, axes) - wavelets = _wavelets_per_axis(wavelet, axes) - - coeffs = [('', data)] - for axis, wav, mode in zip(axes, wavelets, modes): - new_coeffs = [] - for subband, x in coeffs: - cA, cD = dwt_axis(x, wav, mode, axis) - new_coeffs.extend([(subband + 'a', cA), - (subband + 'd', cD)]) - coeffs = new_coeffs - return dict(coeffs) - - -def _fix_coeffs(coeffs): - missing_keys = [k for k, v in coeffs.items() if v is None] - if missing_keys: - raise ValueError( - "The following detail coefficients were set to None:\n" - "{0}\n" - "For multilevel transforms, rather than setting\n" - "\tcoeffs[key] = None\n" - "use\n" - "\tcoeffs[key] = np.zeros_like(coeffs[key])\n".format( - missing_keys)) - - invalid_keys = [k for k, v in coeffs.items() if - not set(k) <= set('ad')] - if invalid_keys: - raise ValueError( - "The following invalid keys were found in the detail " - "coefficient dictionary: {}.".format(invalid_keys)) - - key_lengths = [len(k) for k in coeffs.keys()] - if len(np.unique(key_lengths)) > 1: - raise ValueError( - "All detail coefficient names must have equal length.") - - return dict((k, np.asarray(v)) for k, v in coeffs.items()) - - -def idwtn(coeffs, wavelet, mode='symmetric', axes=None): - """ - Single-level n-dimensional Inverse Discrete Wavelet Transform. - - Parameters - ---------- - coeffs: dict - Dictionary as in output of ``dwtn``. Missing or ``None`` items - will be treated as zeros. - wavelet : Wavelet object or name string, or tuple of wavelets - Wavelet to use. This can also be a tuple containing a wavelet to - apply along each axis in ``axes``. - mode : str or list of string, optional - Signal extension mode used in the decomposition, - see Modes (default: 'symmetric'). This can also be a tuple of modes - specifying the mode to use on each axis in ``axes``. - axes : sequence of ints, optional - Axes over which to compute the IDWT. Repeated elements mean the IDWT - will be performed multiple times along these axes. A value of ``None`` - (the default) selects all axes. - - For the most accurate reconstruction, the axes should be provided in - the same order as they were provided to ``dwtn``. - - Returns - ------- - data: ndarray - Original signal reconstructed from input data. - - """ - - # drop the keys corresponding to value = None - coeffs = dict((k, v) for k, v in coeffs.items() if v is not None) - - # Raise error for invalid key combinations - coeffs = _fix_coeffs(coeffs) - - if (not _have_c99_complex and - any(np.iscomplexobj(v) for v in coeffs.values())): - real_coeffs = dict((k, v.real) for k, v in coeffs.items()) - imag_coeffs = dict((k, v.imag) for k, v in coeffs.items()) - return (idwtn(real_coeffs, wavelet, mode, axes) + - 1j * idwtn(imag_coeffs, wavelet, mode, axes)) - - # key length matches the number of axes transformed - ndim_transform = max(len(key) for key in coeffs.keys()) - - try: - coeff_shapes = (v.shape for k, v in coeffs.items() - if v is not None and len(k) == ndim_transform) - coeff_shape = next(coeff_shapes) - except StopIteration: - raise ValueError("`coeffs` must contain at least one non-null wavelet " - "band") - if any(s != coeff_shape for s in coeff_shapes): - raise ValueError("`coeffs` must all be of equal size (or None)") - - if axes is None: - axes = range(ndim_transform) - ndim = ndim_transform - else: - ndim = len(coeff_shape) - axes = [a + ndim if a < 0 else a for a in axes] - - modes = _modes_per_axis(mode, axes) - wavelets = _wavelets_per_axis(wavelet, axes) - for key_length, (axis, wav, mode) in reversed( - list(enumerate(zip(axes, wavelets, modes)))): - if axis < 0 or axis >= ndim: - raise ValueError("Axis greater than data dimensions") - - new_coeffs = {} - new_keys = [''.join(coef) for coef in product('ad', repeat=key_length)] - - for key in new_keys: - L = coeffs.get(key + 'a', None) - H = coeffs.get(key + 'd', None) - - new_coeffs[key] = idwt_axis(L, H, wav, mode, axis) - coeffs = new_coeffs - - return coeffs[''] diff --git a/.eggs/PyWavelets-1.0.0-py3.7-linux-x86_64.egg/pywt/_multilevel.py b/.eggs/PyWavelets-1.0.0-py3.7-linux-x86_64.egg/pywt/_multilevel.py deleted file mode 100644 index c754b3a6..00000000 --- a/.eggs/PyWavelets-1.0.0-py3.7-linux-x86_64.egg/pywt/_multilevel.py +++ /dev/null @@ -1,1513 +0,0 @@ -# Copyright (c) 2006-2012 Filip Wasilewski -# Copyright (c) 2012-2018 The PyWavelets Developers -# -# See COPYING for license details. - -""" -Multilevel 1D and 2D Discrete Wavelet Transform -and Inverse Discrete Wavelet Transform. -""" - -from __future__ import division, print_function, absolute_import - -import numbers -import warnings -from itertools import product -from copy import copy -import numpy as np - -from ._extensions._pywt import Wavelet, Modes -from ._extensions._dwt import dwt_max_level -from ._dwt import dwt, idwt, dwt_coeff_len -from ._multidim import dwt2, idwt2, dwtn, idwtn, _fix_coeffs -from ._utils import _as_wavelet, _wavelets_per_axis, _modes_per_axis - -__all__ = ['wavedec', 'waverec', 'wavedec2', 'waverec2', 'wavedecn', - 'waverecn', 'coeffs_to_array', 'array_to_coeffs', 'ravel_coeffs', - 'unravel_coeffs', 'dwtn_max_level', 'wavedecn_size', - 'wavedecn_shapes', 'fswavedecn', 'fswaverecn', 'FswavedecnResult'] - - -def _check_level(sizes, dec_lens, level): - if np.isscalar(sizes): - sizes = (sizes, ) - if np.isscalar(dec_lens): - dec_lens = (dec_lens, ) - max_level = np.min([dwt_max_level(s, d) for s, d in zip(sizes, dec_lens)]) - if level is None: - level = max_level - elif level < 0: - raise ValueError( - "Level value of %d is too low . Minimum level is 0." % level) - elif level > max_level: - warnings.warn( - ("Level value of {} is too high: all coefficients will experience " - "boundary effects.").format(level)) - return level - - -def wavedec(data, wavelet, mode='symmetric', level=None, axis=-1): - """ - Multilevel 1D Discrete Wavelet Transform of data. - - Parameters - ---------- - data: array_like - Input data - wavelet : Wavelet object or name string - Wavelet to use - mode : str, optional - Signal extension mode, see `Modes` (default: 'symmetric') - level : int, optional - Decomposition level (must be >= 0). If level is None (default) then it - will be calculated using the `dwt_max_level` function. - axis: int, optional - Axis over which to compute the DWT. If not given, the - last axis is used. - - Returns - ------- - [cA_n, cD_n, cD_n-1, ..., cD2, cD1] : list - Ordered list of coefficients arrays - where `n` denotes the level of decomposition. The first element - (`cA_n`) of the result is approximation coefficients array and the - following elements (`cD_n` - `cD_1`) are details coefficients arrays. - - Examples - -------- - >>> from pywt import wavedec - >>> coeffs = wavedec([1,2,3,4,5,6,7,8], 'db1', level=2) - >>> cA2, cD2, cD1 = coeffs - >>> cD1 - array([-0.70710678, -0.70710678, -0.70710678, -0.70710678]) - >>> cD2 - array([-2., -2.]) - >>> cA2 - array([ 5., 13.]) - - """ - data = np.asarray(data) - - wavelet = _as_wavelet(wavelet) - try: - axes_shape = data.shape[axis] - except IndexError: - raise ValueError("Axis greater than data dimensions") - level = _check_level(axes_shape, wavelet.dec_len, level) - - coeffs_list = [] - - a = data - for i in range(level): - a, d = dwt(a, wavelet, mode, axis) - coeffs_list.append(d) - - coeffs_list.append(a) - coeffs_list.reverse() - - return coeffs_list - - -def waverec(coeffs, wavelet, mode='symmetric', axis=-1): - """ - Multilevel 1D Inverse Discrete Wavelet Transform. - - Parameters - ---------- - coeffs : array_like - Coefficients list [cAn, cDn, cDn-1, ..., cD2, cD1] - wavelet : Wavelet object or name string - Wavelet to use - mode : str, optional - Signal extension mode, see `Modes` (default: 'symmetric') - axis: int, optional - Axis over which to compute the inverse DWT. If not given, the - last axis is used. - - Notes - ----- - It may sometimes be desired to run `waverec` with some sets of - coefficients omitted. This can best be done by setting the corresponding - arrays to zero arrays of matching shape and dtype. Explicitly removing - list entries or setting them to None is not supported. - - Specifically, to ignore detail coefficients at level 2, one could do:: - - coeffs[-2] == np.zeros_like(coeffs[-2]) - - Examples - -------- - >>> import pywt - >>> coeffs = pywt.wavedec([1,2,3,4,5,6,7,8], 'db1', level=2) - >>> pywt.waverec(coeffs, 'db1') - array([ 1., 2., 3., 4., 5., 6., 7., 8.]) - """ - - if not isinstance(coeffs, (list, tuple)): - raise ValueError("Expected sequence of coefficient arrays.") - - if len(coeffs) < 1: - raise ValueError( - "Coefficient list too short (minimum 1 arrays required).") - elif len(coeffs) == 1: - # level 0 transform (just returns the approximation coefficients) - return coeffs[0] - - a, ds = coeffs[0], coeffs[1:] - - for d in ds: - if (a is not None) and (d is not None): - try: - if a.shape[axis] == d.shape[axis] + 1: - a = a[tuple(slice(s) for s in d.shape)] - elif a.shape[axis] != d.shape[axis]: - raise ValueError("coefficient shape mismatch") - except IndexError: - raise ValueError("Axis greater than coefficient dimensions") - except AttributeError: - raise AttributeError( - "Wrong coefficient format, if using 'array_to_coeffs' " - "please specify the 'output_format' parameter") - a = idwt(a, d, wavelet, mode, axis) - - return a - - -def wavedec2(data, wavelet, mode='symmetric', level=None, axes=(-2, -1)): - """ - Multilevel 2D Discrete Wavelet Transform. - - Parameters - ---------- - data : ndarray - 2D input data - wavelet : Wavelet object or name string, or 2-tuple of wavelets - Wavelet to use. This can also be a tuple containing a wavelet to - apply along each axis in `axes`. - mode : str or 2-tuple of str, optional - Signal extension mode, see `Modes` (default: 'symmetric'). This can - also be a tuple containing a mode to apply along each axis in `axes`. - level : int, optional - Decomposition level (must be >= 0). If level is None (default) then it - will be calculated using the `dwt_max_level` function. - axes : 2-tuple of ints, optional - Axes over which to compute the DWT. Repeated elements are not allowed. - - Returns - ------- - [cAn, (cHn, cVn, cDn), ... (cH1, cV1, cD1)] : list - Coefficients list. For user-specified `axes`, `cH*` - corresponds to ``axes[0]`` while `cV*` corresponds to ``axes[1]``. - The first element returned is the approximation coefficients for the - nth level of decomposition. Remaining elements are tuples of detail - coefficients in descending order of decomposition level. - (i.e. `cH1` are the horizontal detail coefficients at the first level) - - Examples - -------- - >>> import pywt - >>> import numpy as np - >>> coeffs = pywt.wavedec2(np.ones((4,4)), 'db1') - >>> # Levels: - >>> len(coeffs)-1 - 2 - >>> pywt.waverec2(coeffs, 'db1') - array([[ 1., 1., 1., 1.], - [ 1., 1., 1., 1.], - [ 1., 1., 1., 1.], - [ 1., 1., 1., 1.]]) - """ - data = np.asarray(data) - if data.ndim < 2: - raise ValueError("Expected input data to have at least 2 dimensions.") - - axes = tuple(axes) - if len(axes) != 2: - raise ValueError("Expected 2 axes") - if len(axes) != len(set(axes)): - raise ValueError("The axes passed to wavedec2 must be unique.") - try: - axes_sizes = [data.shape[ax] for ax in axes] - except IndexError: - raise ValueError("Axis greater than data dimensions") - - wavelets = _wavelets_per_axis(wavelet, axes) - dec_lengths = [w.dec_len for w in wavelets] - - level = _check_level(axes_sizes, dec_lengths, level) - - coeffs_list = [] - - a = data - for i in range(level): - a, ds = dwt2(a, wavelet, mode, axes) - coeffs_list.append(ds) - - coeffs_list.append(a) - coeffs_list.reverse() - - return coeffs_list - - -def waverec2(coeffs, wavelet, mode='symmetric', axes=(-2, -1)): - """ - Multilevel 2D Inverse Discrete Wavelet Transform. - - coeffs : list or tuple - Coefficients list [cAn, (cHn, cVn, cDn), ... (cH1, cV1, cD1)] - wavelet : Wavelet object or name string, or 2-tuple of wavelets - Wavelet to use. This can also be a tuple containing a wavelet to - apply along each axis in `axes`. - mode : str or 2-tuple of str, optional - Signal extension mode, see `Modes` (default: 'symmetric'). This can - also be a tuple containing a mode to apply along each axis in `axes`. - axes : 2-tuple of ints, optional - Axes over which to compute the IDWT. Repeated elements are not allowed. - - Returns - ------- - 2D array of reconstructed data. - - Notes - ----- - It may sometimes be desired to run `waverec2` with some sets of - coefficients omitted. This can best be done by setting the corresponding - arrays to zero arrays of matching shape and dtype. Explicitly removing - list or tuple entries or setting them to None is not supported. - - Specifically, to ignore all detail coefficients at level 2, one could do:: - - coeffs[-2] == tuple([np.zeros_like(v) for v in coeffs[-2]]) - - Examples - -------- - >>> import pywt - >>> import numpy as np - >>> coeffs = pywt.wavedec2(np.ones((4,4)), 'db1') - >>> # Levels: - >>> len(coeffs)-1 - 2 - >>> pywt.waverec2(coeffs, 'db1') - array([[ 1., 1., 1., 1.], - [ 1., 1., 1., 1.], - [ 1., 1., 1., 1.], - [ 1., 1., 1., 1.]]) - """ - if not isinstance(coeffs, (list, tuple)): - raise ValueError("Expected sequence of coefficient arrays.") - - if len(axes) != len(set(axes)): - raise ValueError("The axes passed to waverec2 must be unique.") - - if len(coeffs) < 1: - raise ValueError( - "Coefficient list too short (minimum 1 array required).") - elif len(coeffs) == 1: - # level 0 transform (just returns the approximation coefficients) - return coeffs[0] - - a, ds = coeffs[0], coeffs[1:] - a = np.asarray(a) - - for d in ds: - d = tuple(np.asarray(coeff) if coeff is not None else None - for coeff in d) - d_shapes = (coeff.shape for coeff in d if coeff is not None) - try: - d_shape = next(d_shapes) - except StopIteration: - idxs = slice(None), slice(None) - else: - if not all(s == d_shape for s in d_shapes): - raise ValueError("All detail shapes must be the same length.") - idxs = tuple(slice(None, -1 if a_len == d_len + 1 else None) - for a_len, d_len in zip(a.shape, d_shape)) - a = idwt2((a[idxs], d), wavelet, mode, axes) - - return a - - -def _prep_axes_wavedecn(shape, axes): - if len(shape) < 1: - raise ValueError("Expected at least 1D input data.") - ndim = len(shape) - if np.isscalar(axes): - axes = (axes, ) - if axes is None: - axes = range(ndim) - else: - axes = tuple(axes) - if len(axes) != len(set(axes)): - raise ValueError("The axes passed to wavedecn must be unique.") - try: - axes_shapes = [shape[ax] for ax in axes] - except IndexError: - raise ValueError("Axis greater than data dimensions") - ndim_transform = len(axes) - return axes, axes_shapes, ndim_transform - - -def wavedecn(data, wavelet, mode='symmetric', level=None, axes=None): - """ - Multilevel nD Discrete Wavelet Transform. - - Parameters - ---------- - data : ndarray - nD input data - wavelet : Wavelet object or name string, or tuple of wavelets - Wavelet to use. This can also be a tuple containing a wavelet to - apply along each axis in `axes`. - mode : str or tuple of str, optional - Signal extension mode, see `Modes` (default: 'symmetric'). This can - also be a tuple containing a mode to apply along each axis in `axes`. - level : int, optional - Decomposition level (must be >= 0). If level is None (default) then it - will be calculated using the `dwt_max_level` function. - axes : sequence of ints, optional - Axes over which to compute the DWT. Axes may not be repeated. The - default is None, which means transform all axes - (``axes = range(data.ndim)``). - - Returns - ------- - [cAn, {details_level_n}, ... {details_level_1}] : list - Coefficients list. Coefficients are listed in descending order of - decomposition level. `cAn` are the approximation coefficients at - level `n`. Each `details_level_i` element is a dictionary - containing detail coefficients at level `i` of the decomposition. As - a concrete example, a 3D decomposition would have the following set of - keys in each `details_level_i` dictionary:: - - {'aad', 'ada', 'daa', 'add', 'dad', 'dda', 'ddd'} - - where the order of the characters in each key map to the specified - `axes`. - - Examples - -------- - >>> import numpy as np - >>> from pywt import wavedecn, waverecn - >>> coeffs = wavedecn(np.ones((4, 4, 4)), 'db1') - >>> # Levels: - >>> len(coeffs)-1 - 2 - >>> waverecn(coeffs, 'db1') # doctest: +NORMALIZE_WHITESPACE - array([[[ 1., 1., 1., 1.], - [ 1., 1., 1., 1.], - [ 1., 1., 1., 1.], - [ 1., 1., 1., 1.]], - [[ 1., 1., 1., 1.], - [ 1., 1., 1., 1.], - [ 1., 1., 1., 1.], - [ 1., 1., 1., 1.]], - [[ 1., 1., 1., 1.], - [ 1., 1., 1., 1.], - [ 1., 1., 1., 1.], - [ 1., 1., 1., 1.]], - [[ 1., 1., 1., 1.], - [ 1., 1., 1., 1.], - [ 1., 1., 1., 1.], - [ 1., 1., 1., 1.]]]) - - """ - data = np.asarray(data) - axes, axes_shapes, ndim_transform = _prep_axes_wavedecn(data.shape, axes) - wavelets = _wavelets_per_axis(wavelet, axes) - dec_lengths = [w.dec_len for w in wavelets] - - level = _check_level(axes_shapes, dec_lengths, level) - - coeffs_list = [] - - a = data - for i in range(level): - coeffs = dwtn(a, wavelet, mode, axes) - a = coeffs.pop('a' * ndim_transform) - coeffs_list.append(coeffs) - - coeffs_list.append(a) - coeffs_list.reverse() - - return coeffs_list - - -def _match_coeff_dims(a_coeff, d_coeff_dict): - # For each axis, compare the approximation coeff shape to one of the - # stored detail coeffs and truncate the last element along the axis - # if necessary. - if a_coeff is None: - return None - if not d_coeff_dict: - return a_coeff - d_coeff = d_coeff_dict[next(iter(d_coeff_dict))] - size_diffs = np.subtract(a_coeff.shape, d_coeff.shape) - if np.any((size_diffs < 0) | (size_diffs > 1)): - print(size_diffs) - raise ValueError("incompatible coefficient array sizes") - return a_coeff[tuple(slice(s) for s in d_coeff.shape)] - - -def waverecn(coeffs, wavelet, mode='symmetric', axes=None): - """ - Multilevel nD Inverse Discrete Wavelet Transform. - - coeffs : array_like - Coefficients list [cAn, {details_level_n}, ... {details_level_1}] - wavelet : Wavelet object or name string, or tuple of wavelets - Wavelet to use. This can also be a tuple containing a wavelet to - apply along each axis in `axes`. - mode : str or tuple of str, optional - Signal extension mode, see `Modes` (default: 'symmetric'). This can - also be a tuple containing a mode to apply along each axis in `axes`. - axes : sequence of ints, optional - Axes over which to compute the IDWT. Axes may not be repeated. - - Returns - ------- - nD array of reconstructed data. - - Notes - ----- - It may sometimes be desired to run `waverecn` with some sets of - coefficients omitted. This can best be done by setting the corresponding - arrays to zero arrays of matching shape and dtype. Explicitly removing - list or dictionary entries or setting them to None is not supported. - - Specifically, to ignore all detail coefficients at level 2, one could do:: - - coeffs[-2] = {k: np.zeros_like(v) for k, v in coeffs[-2].items()} - - Examples - -------- - >>> import numpy as np - >>> from pywt import wavedecn, waverecn - >>> coeffs = wavedecn(np.ones((4, 4, 4)), 'db1') - >>> # Levels: - >>> len(coeffs)-1 - 2 - >>> waverecn(coeffs, 'db1') # doctest: +NORMALIZE_WHITESPACE - array([[[ 1., 1., 1., 1.], - [ 1., 1., 1., 1.], - [ 1., 1., 1., 1.], - [ 1., 1., 1., 1.]], - [[ 1., 1., 1., 1.], - [ 1., 1., 1., 1.], - [ 1., 1., 1., 1.], - [ 1., 1., 1., 1.]], - [[ 1., 1., 1., 1.], - [ 1., 1., 1., 1.], - [ 1., 1., 1., 1.], - [ 1., 1., 1., 1.]], - [[ 1., 1., 1., 1.], - [ 1., 1., 1., 1.], - [ 1., 1., 1., 1.], - [ 1., 1., 1., 1.]]]) - - """ - if len(coeffs) < 1: - raise ValueError( - "Coefficient list too short (minimum 1 array required).") - - a, ds = coeffs[0], coeffs[1:] - - # Raise error for invalid key combinations - ds = list(map(_fix_coeffs, ds)) - - if not ds: - # level 0 transform (just returns the approximation coefficients) - return coeffs[0] - if a is None and not any(ds): - raise ValueError( - "At least one coefficient must contain a valid value.") - - coeff_ndims = [] - if a is not None: - a = np.asarray(a) - coeff_ndims.append(a.ndim) - for d in ds: - coeff_ndims += [v.ndim for k, v in d.items()] - - # test that all coefficients have a matching number of dimensions - unique_coeff_ndims = np.unique(coeff_ndims) - if len(unique_coeff_ndims) == 1: - ndim = unique_coeff_ndims[0] - else: - raise ValueError( - "All coefficients must have a matching number of dimensions") - - if np.isscalar(axes): - axes = (axes, ) - if axes is None: - axes = range(ndim) - else: - axes = tuple(axes) - if len(axes) != len(set(axes)): - raise ValueError("The axes passed to waverecn must be unique.") - ndim_transform = len(axes) - - for idx, d in enumerate(ds): - if a is None and not d: - continue - # The following if statement handles the case where the approximation - # coefficient returned at the previous level may exceed the size of the - # stored detail coefficients by 1 on any given axis. - if idx > 0: - a = _match_coeff_dims(a, d) - d['a' * ndim_transform] = a - a = idwtn(d, wavelet, mode, axes) - - return a - - -def _coeffs_wavedec_to_wavedecn(coeffs): - """Convert wavedec coefficients to the wavedecn format.""" - if len(coeffs) == 0: - return coeffs - coeffs = copy(coeffs) - for n in range(1, len(coeffs)): - if coeffs[n] is None: - continue - if coeffs[n].ndim != 1: - raise ValueError("expected a 1D coefficient array") - coeffs[n] = dict(d=coeffs[n]) - return coeffs - - -def _coeffs_wavedec2_to_wavedecn(coeffs): - """Convert wavedec2 coefficients to the wavedecn format.""" - if len(coeffs) == 0: - return coeffs - coeffs = copy(coeffs) - for n in range(1, len(coeffs)): - if not isinstance(coeffs[n], (tuple, list)) or len(coeffs[n]) != 3: - raise ValueError("expected a 3-tuple of detail coefficients") - (da, ad, dd) = coeffs[n] - if da is None or ad is None or dd is None: - raise ValueError( - "Expected numpy arrays of detail coefficients. Setting " - "coefficients to None is not supported.") - coeffs[n] = dict(ad=ad, da=da, dd=dd) - return coeffs - - -def _determine_coeff_array_shape(coeffs, axes): - arr_shape = np.asarray(coeffs[0].shape) - axes = np.asarray(axes) # axes that were transformed - ndim_transform = len(axes) - ncoeffs = coeffs[0].size - for d in coeffs[1:]: - arr_shape[axes] += np.asarray(d['d'*ndim_transform].shape)[axes] - for k, v in d.items(): - ncoeffs += v.size - arr_shape = tuple(arr_shape.tolist()) - # if the total number of coefficients doesn't equal the size of the array - # then tight packing is not possible. - is_tight_packing = (np.prod(arr_shape) == ncoeffs) - return arr_shape, is_tight_packing - - -def _prepare_coeffs_axes(coeffs, axes): - """Helper function to check type of coeffs and axes. - - This code is used by both coeffs_to_array and ravel_coeffs. - """ - if not isinstance(coeffs, list) or len(coeffs) == 0: - raise ValueError("input must be a list of coefficients from wavedecn") - if coeffs[0] is None: - raise ValueError("coeffs_to_array does not support missing " - "coefficients.") - if not isinstance(coeffs[0], np.ndarray): - raise ValueError("first list element must be a numpy array") - ndim = coeffs[0].ndim - - if len(coeffs) > 1: - # convert wavedec or wavedec2 format coefficients to waverecn format - if isinstance(coeffs[1], dict): - pass - elif isinstance(coeffs[1], np.ndarray): - coeffs = _coeffs_wavedec_to_wavedecn(coeffs) - elif isinstance(coeffs[1], (tuple, list)): - coeffs = _coeffs_wavedec2_to_wavedecn(coeffs) - else: - raise ValueError("invalid coefficient list") - - if len(coeffs) == 1: - # no detail coefficients were found - return coeffs, axes, ndim, None - - # Determine the number of dimensions that were transformed via key length - ndim_transform = len(list(coeffs[1].keys())[0]) - if axes is None: - if ndim_transform < ndim: - raise ValueError( - "coeffs corresponds to a DWT performed over only a subset of " - "the axes. In this case, axes must be specified.") - axes = np.arange(ndim) - - if len(axes) != ndim_transform: - raise ValueError( - "The length of axes doesn't match the number of dimensions " - "transformed.") - - return coeffs, axes, ndim, ndim_transform - - -def coeffs_to_array(coeffs, padding=0, axes=None): - """ - Arrange a wavelet coefficient list from `wavedecn` into a single array. - - Parameters - ---------- - - coeffs : array-like - dictionary of wavelet coefficients as returned by pywt.wavedecn - padding : float or None, optional - If None, raise an error if the coefficients cannot be tightly packed. - axes : sequence of ints, optional - Axes over which the DWT that created `coeffs` was performed. The - default value of None corresponds to all axes. - - Returns - ------- - coeff_arr : array-like - Wavelet transform coefficient array. - coeff_slices : list - List of slices corresponding to each coefficient. As a 2D example, - `coeff_arr[coeff_slices[1]['dd']]` would extract the first level detail - coefficients from `coeff_arr`. - - See Also - -------- - array_to_coeffs : the inverse of coeffs_to_array - - Notes - ----- - Assume a 2D coefficient dictionary, c, from a two-level transform. - - Then all 2D coefficients will be stacked into a single larger 2D array - as follows:: - - +---------------+---------------+-------------------------------+ - | | | | - | c[0] | c[1]['da'] | | - | | | | - +---------------+---------------+ c[2]['da'] | - | | | | - | c[1]['ad'] | c[1]['dd'] | | - | | | | - +---------------+---------------+ ------------------------------+ - | | | - | | | - | | | - | c[2]['ad'] | c[2]['dd'] | - | | | - | | | - | | | - +-------------------------------+-------------------------------+ - - Examples - -------- - >>> import pywt - >>> cam = pywt.data.camera() - >>> coeffs = pywt.wavedecn(cam, wavelet='db2', level=3) - >>> arr, coeff_slices = pywt.coeffs_to_array(coeffs) - - """ - - coeffs, axes, ndim, ndim_transform = _prepare_coeffs_axes(coeffs, axes) - - # initialize with the approximation coefficients. - a_coeffs = coeffs[0] - a_shape = a_coeffs.shape - - if len(coeffs) == 1: - # only a single approximation coefficient array was found - return a_coeffs, [tuple([slice(None)] * ndim)] - - # determine size of output and if tight packing is possible - arr_shape, is_tight_packing = _determine_coeff_array_shape(coeffs, axes) - - # preallocate output array - if padding is None: - if not is_tight_packing: - raise ValueError("array coefficients cannot be tightly packed") - coeff_arr = np.empty(arr_shape, dtype=a_coeffs.dtype) - else: - coeff_arr = np.full(arr_shape, padding, dtype=a_coeffs.dtype) - - a_slices = tuple([slice(s) for s in a_shape]) - coeff_arr[a_slices] = a_coeffs - - # initialize list of coefficient slices - coeff_slices = [] - coeff_slices.append(a_slices) - - # loop over the detail cofficients, adding them to coeff_arr - ds = coeffs[1:] - for coeff_dict in ds: - coeff_slices.append({}) # new dictionary for detail coefficients - if np.any([d is None for d in coeff_dict.values()]): - raise ValueError("coeffs_to_array does not support missing " - "coefficients.") - d_shape = coeff_dict['d' * ndim_transform].shape - for key in coeff_dict.keys(): - d = coeff_dict[key] - slice_array = [slice(None), ] * ndim - for i, let in enumerate(key): - ax_i = axes[i] # axis corresponding to this transform index - if let == 'a': - slice_array[ax_i] = slice(d.shape[ax_i]) - elif let == 'd': - slice_array[ax_i] = slice(a_shape[ax_i], - a_shape[ax_i] + d.shape[ax_i]) - else: - raise ValueError("unexpected letter: {}".format(let)) - slice_array = tuple(slice_array) - coeff_arr[slice_array] = d - coeff_slices[-1][key] = slice_array - a_shape = [a_shape[n] + d_shape[n] for n in range(ndim)] - return coeff_arr, coeff_slices - - -def array_to_coeffs(arr, coeff_slices, output_format='wavedecn'): - """ - Convert a combined array of coefficients back to a list compatible with - `waverecn`. - - Parameters - ---------- - - arr : array-like - An array containing all wavelet coefficients. This should have been - generated via `coeffs_to_array`. - coeff_slices : list of tuples - List of slices corresponding to each coefficient as obtained from - `array_to_coeffs`. - output_format : {'wavedec', 'wavedec2', 'wavedecn'} - Make the form of the coefficients compatible with this type of - multilevel transform. - - Returns - ------- - coeffs: array-like - Wavelet transform coefficient array. - - See Also - -------- - coeffs_to_array : the inverse of array_to_coeffs - - Notes - ----- - A single large array containing all coefficients will have subsets stored, - into a `waverecn` list, c, as indicated below:: - - +---------------+---------------+-------------------------------+ - | | | | - | c[0] | c[1]['da'] | | - | | | | - +---------------+---------------+ c[2]['da'] | - | | | | - | c[1]['ad'] | c[1]['dd'] | | - | | | | - +---------------+---------------+ ------------------------------+ - | | | - | | | - | | | - | c[2]['ad'] | c[2]['dd'] | - | | | - | | | - | | | - +-------------------------------+-------------------------------+ - - Examples - -------- - >>> import pywt - >>> from numpy.testing import assert_array_almost_equal - >>> cam = pywt.data.camera() - >>> coeffs = pywt.wavedecn(cam, wavelet='db2', level=3) - >>> arr, coeff_slices = pywt.coeffs_to_array(coeffs) - >>> coeffs_from_arr = pywt.array_to_coeffs(arr, coeff_slices) - >>> cam_recon = pywt.waverecn(coeffs_from_arr, wavelet='db2') - >>> assert_array_almost_equal(cam, cam_recon) - - """ - arr = np.asarray(arr) - coeffs = [] - if len(coeff_slices) == 0: - raise ValueError("empty list of coefficient slices") - else: - coeffs.append(arr[coeff_slices[0]]) - - # difference coefficients at each level - for n in range(1, len(coeff_slices)): - if output_format == 'wavedec': - d = arr[coeff_slices[n]['d']] - elif output_format == 'wavedec2': - d = (arr[coeff_slices[n]['da']], - arr[coeff_slices[n]['ad']], - arr[coeff_slices[n]['dd']]) - elif output_format == 'wavedecn': - d = {} - for k, v in coeff_slices[n].items(): - d[k] = arr[v] - else: - raise ValueError( - "Unrecognized output format: {}".format(output_format)) - coeffs.append(d) - return coeffs - - -def wavedecn_shapes(shape, wavelet, mode='symmetric', level=None, axes=None): - """Subband shapes for a multilevel nD discrete wavelet transform. - - Parameters - ---------- - shape : sequence of ints - The shape of the data to be transformed. - wavelet : Wavelet object or name string, or tuple of wavelets - Wavelet to use. This can also be a tuple containing a wavelet to - apply along each axis in `axes`. - mode : str or tuple of str, optional - Signal extension mode, see Modes (default: 'symmetric'). This can - also be a tuple containing a mode to apply along each axis in `axes`. - level : int, optional - Decomposition level (must be >= 0). If level is None (default) then it - will be calculated using the `dwt_max_level` function. - axes : sequence of ints, optional - Axes over which to compute the DWT. Axes may not be repeated. The - default is None, which means transform all axes - (``axes = range(data.ndim)``). - - Returns - ------- - shapes : [cAn, {details_level_n}, ... {details_level_1}] : list - Coefficients shape list. Mirrors the output of `wavedecn`, except - it contains only the shapes of the coefficient arrays rather than the - arrays themselves. - - Examples - -------- - >>> import pywt - >>> pywt.wavedecn_shapes((64, 32), wavelet='db2', level=3, axes=(0, )) - [(10, 32), {'d': (10, 32)}, {'d': (18, 32)}, {'d': (33, 32)}] - """ - axes, axes_shapes, ndim_transform = _prep_axes_wavedecn(shape, axes) - wavelets = _wavelets_per_axis(wavelet, axes) - modes = _modes_per_axis(mode, axes) - dec_lengths = [w.dec_len for w in wavelets] - - level = _check_level(min(axes_shapes), max(dec_lengths), level) - - shapes = [] - for i in range(level): - detail_keys = [''.join(c) for c in product('ad', repeat=len(axes))] - new_shapes = {k: list(shape) for k in detail_keys} - for axis, wav, mode in zip(axes, wavelets, modes): - s = dwt_coeff_len(shape[axis], filter_len=wav.dec_len, mode=mode) - for k in detail_keys: - new_shapes[k][axis] = s - for k, v in new_shapes.items(): - new_shapes[k] = tuple(v) - shapes.append(new_shapes) - shape = new_shapes.pop('a' * ndim_transform) - shapes.append(shape) - shapes.reverse() - return shapes - - -def wavedecn_size(shapes): - """Compute the total number of wavedecn coefficients. - - Parameters - ---------- - shapes : list of coefficient shapes - A set of coefficient shapes as returned by `wavedecn_shapes`. - Alternatively, the user can specify a set of coefficients as returned - by `wavedecn`. - - Returns - ------- - size : int - The total number of coefficients. - - Examples - -------- - >>> import pywt - >>> data_shape = (64, 32) - >>> shapes = pywt.wavedecn_shapes(data_shape, 'db2', mode='periodization') - >>> pywt.wavedecn_size(shapes) - 2048 - >>> coeffs = pywt.wavedecn(np.ones(data_shape), 'sym4', mode='symmetric') - >>> pywt.wavedecn_size(coeffs) - 3087 - """ - def _size(x): - """Size corresponding to `x` as either a shape tuple or an ndarray.""" - if isinstance(x, np.ndarray): - return x.size - else: - return np.prod(x) - ncoeffs = _size(shapes[0]) - for d in shapes[1:]: - for k, v in d.items(): - if v is None: - raise ValueError( - "Setting coefficient arrays to None is not supported.") - ncoeffs += _size(v) - return ncoeffs - - -def dwtn_max_level(shape, wavelet, axes=None): - """Compute the maximum level of decomposition for n-dimensional data. - - This returns the maximum number of levels of decomposition suitable for use - with `wavedec`, `wavedec2` or `wavedecn`. - - Parameters - ---------- - shape : sequence of ints - Input data shape. - wavelet : Wavelet object or name string, or tuple of wavelets - Wavelet to use. This can also be a tuple containing a wavelet to - apply along each axis in `axes`. - axes : sequence of ints, optional - Axes over which to compute the DWT. Axes may not be repeated. - - Returns - ------- - level : int - Maximum level. - - Notes - ----- - The level returned is the smallest `dwt_max_level` over all axes. - - Examples - -------- - >>> import pywt - >>> pywt.dwtn_max_level((64, 32), 'db2') - 3 - """ - # Determine the axes and shape for the transform - axes, axes_shapes, ndim_transform = _prep_axes_wavedecn(shape, axes) - - # initialize a Wavelet object per (transformed) axis - wavelets = _wavelets_per_axis(wavelet, axes) - - # maximum level of decomposition per axis - max_levels = [dwt_max_level(n, wav.dec_len) - for n, wav in zip(axes_shapes, wavelets)] - return min(max_levels) - - -def ravel_coeffs(coeffs, axes=None): - """Ravel a set of multilevel wavelet coefficients into a single 1D array. - - Parameters - ---------- - coeffs : array-like - A list of multilevel wavelet coefficients as returned by - `wavedec`, `wavedec2` or `wavedecn`. - axes : sequence of ints, optional - Axes over which the DWT that created `coeffs` was performed. The - default value of None corresponds to all axes. - - Returns - ------- - coeff_arr : array-like - Wavelet transform coefficient array. All coefficients have been - concatenated into a single array. - coeff_slices : list - List of slices corresponding to each coefficient. As a 2D example, - ``coeff_arr[coeff_slices[1]['dd']]`` would extract the first level - detail coefficients from `coeff_arr`. - coeff_shapes : list - List of shapes corresponding to each coefficient. For example, in 2D, - ``coeff_shapes[1]['dd']`` would contain the original shape of the first - level detail coefficients array. - - See Also - -------- - unravel_coeffs : the inverse of ravel_coeffs - - Examples - -------- - >>> import pywt - >>> cam = pywt.data.camera() - >>> coeffs = pywt.wavedecn(cam, wavelet='db2', level=3) - >>> arr, coeff_slices, coeff_shapes = pywt.ravel_coeffs(coeffs) - - """ - coeffs, axes, ndim, ndim_transform = _prepare_coeffs_axes(coeffs, axes) - - # initialize with the approximation coefficients. - a_coeffs = coeffs[0] - a_size = a_coeffs.size - - if len(coeffs) == 1: - # only a single approximation coefficient array was found - return a_coeffs.ravel(), [slice(a_size), ], [a_coeffs.shape, ] - - # preallocate output array - arr_size = wavedecn_size(coeffs) - coeff_arr = np.empty((arr_size, ), dtype=a_coeffs.dtype) - - a_slice = slice(a_size) - coeff_arr[a_slice] = a_coeffs.ravel() - - # initialize list of coefficient slices - coeff_slices = [] - coeff_shapes = [] - coeff_slices.append(a_slice) - coeff_shapes.append(coeffs[0].shape) - - # loop over the detail cofficients, embedding them in coeff_arr - ds = coeffs[1:] - offset = a_size - for coeff_dict in ds: - # new dictionaries for detail coefficient slices and shapes - coeff_slices.append({}) - coeff_shapes.append({}) - if np.any([d is None for d in coeff_dict.values()]): - raise ValueError("coeffs_to_array does not support missing " - "coefficients.") - for key, d in coeff_dict.items(): - sl = slice(offset, offset + d.size) - offset += d.size - coeff_arr[sl] = d.ravel() - coeff_slices[-1][key] = sl - coeff_shapes[-1][key] = d.shape - return coeff_arr, coeff_slices, coeff_shapes - - -def unravel_coeffs(arr, coeff_slices, coeff_shapes, output_format='wavedecn'): - """Unravel a raveled array of multilevel wavelet coefficients. - - Parameters - ---------- - arr : array-like - An array containing all wavelet coefficients. This should have been - generated by applying `ravel_coeffs` to the output of `wavedec`, - `wavedec2` or `wavedecn`. - coeff_slices : list of tuples - List of slices corresponding to each coefficient as obtained from - `ravel_coeffs`. - coeff_shapes : list of tuples - List of shapes corresponding to each coefficient as obtained from - `ravel_coeffs`. - output_format : {'wavedec', 'wavedec2', 'wavedecn'}, optional - Make the form of the unraveled coefficients compatible with this type - of multilevel transform. The default is 'wavedecn'. - - Returns - ------- - coeffs: list - List of wavelet transform coefficients. The specific format of the list - elements is determined by `output_format`. - - See Also - -------- - ravel_coeffs : the inverse of unravel_coeffs - - Examples - -------- - >>> import pywt - >>> from numpy.testing import assert_array_almost_equal - >>> cam = pywt.data.camera() - >>> coeffs = pywt.wavedecn(cam, wavelet='db2', level=3) - >>> arr, coeff_slices, coeff_shapes = pywt.ravel_coeffs(coeffs) - >>> coeffs_from_arr = pywt.unravel_coeffs(arr, coeff_slices, coeff_shapes) - >>> cam_recon = pywt.waverecn(coeffs_from_arr, wavelet='db2') - >>> assert_array_almost_equal(cam, cam_recon) - - """ - arr = np.asarray(arr) - coeffs = [] - if len(coeff_slices) == 0: - raise ValueError("empty list of coefficient slices") - elif len(coeff_shapes) == 0: - raise ValueError("empty list of coefficient shapes") - elif len(coeff_shapes) != len(coeff_slices): - raise ValueError("coeff_shapes and coeff_slices have unequal length") - else: - coeffs.append(arr[coeff_slices[0]].reshape(coeff_shapes[0])) - - # difference coefficients at each level - for n in range(1, len(coeff_slices)): - slice_dict = coeff_slices[n] - shape_dict = coeff_shapes[n] - if output_format == 'wavedec': - d = arr[slice_dict['d']].reshape(shape_dict['d']) - elif output_format == 'wavedec2': - d = (arr[slice_dict['da']].reshape(shape_dict['da']), - arr[slice_dict['ad']].reshape(shape_dict['ad']), - arr[slice_dict['dd']].reshape(shape_dict['dd'])) - elif output_format == 'wavedecn': - d = {} - for k, v in coeff_slices[n].items(): - d[k] = arr[v].reshape(shape_dict[k]) - else: - raise ValueError( - "Unrecognized output format: {}".format(output_format)) - coeffs.append(d) - return coeffs - - -def _check_fswavedecn_axes(data, axes): - """Axes checks common to fswavedecn, fswaverecn.""" - if len(axes) != len(set(axes)): - raise ValueError("The axes passed to fswavedecn must be unique.") - try: - [data.shape[ax] for ax in axes] - except IndexError: - raise ValueError("Axis greater than data dimensions") - - -class FswavedecnResult(object): - """Object representing fully separable wavelet transform coefficients. - - Parameters - ---------- - coeffs : ndarray - The coefficient array. - coeff_slices : dict - Dictionary of slices corresponding to each detail or approximation - coefficient array. - wavelets : list of pywt.DiscreteWavelet objects - The wavelets used. Will be a list with length equal to - ``len(axes)``. - mode_enums : list of int - The border modes used. Will be a list with length equal to - ``len(axes)``. - axes : tuple of int - The set of axes over which the transform was performed. - - """ - def __init__(self, coeffs, coeff_slices, wavelets, mode_enums, - axes): - self._coeffs = coeffs - self._coeff_slices = coeff_slices - self._axes = axes - if not np.all(isinstance(w, Wavelet) for w in wavelets): - raise ValueError( - "wavelets must contain pywt.Wavelet objects") - self._wavelets = wavelets - if not np.all(isinstance(m, int) for m in mode_enums): - raise ValueError( - "mode_enums must be integers") - self._mode_enums = mode_enums - - @property - def coeffs(self): - """ndarray: All coefficients stacked into a single array.""" - return self._coeffs - - @coeffs.setter - def coeffs(self, c): - if c.shape != self._coeffs.shape: - raise ValueError("new coefficient array must match the existing " - "coefficient shape") - self._coeffs = c - - @property - def coeff_slices(self): - """Dict: Dictionary of coeffficient slices.""" - return self._coeff_slices - - @property - def ndim(self): - """int: Number of data dimensions.""" - return self.coeffs.ndim - - @property - def ndim_transform(self): - """int: Number of axes transformed.""" - return len(self.axes) - - @property - def axes(self): - """List of str: The axes the transform was performed along.""" - return self._axes - - @property - def levels(self): - """List of int: Levels of decomposition along each transformed axis.""" - return [len(s) - 1 for s in self.coeff_slices] - - @property - def wavelets(self): - """List of pywt.DiscreteWavelet: wavelet for each transformed axis.""" - return self._wavelets - - @property - def wavelet_names(self): - """List of pywt.DiscreteWavelet: wavelet for each transformed axis.""" - return [w.name for w in self._wavelets] - - @property - def modes(self): - """List of str: The border mode used along each transformed axis.""" - names_dict = {getattr(Modes, mode): mode - for mode in Modes.modes} - return [names_dict[m] for m in self._mode_enums] - - def _get_coef_sl(self, levels): - sl = [slice(None), ] * self.ndim - for n, (ax, lev) in enumerate(zip(self.axes, levels)): - sl[ax] = self.coeff_slices[n][lev] - return sl - - @property - def approx(self): - """ndarray: The approximation coefficients.""" - sl = self._get_coef_sl((0, )*self.ndim) - return self._coeffs[sl] - - @approx.setter - def approx(self, a): - sl = self._get_coef_sl((0, )*self.ndim) - if self._coeffs[sl].shape != a.shape: - raise ValueError( - "x does not match the shape of the requested coefficient") - self._coeffs[sl] = a - - def _validate_index(self, levels): - levels = tuple(levels) - - if len(levels) != len(self.axes): - raise ValueError( - "levels must match the number of transformed axes") - - # check that all elements are non-negative integers - if (not np.all([isinstance(lev, numbers.Number) for lev in levels]) or - np.any(np.asarray(levels) % 1 > 0) or - np.any([lev < 0 for lev in levels])): - raise ValueError("Index must be a tuple of non-negative integers") - # convert integer-valued floats to int - levels = tuple([int(lev) for lev in levels]) - - # check for out of range levels - if np.any([lev > maxlev for lev, maxlev in zip(levels, self.levels)]): - raise ValueError( - "Specified indices exceed the number of transform levels.") - - def __getitem__(self, levels): - """Retrieve a coefficient subband. - - Parameters - ---------- - levels : tuple of int - The number of degrees of decomposition along each transformed - axis. - """ - self._validate_index(levels) - sl = self._get_coef_sl(levels) - return self._coeffs[sl] - - def __setitem__(self, levels, x): - """Assign values to a coefficient subband. - - Parameters - ---------- - levels : tuple of int - The number of degrees of decomposition along each transformed - axis. - x : ndarray - The data corresponding to assign. It must match the expected - shape and dtype of the specified subband. - """ - self._validate_index(levels) - sl = self._get_coef_sl(levels) - if self._coeffs[sl].shape != x.shape: - raise ValueError( - "x does not match the shape of the requested coefficient") - if x.dtype != sl.dtype: - warnings.warn("dtype mismatch: converting the provided array to" - "dtype {}".format(sl.dtype)) - self._coeffs[sl] = x - - def detail_keys(self): - """Return a list of all detail coefficient keys. - - Returns - ------- - keys : list of str - List of all detail coefficient keys. - """ - keys = list(product(*(range(l+1) for l in self.levels))) - keys.remove((0, )*len(self.axes)) - return sorted(keys) - - -def fswavedecn(data, wavelet, mode='symmetric', levels=None, axes=None): - """Fully Separable Wavelet Decomposition. - - This is a variant of the multilevel discrete wavelet transform where all - levels of decomposition are performed along a single axis prior to moving - onto the next axis. Unlike in ``wavedecn``, the number of levels of - decomposition are not required to be the same along each axis which can be - a benefit for anisotropic data. - - Parameters - ---------- - data: array_like - Input data - wavelet : Wavelet object or name string, or tuple of wavelets - Wavelet to use. This can also be a tuple containing a wavelet to - apply along each axis in ``axes``. - mode : str or tuple of str, optional - Signal extension mode, see `Modes` (default: 'symmetric'). This can - also be a tuple containing a mode to apply along each axis in ``axes``. - levels : int or sequence of ints, optional - Decomposition levels along each axis (must be >= 0). If an integer is - provided, the same number of levels are used for all axes. If - ``levels`` is None (default), `dwt_max_level` will be used to compute - the maximum number of levels possible for each axis. - axes : sequence of ints, optional - Axes over which to compute the transform. Axes may not be repeated. The - default is to transform along all axes. - - Returns - ------- - fswavedecn_result : FswavedecnResult object - Contains the wavelet coefficients, slice objects to allow obtaining - the coefficients per detail or approximation level, and more. - See `FswavedecnResult` for details. - - Notes - ----- - This transformation has been variously referred to as the (fully) separable - wavelet transform (e.g. refs [1]_, [3]_), the tensor-product wavelet - ([2]_) or the hyperbolic wavelet transform ([4]_). It is well suited to - data with anisotropic smoothness. - - In [2]_ it was demonstrated that fully separable transform performs at - least as well as the DWT for image compression. Computation time is a - factor 2 larger than that for the DWT. - - See Also - -------- - fswaverecn : inverse of fswavedecn - - References - ---------- - .. [1] PH Westerink. Subband Coding of Images. Ph.D. dissertation, Dept. - Elect. Eng., Inf. Theory Group, Delft Univ. Technol., Delft, The - Netherlands, 1989. (see Section 2.3) - http://resolver.tudelft.nl/uuid:a4d195c3-1f89-4d66-913d-db9af0969509 - - .. [2] CP Rosiene and TQ Nguyen. Tensor-product wavelet vs. Mallat - decomposition: A comparative analysis, in Proc. IEEE Int. Symp. - Circuits and Systems, Orlando, FL, Jun. 1999, pp. 431-434. - - .. [3] V Velisavljevic, B Beferull-Lozano, M Vetterli and PL Dragotti. - Directionlets: Anisotropic Multidirectional Representation With - Separable Filtering. IEEE Transactions on Image Processing, Vol. 15, - No. 7, July 2006. - - .. [4] RA DeVore, SV Konyagin and VN Temlyakov. "Hyperbolic wavelet - approximation," Constr. Approx. 14 (1998), 1-26. - """ - data = np.asarray(data) - if axes is None: - axes = tuple(np.arange(data.ndim)) - _check_fswavedecn_axes(data, axes) - - if levels is None or np.isscalar(levels): - levels = [levels, ] * len(axes) - if len(levels) != len(axes): - raise ValueError("levels must match the length of the axes list") - - modes = _modes_per_axis(mode, axes) - wavelets = _wavelets_per_axis(wavelet, axes) - - coeff_slices = [slice(None), ] * len(axes) - coeffs_arr = data - for ax_count, (ax, lev, wav, mode) in enumerate( - zip(axes, levels, wavelets, modes)): - coeffs = wavedec(coeffs_arr, wav, mode=mode, level=lev, axis=ax) - - # Slice objects for accessing coefficient subsets. - # These can be used to access specific detail coefficient arrays - # (e.g. as needed for inverse transformation via fswaverecn). - c_shapes = [c.shape[ax] for c in coeffs] - c_offsets = np.cumsum([0, ] + c_shapes) - coeff_slices[ax_count] = [ - slice(c_offsets[d], c_offsets[d+1]) for d in range(len(c_shapes))] - - # stack the coefficients from all levels into a single array - coeffs_arr = np.concatenate(coeffs, axis=ax) - - return FswavedecnResult(coeffs_arr, coeff_slices, wavelets, modes, axes) - - -def fswaverecn(fswavedecn_result): - """Fully Separable Inverse Wavelet Reconstruction. - - Parameters - ---------- - fswavedecn_result : FswavedecnResult object - FswavedecnResult object from ``fswavedecn``. - - Returns - ------- - reconstructed : ndarray - Array of reconstructed data. - - Notes - ----- - This transformation has been variously referred to as the (fully) separable - wavelet transform (e.g. refs [1]_, [3]_), the tensor-product wavelet - ([2]_) or the hyperbolic wavelet transform ([4]_). It is well suited to - data with anisotropic smoothness. - - In [2]_ it was demonstrated that the fully separable transform performs at - least as well as the DWT for image compression. Computation time is a - factor 2 larger than that for the DWT. - - See Also - -------- - fswavedecn : inverse of fswaverecn - - References - ---------- - .. [1] PH Westerink. Subband Coding of Images. Ph.D. dissertation, Dept. - Elect. Eng., Inf. Theory Group, Delft Univ. Technol., Delft, The - Netherlands, 1989. (see Section 2.3) - http://resolver.tudelft.nl/uuid:a4d195c3-1f89-4d66-913d-db9af0969509 - - .. [2] CP Rosiene and TQ Nguyen. Tensor-product wavelet vs. Mallat - decomposition: A comparative analysis, in Proc. IEEE Int. Symp. - Circuits and Systems, Orlando, FL, Jun. 1999, pp. 431-434. - - .. [3] V Velisavljevic, B Beferull-Lozano, M Vetterli and PL Dragotti. - Directionlets: Anisotropic Multidirectional Representation With - Separable Filtering. IEEE Transactions on Image Processing, Vol. 15, - No. 7, July 2006. - - .. [4] RA DeVore, SV Konyagin and VN Temlyakov. "Hyperbolic wavelet - approximation," Constr. Approx. 14 (1998), 1-26. - """ - coeffs_arr = fswavedecn_result.coeffs - coeff_slices = fswavedecn_result.coeff_slices - axes = fswavedecn_result.axes - modes = fswavedecn_result.modes - wavelets = fswavedecn_result.wavelets - - _check_fswavedecn_axes(coeffs_arr, axes) - if len(axes) != len(coeff_slices): - raise ValueError("dimension mismatch") - - arr = coeffs_arr - csl = [slice(None), ] * arr.ndim - # for ax_count, (ax, wav, mode) in reversed( - # list(enumerate(zip(axes, wavelets, modes)))): - for ax_count, (ax, wav, mode) in enumerate(zip(axes, wavelets, modes)): - coeffs = [] - for sl in coeff_slices[ax_count]: - csl[ax] = sl - coeffs.append(arr[tuple(csl)]) - csl[ax] = slice(None) - arr = waverec(coeffs, wav, mode=mode, axis=ax) - return arr diff --git a/.eggs/PyWavelets-1.0.0-py3.7-linux-x86_64.egg/pywt/_swt.py b/.eggs/PyWavelets-1.0.0-py3.7-linux-x86_64.egg/pywt/_swt.py deleted file mode 100644 index 1fe2c79e..00000000 --- a/.eggs/PyWavelets-1.0.0-py3.7-linux-x86_64.egg/pywt/_swt.py +++ /dev/null @@ -1,533 +0,0 @@ -import warnings -from itertools import product - -import numpy as np - -from ._c99_config import _have_c99_complex -from ._extensions._dwt import idwt_single -from ._extensions._swt import swt_max_level, swt as _swt, swt_axis as _swt_axis -from ._extensions._pywt import Modes, _check_dtype -from ._multidim import idwt2, idwtn -from ._utils import _as_wavelet, _wavelets_per_axis - - -__all__ = ["swt", "swt_max_level", 'iswt', 'swt2', 'iswt2', 'swtn', 'iswtn'] - - -def swt(data, wavelet, level=None, start_level=0, axis=-1): - """ - Multilevel 1D stationary wavelet transform. - - Parameters - ---------- - data : - Input signal - wavelet : - Wavelet to use (Wavelet object or name) - level : int, optional - The number of decomposition steps to perform. - start_level : int, optional - The level at which the decomposition will begin (it allows one to - skip a given number of transform steps and compute - coefficients starting from start_level) (default: 0) - axis: int, optional - Axis over which to compute the SWT. If not given, the - last axis is used. - - Returns - ------- - coeffs : list - List of approximation and details coefficients pairs in order - similar to wavedec function:: - - [(cAn, cDn), ..., (cA2, cD2), (cA1, cD1)] - - where n equals input parameter ``level``. - - If ``start_level = m`` is given, then the beginning m steps are - skipped:: - - [(cAm+n, cDm+n), ..., (cAm+1, cDm+1), (cAm, cDm)] - - Notes - ----- - The implementation here follows the "algorithm a-trous" and requires that - the signal length along the transformed axis be a multiple of ``2**level``. - If this is not the case, the user should pad up to an appropriate size - using a function such as ``numpy.pad``. - """ - if not _have_c99_complex and np.iscomplexobj(data): - data = np.asarray(data) - coeffs_real = swt(data.real, wavelet, level, start_level) - coeffs_imag = swt(data.imag, wavelet, level, start_level) - coeffs_cplx = [] - for (cA_r, cD_r), (cA_i, cD_i) in zip(coeffs_real, coeffs_imag): - coeffs_cplx.append((cA_r + 1j*cA_i, cD_r + 1j*cD_i)) - return coeffs_cplx - - # accept array_like input; make a copy to ensure a contiguous array - dt = _check_dtype(data) - data = np.array(data, dtype=dt) - - wavelet = _as_wavelet(wavelet) - - if axis < 0: - axis = axis + data.ndim - if not 0 <= axis < data.ndim: - raise ValueError("Axis greater than data dimensions") - - if level is None: - level = swt_max_level(data.shape[axis]) - - if data.ndim == 1: - ret = _swt(data, wavelet, level, start_level) - else: - ret = _swt_axis(data, wavelet, level, start_level, axis) - return [(np.asarray(cA), np.asarray(cD)) for cA, cD in ret] - - -def iswt(coeffs, wavelet): - """ - Multilevel 1D inverse discrete stationary wavelet transform. - - Parameters - ---------- - coeffs : array_like - Coefficients list of tuples:: - - [(cAn, cDn), ..., (cA2, cD2), (cA1, cD1)] - - where cA is approximation, cD is details. Index 1 corresponds to - ``start_level`` from ``pywt.swt``. - wavelet : Wavelet object or name string - Wavelet to use - - Returns - ------- - 1D array of reconstructed data. - - Examples - -------- - >>> import pywt - >>> coeffs = pywt.swt([1,2,3,4,5,6,7,8], 'db2', level=2) - >>> pywt.iswt(coeffs, 'db2') - array([ 1., 2., 3., 4., 5., 6., 7., 8.]) - """ - output = coeffs[0][0].copy() # Avoid modification of input data - if not _have_c99_complex and np.iscomplexobj(output): - # compute real and imaginary separately then combine - coeffs_real = [(cA.real, cD.real) for (cA, cD) in coeffs] - coeffs_imag = [(cA.imag, cD.imag) for (cA, cD) in coeffs] - return iswt(coeffs_real, wavelet) + 1j*iswt(coeffs_imag, wavelet) - - # num_levels, equivalent to the decomposition level, n - num_levels = len(coeffs) - wavelet = _as_wavelet(wavelet) - mode = Modes.from_object('periodization') - for j in range(num_levels, 0, -1): - step_size = int(pow(2, j-1)) - last_index = step_size - _, cD = coeffs[num_levels - j] - dt = _check_dtype(cD) - cD = np.asarray(cD, dtype=dt) # doesn't copy if dtype matches - for first in range(last_index): # 0 to last_index - 1 - - # Getting the indices that we will transform - indices = np.arange(first, len(cD), step_size) - - # select the even indices - even_indices = indices[0::2] - # select the odd indices - odd_indices = indices[1::2] - - # perform the inverse dwt on the selected indices, - # making sure to use periodic boundary conditions - # Note: indexing with an array of ints returns a contiguous - # copy as required by idwt_single. - x1 = idwt_single(output[even_indices], - cD[even_indices], - wavelet, mode) - x2 = idwt_single(output[odd_indices], - cD[odd_indices], - wavelet, mode) - - # perform a circular shift right - x2 = np.roll(x2, 1) - - # average and insert into the correct indices - output[indices] = (x1 + x2)/2. - - return output - - -def swt2(data, wavelet, level, start_level=0, axes=(-2, -1)): - """ - Multilevel 2D stationary wavelet transform. - - Parameters - ---------- - data : array_like - 2D array with input data - wavelet : Wavelet object or name string, or 2-tuple of wavelets - Wavelet to use. This can also be a tuple of wavelets to apply per - axis in ``axes``. - level : int - The number of decomposition steps to perform. - start_level : int, optional - The level at which the decomposition will start (default: 0) - axes : 2-tuple of ints, optional - Axes over which to compute the SWT. Repeated elements are not allowed. - - Returns - ------- - coeffs : list - Approximation and details coefficients (for ``start_level = m``):: - - [ - (cA_m+level, - (cH_m+level, cV_m+level, cD_m+level) - ), - ..., - (cA_m+1, - (cH_m+1, cV_m+1, cD_m+1) - ), - (cA_m, - (cH_m, cV_m, cD_m) - ) - ] - - where cA is approximation, cH is horizontal details, cV is - vertical details, cD is diagonal details and m is ``start_level``. - - Notes - ----- - The implementation here follows the "algorithm a-trous" and requires that - the signal length along the transformed axes be a multiple of ``2**level``. - If this is not the case, the user should pad up to an appropriate size - using a function such as ``numpy.pad``. - """ - axes = tuple(axes) - data = np.asarray(data) - if len(axes) != 2: - raise ValueError("Expected 2 axes") - if len(axes) != len(set(axes)): - raise ValueError("The axes passed to swt2 must be unique.") - if data.ndim < len(np.unique(axes)): - raise ValueError("Input array has fewer dimensions than the specified " - "axes") - - coefs = swtn(data, wavelet, level, start_level, axes) - ret = [] - for c in coefs: - ret.append((c['aa'], (c['da'], c['ad'], c['dd']))) - - return ret - - -def iswt2(coeffs, wavelet): - """ - Multilevel 2D inverse discrete stationary wavelet transform. - - Parameters - ---------- - coeffs : list - Approximation and details coefficients:: - - [ - (cA_n, - (cH_n, cV_n, cD_n) - ), - ..., - (cA_2, - (cH_2, cV_2, cD_2) - ), - (cA_1, - (cH_1, cV_1, cD_1) - ) - ] - - where cA is approximation, cH is horizontal details, cV is - vertical details, cD is diagonal details and n is the number of - levels. Index 1 corresponds to ``start_level`` from ``pywt.swt2``. - wavelet : Wavelet object or name string, or 2-tuple of wavelets - Wavelet to use. This can also be a 2-tuple of wavelets to apply per - axis. - - Returns - ------- - 2D array of reconstructed data. - - Examples - -------- - >>> import pywt - >>> coeffs = pywt.swt2([[1,2,3,4],[5,6,7,8], - ... [9,10,11,12],[13,14,15,16]], - ... 'db1', level=2) - >>> pywt.iswt2(coeffs, 'db1') - array([[ 1., 2., 3., 4.], - [ 5., 6., 7., 8.], - [ 9., 10., 11., 12.], - [ 13., 14., 15., 16.]]) - - """ - - output = coeffs[0][0].copy() # Avoid modification of input data - if output.ndim != 2: - raise ValueError( - "iswt2 only supports 2D arrays. see iswtn for a general " - "n-dimensionsal ISWT") - # num_levels, equivalent to the decomposition level, n - num_levels = len(coeffs) - wavelets = _wavelets_per_axis(wavelet, axes=(0, 1)) - - for j in range(num_levels): - step_size = int(pow(2, num_levels-j-1)) - last_index = step_size - _, (cH, cV, cD) = coeffs[j] - # We are going to assume cH, cV, and cD are of equal size - if (cH.shape != cV.shape) or (cH.shape != cD.shape): - raise RuntimeError( - "Mismatch in shape of intermediate coefficient arrays") - for first_h in range(last_index): # 0 to last_index - 1 - for first_w in range(last_index): # 0 to last_index - 1 - # Getting the indices that we will transform - indices_h = slice(first_h, cH.shape[0], step_size) - indices_w = slice(first_w, cH.shape[1], step_size) - - even_idx_h = slice(first_h, cH.shape[0], 2*step_size) - even_idx_w = slice(first_w, cH.shape[1], 2*step_size) - odd_idx_h = slice(first_h + step_size, cH.shape[0], 2*step_size) - odd_idx_w = slice(first_w + step_size, cH.shape[1], 2*step_size) - - # perform the inverse dwt on the selected indices, - # making sure to use periodic boundary conditions - x1 = idwt2((output[even_idx_h, even_idx_w], - (cH[even_idx_h, even_idx_w], - cV[even_idx_h, even_idx_w], - cD[even_idx_h, even_idx_w])), - wavelets, 'periodization') - x2 = idwt2((output[even_idx_h, odd_idx_w], - (cH[even_idx_h, odd_idx_w], - cV[even_idx_h, odd_idx_w], - cD[even_idx_h, odd_idx_w])), - wavelets, 'periodization') - x3 = idwt2((output[odd_idx_h, even_idx_w], - (cH[odd_idx_h, even_idx_w], - cV[odd_idx_h, even_idx_w], - cD[odd_idx_h, even_idx_w])), - wavelets, 'periodization') - x4 = idwt2((output[odd_idx_h, odd_idx_w], - (cH[odd_idx_h, odd_idx_w], - cV[odd_idx_h, odd_idx_w], - cD[odd_idx_h, odd_idx_w])), - wavelets, 'periodization') - - # perform a circular shifts - x2 = np.roll(x2, 1, axis=1) - x3 = np.roll(x3, 1, axis=0) - x4 = np.roll(x4, 1, axis=0) - x4 = np.roll(x4, 1, axis=1) - output[indices_h, indices_w] = (x1 + x2 + x3 + x4) / 4 - - return output - - -def swtn(data, wavelet, level, start_level=0, axes=None): - """ - n-dimensional stationary wavelet transform. - - Parameters - ---------- - data : array_like - n-dimensional array with input data. - wavelet : Wavelet object or name string, or tuple of wavelets - Wavelet to use. This can also be a tuple of wavelets to apply per - axis in ``axes``. - level : int - The number of decomposition steps to perform. - start_level : int, optional - The level at which the decomposition will start (default: 0) - axes : sequence of ints, optional - Axes over which to compute the SWT. A value of ``None`` (the - default) selects all axes. Axes may not be repeated. - - Returns - ------- - [{coeffs_level_n}, ..., {coeffs_level_1}]: list of dict - Results for each level are arranged in a dictionary, where the key - specifies the transform type on each dimension and value is a - n-dimensional coefficients array. - - For example, for a 2D case the result at a given level will look - something like this:: - - {'aa': # A(LL) - approx. on 1st dim, approx. on 2nd dim - 'ad': # V(LH) - approx. on 1st dim, det. on 2nd dim - 'da': # H(HL) - det. on 1st dim, approx. on 2nd dim - 'dd': # D(HH) - det. on 1st dim, det. on 2nd dim - } - - For user-specified ``axes``, the order of the characters in the - dictionary keys map to the specified ``axes``. - - Notes - ----- - The implementation here follows the "algorithm a-trous" and requires that - the signal length along the transformed axes be a multiple of ``2**level``. - If this is not the case, the user should pad up to an appropriate size - using a function such as ``numpy.pad``. - """ - data = np.asarray(data) - if not _have_c99_complex and np.iscomplexobj(data): - real = swtn(data.real, wavelet, level, start_level, axes) - imag = swtn(data.imag, wavelet, level, start_level, axes) - cplx = [] - for rdict, idict in zip(real, imag): - cplx.append( - dict((k, rdict[k] + 1j * idict[k]) for k in rdict.keys())) - return cplx - - if data.dtype == np.dtype('object'): - raise TypeError("Input must be a numeric array-like") - if data.ndim < 1: - raise ValueError("Input data must be at least 1D") - - if axes is None: - axes = range(data.ndim) - axes = [a + data.ndim if a < 0 else a for a in axes] - if len(axes) != len(set(axes)): - raise ValueError("The axes passed to swtn must be unique.") - num_axes = len(axes) - - wavelets = _wavelets_per_axis(wavelet, axes) - - ret = [] - for i in range(start_level, start_level + level): - coeffs = [('', data)] - for axis, wavelet in zip(axes, wavelets): - new_coeffs = [] - for subband, x in coeffs: - cA, cD = _swt_axis(x, wavelet, level=1, start_level=i, - axis=axis)[0] - new_coeffs.extend([(subband + 'a', cA), - (subband + 'd', cD)]) - coeffs = new_coeffs - - coeffs = dict(coeffs) - ret.append(coeffs) - - # data for the next level is the approximation coeffs from this level - data = coeffs['a' * num_axes] - - ret.reverse() - return ret - - -def iswtn(coeffs, wavelet, axes=None): - """ - Multilevel nD inverse discrete stationary wavelet transform. - - Parameters - ---------- - coeffs : list - [{coeffs_level_n}, ..., {coeffs_level_1}]: list of dict - wavelet : Wavelet object or name string, or tuple of wavelets - Wavelet to use. This can also be a tuple of wavelets to apply per - axis in ``axes``. - axes : sequence of ints, optional - Axes over which to compute the inverse SWT. Axes may not be repeated. - The default is ``None``, which means transform all axes - (``axes = range(data.ndim)``). - - Returns - ------- - nD array of reconstructed data. - - Examples - -------- - >>> import pywt - >>> coeffs = pywt.swtn([[1,2,3,4],[5,6,7,8], - ... [9,10,11,12],[13,14,15,16]], - ... 'db1', level=2) - >>> pywt.iswtn(coeffs, 'db1') - array([[ 1., 2., 3., 4.], - [ 5., 6., 7., 8.], - [ 9., 10., 11., 12.], - [ 13., 14., 15., 16.]]) - - """ - - # key length matches the number of axes transformed - ndim_transform = max(len(key) for key in coeffs[0].keys()) - - output = coeffs[0]['a'*ndim_transform].copy() # Avoid modifying input data - ndim = output.ndim - - if axes is None: - axes = range(output.ndim) - axes = [a + ndim if a < 0 else a for a in axes] - if len(axes) != len(set(axes)): - raise ValueError("The axes passed to swtn must be unique.") - if ndim_transform != len(axes): - raise ValueError("The number of axes used in iswtn must match the " - "number of dimensions transformed in swtn.") - - # num_levels, equivalent to the decomposition level, n - num_levels = len(coeffs) - wavelets = _wavelets_per_axis(wavelet, axes) - - # initialize various slice objects used in the loops below - # these will remain slice(None) only on axes that aren't transformed - indices = [slice(None), ]*ndim - even_indices = [slice(None), ]*ndim - odd_indices = [slice(None), ]*ndim - odd_even_slices = [slice(None), ]*ndim - - for j in range(num_levels): - step_size = int(pow(2, num_levels-j-1)) - last_index = step_size - a = coeffs[j].pop('a'*ndim_transform) # will restore later - details = coeffs[j] - # We assume all coefficient arrays are of equal size - shapes = [v.shape for k, v in details.items()] - dshape = shapes[0] - if len(set(shapes)) != 1: - raise RuntimeError( - "Mismatch in shape of intermediate coefficient arrays") - - # nested loop over all combinations of axis offsets at this level - for firsts in product(*([range(last_index), ]*ndim_transform)): - for first, sh, ax in zip(firsts, dshape, axes): - indices[ax] = slice(first, sh, step_size) - even_indices[ax] = slice(first, sh, 2*step_size) - odd_indices[ax] = slice(first+step_size, sh, 2*step_size) - - # nested loop over all combinations of odd/even inidices - approx = output.copy() - output[tuple(indices)] = 0 - ntransforms = 0 - for odds in product(*([(0, 1), ]*ndim_transform)): - for o, ax in zip(odds, axes): - if o: - odd_even_slices[ax] = odd_indices[ax] - else: - odd_even_slices[ax] = even_indices[ax] - # extract the odd/even indices for all detail coefficients - details_slice = {} - for key, value in details.items(): - details_slice[key] = value[tuple(odd_even_slices)] - details_slice['a'*ndim_transform] = approx[ - tuple(odd_even_slices)] - - # perform the inverse dwt on the selected indices, - # making sure to use periodic boundary conditions - x = idwtn(details_slice, wavelets, 'periodization', axes=axes) - for o, ax in zip(odds, axes): - # circular shift along any odd indexed axis - if o: - x = np.roll(x, 1, axis=ax) - output[tuple(indices)] += x - ntransforms += 1 - output[tuple(indices)] /= ntransforms # normalize - coeffs[j]['a'*ndim_transform] = a # restore approx coeffs to dict - return output diff --git a/.eggs/PyWavelets-1.0.0-py3.7-linux-x86_64.egg/pywt/_thresholding.py b/.eggs/PyWavelets-1.0.0-py3.7-linux-x86_64.egg/pywt/_thresholding.py deleted file mode 100644 index 2b433d8b..00000000 --- a/.eggs/PyWavelets-1.0.0-py3.7-linux-x86_64.egg/pywt/_thresholding.py +++ /dev/null @@ -1,247 +0,0 @@ -# Copyright (c) 2006-2012 Filip Wasilewski -# Copyright (c) 2012-2016 The PyWavelets Developers -# -# See COPYING for license details. - -""" -The thresholding helper module implements the most popular signal thresholding -functions. -""" - -from __future__ import division, print_function, absolute_import -import numpy as np - -__all__ = ['threshold', 'threshold_firm'] - - -def soft(data, value, substitute=0): - data = np.asarray(data) - magnitude = np.absolute(data) - - with np.errstate(divide='ignore'): - # divide by zero okay as np.inf values get clipped, so ignore warning. - thresholded = (1 - value/magnitude) - thresholded.clip(min=0, max=None, out=thresholded) - thresholded = data * thresholded - - if substitute == 0: - return thresholded - else: - cond = np.less(magnitude, value) - return np.where(cond, substitute, thresholded) - - -def nn_garrote(data, value, substitute=0): - """Non-negative Garotte.""" - data = np.asarray(data) - magnitude = np.absolute(data) - - with np.errstate(divide='ignore'): - # divide by zero okay as np.inf values get clipped, so ignore warning. - thresholded = (1 - value**2/magnitude**2) - thresholded.clip(min=0, max=None, out=thresholded) - thresholded = data * thresholded - - if substitute == 0: - return thresholded - else: - cond = np.less(magnitude, value) - return np.where(cond, substitute, thresholded) - - -def hard(data, value, substitute=0): - data = np.asarray(data) - cond = np.less(np.absolute(data), value) - return np.where(cond, substitute, data) - - -def greater(data, value, substitute=0): - data = np.asarray(data) - if np.iscomplexobj(data): - raise ValueError("greater thresholding only supports real data") - return np.where(np.less(data, value), substitute, data) - - -def less(data, value, substitute=0): - data = np.asarray(data) - if np.iscomplexobj(data): - raise ValueError("less thresholding only supports real data") - return np.where(np.greater(data, value), substitute, data) - - -thresholding_options = {'soft': soft, - 'hard': hard, - 'greater': greater, - 'less': less, - 'garotte': nn_garrote} - - -def threshold(data, value, mode='soft', substitute=0): - """ - Thresholds the input data depending on the mode argument. - - In ``soft`` thresholding [1]_, data values with absolute value less than - `param` are replaced with `substitute`. Data values with absolute value - greater or equal to the thresholding value are shrunk toward zero - by `value`. In other words, the new value is - ``data/np.abs(data) * np.maximum(np.abs(data) - value, 0)``. - - In ``hard`` thresholding, the data values where their absolute value is - less than the value param are replaced with `substitute`. Data values with - absolute value greater or equal to the thresholding value stay untouched. - - ``garotte`` corresponds to the Non-negative garrote threshold [2]_, [3]_. - It is intermediate between ``hard`` and ``soft`` thresholding. It behaves - like soft thresholding for small data values and approaches hard - thresholding for large data values. - - In ``greater`` thresholding, the data is replaced with `substitute` where - data is below the thresholding value. Greater data values pass untouched. - - In ``less`` thresholding, the data is replaced with `substitute` where data - is above the thresholding value. Lesser data values pass untouched. - - Both ``hard`` and ``soft`` thresholding also support complex-valued data. - - Parameters - ---------- - data : array_like - Numeric data. - value : scalar - Thresholding value. - mode : {'soft', 'hard', 'greater', 'less'} - Decides the type of thresholding to be applied on input data. Default - is 'soft'. - substitute : float, optional - Substitute value (default: 0). - - Returns - ------- - output : array - Thresholded array. - - See Also - -------- - threshold_firm - - References - ---------- - .. [1] D.L. Donoho and I.M. Johnstone. Ideal Spatial Adaptation via - Wavelet Shrinkage. Biometrika. Vol. 81, No. 3, pp.425-455, 1994. - DOI:10.1093/biomet/81.3.425 - .. [2] L. Breiman. Better Subset Regression Using the Nonnegative Garrote. - Technometrics, Vol. 37, pp. 373-384, 1995. - DOI:10.2307/1269730 - .. [3] H-Y. Gao. Wavelet Shrinkage Denoising Using the Non-Negative - Garrote. Journal of Computational and Graphical Statistics Vol. 7, - No. 4, pp.469-488. 1998. - DOI:10.1080/10618600.1998.10474789 - - Examples - -------- - >>> import numpy as np - >>> import pywt - >>> data = np.linspace(1, 4, 7) - >>> data - array([ 1. , 1.5, 2. , 2.5, 3. , 3.5, 4. ]) - >>> pywt.threshold(data, 2, 'soft') - array([ 0. , 0. , 0. , 0.5, 1. , 1.5, 2. ]) - >>> pywt.threshold(data, 2, 'hard') - array([ 0. , 0. , 2. , 2.5, 3. , 3.5, 4. ]) - >>> pywt.threshold(data, 2, 'garotte') - array([ 0. , 0. , 0. , 0.9 , 1.66666667, - 2.35714286, 3. ]) - >>> pywt.threshold(data, 2, 'greater') - array([ 0. , 0. , 2. , 2.5, 3. , 3.5, 4. ]) - >>> pywt.threshold(data, 2, 'less') - array([ 1. , 1.5, 2. , 0. , 0. , 0. , 0. ]) - - """ - - try: - return thresholding_options[mode](data, value, substitute) - except KeyError: - # Make sure error is always identical by sorting keys - keys = ("'{0}'".format(key) for key in - sorted(thresholding_options.keys())) - raise ValueError("The mode parameter only takes values from: {0}." - .format(', '.join(keys))) - - -def threshold_firm(data, value_low, value_high): - """Firm threshold. - - The approach is intermediate between soft and hard thresholding [1]_. It - behaves the same as soft-thresholding for values below `value_low` and - the same as hard-thresholding for values above `thresh_high`. For - intermediate values, the thresholded value is in between that corresponding - to soft or hard thresholding. - - Parameters - ---------- - data : array-like - The data to threshold. This can be either real or complex-valued. - value_low : float - Any values smaller then `value_low` will be set to zero. - value_high : float - Any values larger than `value_high` will not be modified. - - Notes - ----- - This thresholding technique is also known as semi-soft thresholding [2]_. - - For each value, `x`, in `data`. This function computes:: - - if np.abs(x) <= value_low: - return 0 - elif np.abs(x) > value_high: - return x - elif value_low < np.abs(x) and np.abs(x) <= value_high: - return x * value_high * (1 - value_low/x)/(value_high - value_low) - - ``firm`` is a continuous function (like soft thresholding), but is - unbiased for large values (like hard thresholding). - - If ``value_high == value_low`` this function becomes hard-thresholding. - If ``value_high`` is infinity, this function becomes soft-thresholding. - - Returns - ------- - val_new : array-like - The values after firm thresholding at the specified thresholds. - - See Also - -------- - threshold - - References - ---------- - .. [1] H.-Y. Gao and A.G. Bruce. Waveshrink with firm shrinkage. - Statistica Sinica, Vol. 7, pp. 855-874, 1997. - .. [2] A. Bruce and H-Y. Gao. WaveShrink: Shrinkage Functions and - Thresholds. Proc. SPIE 2569, Wavelet Applications in Signal and - Image Processing III, 1995. - DOI:10.1117/12.217582 - """ - - if value_low < 0: - raise ValueError("value_low must be non-negative.") - - if value_high < value_low: - raise ValueError( - "value_high must be greater than or equal to value_low.") - - data = np.asarray(data) - magnitude = np.absolute(data) - with np.errstate(divide='ignore'): - # divide by zero okay as np.inf values get clipped, so ignore warning. - vdiff = value_high - value_low - thresholded = value_high * (1 - value_low/magnitude) / vdiff - thresholded.clip(min=0, max=None, out=thresholded) - thresholded = data * thresholded - - # restore hard-thresholding behavior for values > value_high - large_vals = np.where(magnitude > value_high) - if np.any(large_vals[0]): - thresholded[large_vals] = data[large_vals] - return thresholded diff --git a/.eggs/PyWavelets-1.0.0-py3.7-linux-x86_64.egg/pywt/_utils.py b/.eggs/PyWavelets-1.0.0-py3.7-linux-x86_64.egg/pywt/_utils.py deleted file mode 100644 index 754d3bd6..00000000 --- a/.eggs/PyWavelets-1.0.0-py3.7-linux-x86_64.egg/pywt/_utils.py +++ /dev/null @@ -1,120 +0,0 @@ -# Copyright (c) 2017 The PyWavelets Developers -# -# See COPYING for license details. -import inspect -import sys -from collections import Iterable - -from ._extensions._pywt import (Wavelet, ContinuousWavelet, - DiscreteContinuousWavelet, Modes) - - -# define string_types as in six for Python 2/3 compatibility -if sys.version_info[0] == 3: - string_types = str, -else: - string_types = basestring, - - -def _as_wavelet(wavelet): - """Convert wavelet name to a Wavelet object""" - if not isinstance(wavelet, (ContinuousWavelet, Wavelet)): - wavelet = DiscreteContinuousWavelet(wavelet) - if isinstance(wavelet, ContinuousWavelet): - raise ValueError( - "A ContinuousWavelet object was provided, but only discrete " - "Wavelet objects are supported by this function. A list of all " - "supported discrete wavelets can be obtained by running:\n" - "print(pywt.wavelist(kind='discrete'))") - return wavelet - - -def _wavelets_per_axis(wavelet, axes): - """Initialize Wavelets for each axis to be transformed. - - Parameters - ---------- - wavelet : Wavelet or tuple of Wavelets - If a single Wavelet is provided, it will used for all axes. Otherwise - one Wavelet per axis must be provided. - axes : list - The tuple of axes to be transformed. - - Returns - ------- - wavelets : list of Wavelet objects - A tuple of Wavelets equal in length to ``axes``. - - """ - axes = tuple(axes) - if isinstance(wavelet, string_types + (Wavelet, )): - # same wavelet on all axes - wavelets = [_as_wavelet(wavelet), ] * len(axes) - elif isinstance(wavelet, Iterable): - # (potentially) unique wavelet per axis (e.g. for dual-tree DWT) - if len(wavelet) == 1: - wavelets = [_as_wavelet(wavelet[0]), ] * len(axes) - else: - if len(wavelet) != len(axes): - raise ValueError(( - "The number of wavelets must match the number of axes " - "to be transformed.")) - wavelets = [_as_wavelet(w) for w in wavelet] - else: - raise ValueError("wavelet must be a str, Wavelet or iterable") - return wavelets - - -def _modes_per_axis(modes, axes): - """Initialize mode for each axis to be transformed. - - Parameters - ---------- - modes : str or tuple of strings - If a single mode is provided, it will used for all axes. Otherwise - one mode per axis must be provided. - axes : tuple - The tuple of axes to be transformed. - - Returns - ------- - modes : tuple of int - A tuple of Modes equal in length to ``axes``. - - """ - axes = tuple(axes) - if isinstance(modes, string_types + (int, )): - # same wavelet on all axes - modes = [Modes.from_object(modes), ] * len(axes) - elif isinstance(modes, Iterable): - if len(modes) == 1: - modes = [Modes.from_object(modes[0]), ] * len(axes) - else: - # (potentially) unique wavelet per axis (e.g. for dual-tree DWT) - if len(modes) != len(axes): - raise ValueError(("The number of modes must match the number " - "of axes to be transformed.")) - modes = [Modes.from_object(mode) for mode in modes] - else: - raise ValueError("modes must be a str, Mode enum or iterable") - return modes - - -def is_nose_running(): - """Returns whether we are running the nose test loader - """ - if 'nose' not in sys.modules: - return False - try: - import nose - except ImportError: - return False - # Now check that we have the loader in the call stask - stack = inspect.stack() - loader_file_name = nose.loader.__file__ - if loader_file_name.endswith('.pyc'): - loader_file_name = loader_file_name[:-1] - for _, file_name, _, _, _, _ in stack: - if file_name == loader_file_name: - return True - return False diff --git a/.eggs/PyWavelets-1.0.0-py3.7-linux-x86_64.egg/pywt/_wavelet_packets.py b/.eggs/PyWavelets-1.0.0-py3.7-linux-x86_64.egg/pywt/_wavelet_packets.py deleted file mode 100644 index 755179c4..00000000 --- a/.eggs/PyWavelets-1.0.0-py3.7-linux-x86_64.egg/pywt/_wavelet_packets.py +++ /dev/null @@ -1,725 +0,0 @@ -# Copyright (c) 2006-2012 Filip Wasilewski -# Copyright (c) 2012-2016 The PyWavelets Developers -# -# See COPYING for license details. - -"""1D and 2D Wavelet packet transform module.""" - -from __future__ import division, print_function, absolute_import - -__all__ = ["BaseNode", "Node", "WaveletPacket", "Node2D", "WaveletPacket2D"] - -import numpy as np - -from ._extensions._pywt import Wavelet, _check_dtype -from ._dwt import dwt, idwt, dwt_max_level -from ._multidim import dwt2, idwt2 - - -def get_graycode_order(level, x='a', y='d'): - graycode_order = [x, y] - for i in range(level - 1): - graycode_order = [x + path for path in graycode_order] + \ - [y + path for path in graycode_order[::-1]] - return graycode_order - - -class BaseNode(object): - """ - BaseNode for wavelet packet 1D and 2D tree nodes. - - The BaseNode is a base class for `Node` and `Node2D`. - It should not be used directly unless creating a new transformation - type. It is included here to document the common interface of 1D - and 2D node and wavelet packet transform classes. - - Parameters - ---------- - parent : - Parent node. If parent is None then the node is considered detached - (ie root). - data : 1D or 2D array - Data associated with the node. 1D or 2D numeric array, depending on the - transform type. - node_name : - A name identifying the coefficients type. - See `Node.node_name` and `Node2D.node_name` - for information on the accepted subnodes names. - """ - - # PART_LEN and PARTS attributes that define path tokens for node[] lookup - # must be defined in subclasses. - PART_LEN = None - PARTS = None - - def __init__(self, parent, data, node_name): - self.parent = parent - if parent is not None: - self.wavelet = parent.wavelet - self.mode = parent.mode - self.level = parent.level + 1 - self._maxlevel = parent.maxlevel - self.path = parent.path + node_name - else: - self.wavelet = None - self.mode = None - self.path = "" - self.level = 0 - - # data - signal on level 0, coeffs on higher levels - self.data = data - - self._init_subnodes() - - def _init_subnodes(self): - for part in self.PARTS: - self._set_node(part, None) - - def _create_subnode(self, part, data=None, overwrite=True): - raise NotImplementedError() - - def _create_subnode_base(self, node_cls, part, data=None, overwrite=True): - self._validate_node_name(part) - if not overwrite and self._get_node(part) is not None: - return self._get_node(part) - node = node_cls(self, data, part) - self._set_node(part, node) - return node - - def _get_node(self, part): - return getattr(self, part) - - def _set_node(self, part, node): - setattr(self, part, node) - - def _delete_node(self, part): - self._set_node(part, None) - - def _validate_node_name(self, part): - if part not in self.PARTS: - raise ValueError("Subnode name must be in [%s], not '%s'." % - (', '.join("'%s'" % p for p in self.PARTS), part)) - - def _evaluate_maxlevel(self, evaluate_from='parent'): - """ - Try to find the value of maximum decomposition level if it is not - specified explicitly. - - Parameters - ---------- - evaluate_from : {'parent', 'subnodes'} - """ - assert evaluate_from in ('parent', 'subnodes') - - if self._maxlevel is not None: - return self._maxlevel - elif self.data is not None: - return self.level + dwt_max_level( - min(self.data.shape), self.wavelet) - - if evaluate_from == 'parent': - if self.parent is not None: - return self.parent._evaluate_maxlevel(evaluate_from) - elif evaluate_from == 'subnodes': - for node_name in self.PARTS: - node = getattr(self, node_name, None) - if node is not None: - level = node._evaluate_maxlevel(evaluate_from) - if level is not None: - return level - return None - - @property - def maxlevel(self): - if self._maxlevel is not None: - return self._maxlevel - - # Try getting the maxlevel from parents first - self._maxlevel = self._evaluate_maxlevel(evaluate_from='parent') - - # If not found, check whether it can be evaluated from subnodes - if self._maxlevel is None: - self._maxlevel = self._evaluate_maxlevel(evaluate_from='subnodes') - return self._maxlevel - - @property - def node_name(self): - return self.path[-self.PART_LEN:] - - def decompose(self): - """ - Decompose node data creating DWT coefficients subnodes. - - Performs Discrete Wavelet Transform on the `~BaseNode.data` and - returns transform coefficients. - - Note - ---- - Descends to subnodes and recursively - calls `~BaseNode.reconstruct` on them. - - """ - if self.level < self.maxlevel: - return self._decompose() - else: - raise ValueError("Maximum decomposition level reached.") - - def _decompose(self): - raise NotImplementedError() - - def reconstruct(self, update=False): - """ - Reconstruct node from subnodes. - - Parameters - ---------- - update : bool, optional - If True, then reconstructed data replaces the current - node data (default: False). - - Returns: - - original node data if subnodes do not exist - - IDWT of subnodes otherwise. - """ - if not self.has_any_subnode: - return self.data - return self._reconstruct(update) - - def _reconstruct(self): - raise NotImplementedError() # override this in subclasses - - def get_subnode(self, part, decompose=True): - """ - Returns subnode or None (see `decomposition` flag description). - - Parameters - ---------- - part : - Subnode name - decompose : bool, optional - If the param is True and corresponding subnode does not - exist, the subnode will be created using coefficients - from the DWT decomposition of the current node. - (default: True) - """ - self._validate_node_name(part) - subnode = self._get_node(part) - if subnode is None and decompose and not self.is_empty: - self.decompose() - subnode = self._get_node(part) - return subnode - - def __getitem__(self, path): - """ - Find node represented by the given path. - - Similar to `~BaseNode.get_subnode` method with `decompose=True`, but - can access nodes on any level in the decomposition tree. - - Parameters - ---------- - path : str - String composed of node names. See `Node.node_name` and - `Node2D.node_name` for node naming convention. - - Notes - ----- - If node does not exist yet, it will be created by decomposition of its - parent node. - """ - if isinstance(path, str): - if (self.maxlevel is not None - and len(path) > self.maxlevel * self.PART_LEN): - raise IndexError("Path length is out of range.") - if path: - return self.get_subnode(path[0:self.PART_LEN], True)[ - path[self.PART_LEN:]] - else: - return self - else: - raise TypeError("Invalid path parameter type - expected string but" - " got %s." % type(path)) - - def __setitem__(self, path, data): - """ - Set node or node's data in the decomposition tree. Nodes are - identified by string `path`. - - Parameters - ---------- - path : str - String composed of node names. - data : array or BaseNode subclass. - """ - - if isinstance(path, str): - if ( - self.maxlevel is not None - and len(self.path) + len(path) > self.maxlevel * self.PART_LEN - ): - raise IndexError("Path length out of range.") - if path: - subnode = self.get_subnode(path[0:self.PART_LEN], False) - if subnode is None: - self._create_subnode(path[0:self.PART_LEN], None) - subnode = self.get_subnode(path[0:self.PART_LEN], False) - subnode[path[self.PART_LEN:]] = data - else: - if isinstance(data, BaseNode): - self.data = np.asarray(data.data) - else: - self.data = np.asarray(data) - # convert data to nearest supported dtype - dtype = _check_dtype(data) - if self.data.dtype != dtype: - self.data = self.data.astype(dtype) - else: - raise TypeError("Invalid path parameter type - expected string but" - " got %s." % type(path)) - - def __delitem__(self, path): - """ - Remove node from the tree. - - Parameters - ---------- - path : str - String composed of node names. - """ - node = self[path] - # don't clear node value and subnodes (node may still exist outside - # the tree) - # # node._init_subnodes() - # # node.data = None - parent = node.parent - node.parent = None # TODO - if parent and node.node_name: - parent._delete_node(node.node_name) - - @property - def is_empty(self): - return self.data is None - - @property - def has_any_subnode(self): - for part in self.PARTS: - if self._get_node(part) is not None: # and not .is_empty - return True - return False - - def get_leaf_nodes(self, decompose=False): - """ - Returns leaf nodes. - - Parameters - ---------- - decompose : bool, optional - (default: True) - """ - result = [] - - def collect(node): - if node.level == node.maxlevel and not node.is_empty: - result.append(node) - return False - if not decompose and not node.has_any_subnode: - result.append(node) - return False - return True - self.walk(collect, decompose=decompose) - return result - - def walk(self, func, args=(), kwargs=None, decompose=True): - """ - Traverses the decomposition tree and calls - ``func(node, *args, **kwargs)`` on every node. If `func` returns True, - descending to subnodes will continue. - - Parameters - ---------- - func : callable - Callable accepting `BaseNode` as the first param and - optional positional and keyword arguments - args : - func params - kwargs : - func keyword params - decompose : bool, optional - If True (default), the method will also try to decompose the tree - up to the `maximum level `. - """ - if kwargs is None: - kwargs = {} - if func(self, *args, **kwargs) and self.level < self.maxlevel: - for part in self.PARTS: - subnode = self.get_subnode(part, decompose) - if subnode is not None: - subnode.walk(func, args, kwargs, decompose) - - def walk_depth(self, func, args=(), kwargs=None, decompose=True): - """ - Walk tree and call func on every node starting from the bottom-most - nodes. - - Parameters - ---------- - func : callable - Callable accepting :class:`BaseNode` as the first param and - optional positional and keyword arguments - args : - func params - kwargs : - func keyword params - decompose : bool, optional - (default: False) - """ - if kwargs is None: - kwargs = {} - if self.level < self.maxlevel: - for part in self.PARTS: - subnode = self.get_subnode(part, decompose) - if subnode is not None: - subnode.walk_depth(func, args, kwargs, decompose) - func(self, *args, **kwargs) - - def __str__(self): - return self.path + ": " + str(self.data) - - -class Node(BaseNode): - """ - WaveletPacket tree node. - - Subnodes are called `a` and `d`, just like approximation - and detail coefficients in the Discrete Wavelet Transform. - """ - - A = 'a' - D = 'd' - PARTS = A, D - PART_LEN = 1 - - def _create_subnode(self, part, data=None, overwrite=True): - return self._create_subnode_base(node_cls=Node, part=part, data=data, - overwrite=overwrite) - - def _decompose(self): - """ - - See also - -------- - dwt : for 1D Discrete Wavelet Transform output coefficients. - """ - if self.is_empty: - data_a, data_d = None, None - if self._get_node(self.A) is None: - self._create_subnode(self.A, data_a) - if self._get_node(self.D) is None: - self._create_subnode(self.D, data_d) - else: - data_a, data_d = dwt(self.data, self.wavelet, self.mode) - self._create_subnode(self.A, data_a) - self._create_subnode(self.D, data_d) - return self._get_node(self.A), self._get_node(self.D) - - def _reconstruct(self, update): - data_a, data_d = None, None - node_a, node_d = self._get_node(self.A), self._get_node(self.D) - - if node_a is not None: - data_a = node_a.reconstruct() # TODO: (update) ??? - if node_d is not None: - data_d = node_d.reconstruct() # TODO: (update) ??? - - if data_a is None and data_d is None: - raise ValueError("Node is a leaf node and cannot be reconstructed" - " from subnodes.") - else: - rec = idwt(data_a, data_d, self.wavelet, self.mode) - if update: - self.data = rec - return rec - - -class Node2D(BaseNode): - """ - WaveletPacket tree node. - - Subnodes are called 'a' (LL), 'h' (HL), 'v' (LH) and 'd' (HH), like - approximation and detail coefficients in the 2D Discrete Wavelet Transform - """ - - LL = 'a' - HL = 'h' - LH = 'v' - HH = 'd' - - PARTS = LL, HL, LH, HH - PART_LEN = 1 - - def _create_subnode(self, part, data=None, overwrite=True): - return self._create_subnode_base(node_cls=Node2D, part=part, data=data, - overwrite=overwrite) - - def _decompose(self): - """ - See also - -------- - dwt2 : for 2D Discrete Wavelet Transform output coefficients. - """ - if self.is_empty: - data_ll, data_lh, data_hl, data_hh = None, None, None, None - else: - data_ll, (data_hl, data_lh, data_hh) =\ - dwt2(self.data, self.wavelet, self.mode) - self._create_subnode(self.LL, data_ll) - self._create_subnode(self.LH, data_lh) - self._create_subnode(self.HL, data_hl) - self._create_subnode(self.HH, data_hh) - return (self._get_node(self.LL), self._get_node(self.HL), - self._get_node(self.LH), self._get_node(self.HH)) - - def _reconstruct(self, update): - data_ll, data_lh, data_hl, data_hh = None, None, None, None - - node_ll, node_lh, node_hl, node_hh =\ - self._get_node(self.LL), self._get_node(self.LH),\ - self._get_node(self.HL), self._get_node(self.HH) - - if node_ll is not None: - data_ll = node_ll.reconstruct() - if node_lh is not None: - data_lh = node_lh.reconstruct() - if node_hl is not None: - data_hl = node_hl.reconstruct() - if node_hh is not None: - data_hh = node_hh.reconstruct() - - if (data_ll is None and data_lh is None - and data_hl is None and data_hh is None): - raise ValueError( - "Tree is missing data - all subnodes of `%s` node " - "are None. Cannot reconstruct node." % self.path - ) - else: - coeffs = data_ll, (data_hl, data_lh, data_hh) - rec = idwt2(coeffs, self.wavelet, self.mode) - if update: - self.data = rec - return rec - - def expand_2d_path(self, path): - expanded_paths = { - self.HH: 'hh', - self.HL: 'hl', - self.LH: 'lh', - self.LL: 'll' - } - return (''.join([expanded_paths[p][0] for p in path]), - ''.join([expanded_paths[p][1] for p in path])) - - -class WaveletPacket(Node): - """ - Data structure representing Wavelet Packet decomposition of signal. - - Parameters - ---------- - data : 1D ndarray - Original data (signal) - wavelet : Wavelet object or name string - Wavelet used in DWT decomposition and reconstruction - mode : str, optional - Signal extension mode for the `dwt` and `idwt` decomposition and - reconstruction functions. - maxlevel : int, optional - Maximum level of decomposition. - If None, it will be calculated based on the `wavelet` and `data` - length using `pywt.dwt_max_level`. - """ - def __init__(self, data, wavelet, mode='symmetric', maxlevel=None): - super(WaveletPacket, self).__init__(None, data, "") - - if not isinstance(wavelet, Wavelet): - wavelet = Wavelet(wavelet) - self.wavelet = wavelet - self.mode = mode - - if data is not None: - data = np.asarray(data) - assert data.ndim == 1 - self.data_size = data.shape[0] - if maxlevel is None: - maxlevel = dwt_max_level(self.data_size, self.wavelet) - else: - self.data_size = None - - self._maxlevel = maxlevel - - def reconstruct(self, update=True): - """ - Reconstruct data value using coefficients from subnodes. - - Parameters - ---------- - update : bool, optional - If True (default), then data values will be replaced by - reconstruction values, also in subnodes. - """ - if self.has_any_subnode: - data = super(WaveletPacket, self).reconstruct(update) - if self.data_size is not None and len(data) > self.data_size: - data = data[:self.data_size] - if update: - self.data = data - return data - return self.data # return original data - - def get_level(self, level, order="natural", decompose=True): - """ - Returns all nodes on the specified level. - - Parameters - ---------- - level : int - Specifies decomposition `level` from which the nodes will be - collected. - order : {'natural', 'freq'}, optional - - "natural" - left to right in tree (default) - - "freq" - band ordered - decompose : bool, optional - If set then the method will try to decompose the data up - to the specified `level` (default: True). - - Notes - ----- - If nodes at the given level are missing (i.e. the tree is partially - decomposed) and the `decompose` is set to False, only existing nodes - will be returned. - """ - assert order in ["natural", "freq"] - if level > self.maxlevel: - raise ValueError("The level cannot be greater than the maximum" - " decomposition level value (%d)" % self.maxlevel) - - result = [] - - def collect(node): - if node.level == level: - result.append(node) - return False - return True - - self.walk(collect, decompose=decompose) - if order == "natural": - return result - elif order == "freq": - result = dict((node.path, node) for node in result) - graycode_order = get_graycode_order(level) - return [result[path] for path in graycode_order if path in result] - else: - raise ValueError("Invalid order name - %s." % order) - - -class WaveletPacket2D(Node2D): - """ - Data structure representing 2D Wavelet Packet decomposition of signal. - - Parameters - ---------- - data : 2D ndarray - Data associated with the node. - wavelet : Wavelet object or name string - Wavelet used in DWT decomposition and reconstruction - mode : str, optional - Signal extension mode for the `dwt` and `idwt` decomposition and - reconstruction functions. - maxlevel : int - Maximum level of decomposition. - If None, it will be calculated based on the `wavelet` and `data` - length using `pywt.dwt_max_level`. - """ - def __init__(self, data, wavelet, mode='smooth', maxlevel=None): - super(WaveletPacket2D, self).__init__(None, data, "") - - if not isinstance(wavelet, Wavelet): - wavelet = Wavelet(wavelet) - self.wavelet = wavelet - self.mode = mode - - if data is not None: - data = np.asarray(data) - assert data.ndim == 2 - self.data_size = data.shape - if maxlevel is None: - maxlevel = dwt_max_level(min(self.data_size), self.wavelet) - else: - self.data_size = None - self._maxlevel = maxlevel - - def reconstruct(self, update=True): - """ - Reconstruct data using coefficients from subnodes. - - Parameters - ---------- - update : bool, optional - If True (default) then the coefficients of the current node - and its subnodes will be replaced with values from reconstruction. - """ - if self.has_any_subnode: - data = super(WaveletPacket2D, self).reconstruct(update) - if self.data_size is not None and (data.shape != self.data_size): - data = data[:self.data_size[0], :self.data_size[1]] - if update: - self.data = data - return data - return self.data # return original data - - def get_level(self, level, order="natural", decompose=True): - """ - Returns all nodes from specified level. - - Parameters - ---------- - level : int - Decomposition `level` from which the nodes will be - collected. - order : {'natural', 'freq'}, optional - If `natural` (default) a flat list is returned. - If `freq`, a 2d structure with rows and cols - sorted by corresponding dimension frequency of 2d - coefficient array (adapted from 1d case). - decompose : bool, optional - If set then the method will try to decompose the data up - to the specified `level` (default: True). - """ - assert order in ["natural", "freq"] - if level > self.maxlevel: - raise ValueError("The level cannot be greater than the maximum" - " decomposition level value (%d)" % self.maxlevel) - - result = [] - - def collect(node): - if node.level == level: - result.append(node) - return False - return True - - self.walk(collect, decompose=decompose) - - if order == "freq": - nodes = {} - for (row_path, col_path), node in [ - (self.expand_2d_path(node.path), node) for node in result - ]: - nodes.setdefault(row_path, {})[col_path] = node - graycode_order = get_graycode_order(level, x='l', y='h') - nodes = [nodes[path] for path in graycode_order if path in nodes] - result = [] - for row in nodes: - result.append( - [row[path] for path in graycode_order if path in row] - ) - return result diff --git a/.eggs/PyWavelets-1.0.0-py3.7-linux-x86_64.egg/pywt/data/__init__.py b/.eggs/PyWavelets-1.0.0-py3.7-linux-x86_64.egg/pywt/data/__init__.py deleted file mode 100644 index 9344e3f6..00000000 --- a/.eggs/PyWavelets-1.0.0-py3.7-linux-x86_64.egg/pywt/data/__init__.py +++ /dev/null @@ -1,2 +0,0 @@ -from ._readers import ascent, aero, ecg, camera, nino -from ._wavelab_signals import demo_signal diff --git a/.eggs/PyWavelets-1.0.0-py3.7-linux-x86_64.egg/pywt/data/_readers.py b/.eggs/PyWavelets-1.0.0-py3.7-linux-x86_64.egg/pywt/data/_readers.py deleted file mode 100644 index d9c0b777..00000000 --- a/.eggs/PyWavelets-1.0.0-py3.7-linux-x86_64.egg/pywt/data/_readers.py +++ /dev/null @@ -1,185 +0,0 @@ -import os - -import numpy as np - - -def ascent(): - """ - Get an 8-bit grayscale bit-depth, 512 x 512 derived image for - easy use in demos - - The image is derived from accent-to-the-top.jpg at - http://www.public-domain-image.com/people-public-domain-images-pictures/ - - Parameters - ---------- - None - - Returns - ------- - ascent : ndarray - convenient image to use for testing and demonstration - - Examples - -------- - >>> import pywt.data - >>> ascent = pywt.data.ascent() - >>> ascent.shape == (512, 512) - True - >>> ascent.max() - 255 - - >>> import matplotlib.pyplot as plt - >>> plt.gray() - >>> plt.imshow(ascent) # doctest: +ELLIPSIS - - >>> plt.show() # doctest: +SKIP - - """ - fname = os.path.join(os.path.dirname(__file__), 'ascent.npz') - ascent = np.load(fname)['data'] - return ascent - - -def aero(): - """ - Get an 8-bit grayscale bit-depth, 512 x 512 derived image for - easy use in demos - - Parameters - ---------- - None - - Returns - ------- - aero : ndarray - convenient image to use for testing and demonstration - - Examples - -------- - >>> import pywt.data - >>> aero = pywt.data.ascent() - >>> aero.shape == (512, 512) - True - >>> aero.max() - 255 - - >>> import matplotlib.pyplot as plt - >>> plt.gray() - >>> plt.imshow(aero) # doctest: +ELLIPSIS - - >>> plt.show() # doctest: +SKIP - - """ - fname = os.path.join(os.path.dirname(__file__), 'aero.npz') - aero = np.load(fname)['data'] - return aero - - -def camera(): - """ - Get an 8-bit grayscale bit-depth, 512 x 512 derived image for - easy use in demos - - Parameters - ---------- - None - - Returns - ------- - camera : ndarray - convenient image to use for testing and demonstration - - Examples - -------- - >>> import pywt.data - >>> camera = pywt.data.ascent() - >>> camera.shape == (512, 512) - True - - >>> import matplotlib.pyplot as plt - >>> plt.gray() - >>> plt.imshow(camera) # doctest: +ELLIPSIS - - >>> plt.show() # doctest: +SKIP - - """ - fname = os.path.join(os.path.dirname(__file__), 'camera.npz') - camera = np.load(fname)['data'] - return camera - - -def ecg(): - """ - Get 1024 points of an ECG timeseries. - - Parameters - ---------- - None - - Returns - ------- - ecg : ndarray - convenient timeseries to use for testing and demonstration - - Examples - -------- - >>> import pywt.data - >>> ecg = pywt.data.ecg() - >>> ecg.shape == (1024,) - True - - >>> import matplotlib.pyplot as plt - >>> plt.plot(ecg) # doctest: +ELLIPSIS - [] - >>> plt.show() # doctest: +SKIP - """ - fname = os.path.join(os.path.dirname(__file__), 'ecg.npy') - ecg = np.load(fname) - return ecg - - -def nino(): - """ - This data contains the averaged monthly sea surface temperature in degrees - Celcius of the Pacific Ocean, between 0-10 degrees South and 90-80 degrees West, from 1950 to 2016. - This dataset is in the public domain and was obtained from NOAA. - National Oceanic and Atmospheric Administration's National Weather Service - ERSSTv4 dataset, nino 3, http://www.cpc.ncep.noaa.gov/data/indices/ - - Parameters - ---------- - None - - Returns - ------- - time : ndarray - convenient timeseries to use for testing and demonstration - sst : ndarray - convenient timeseries to use for testing and demonstration - - Examples - -------- - >>> import pywt.data - >>> time, sst = pywt.data.nino() - >>> sst.shape == (264,) - True - - >>> import matplotlib.pyplot as plt - >>> plt.plot(time,sst) # doctest: +ELLIPSIS - [] - >>> plt.show() # doctest: +SKIP - """ - fname = os.path.join(os.path.dirname(__file__), 'sst_nino3.npz') - sst_csv = np.load(fname)['sst_csv'] - # sst_csv = pd.read_csv("http://www.cpc.ncep.noaa.gov/data/indices/ersst4.nino.mth.81-10.ascii", sep=' ', skipinitialspace=True) - # take only full years - n = int(np.floor(sst_csv.shape[0]/12.)*12.) - # Building the mean of three mounth - # the 4. column is nino 3 - sst = np.mean(np.reshape(np.array(sst_csv)[:n, 4], (n//3, -1)), axis=1) - sst = (sst - np.mean(sst)) / np.std(sst, ddof=1) - - dt = 0.25 - time = np.arange(len(sst)) * dt + 1950.0 # construct time array - return time, sst diff --git a/.eggs/PyWavelets-1.0.0-py3.7-linux-x86_64.egg/pywt/data/_wavelab_signals.py b/.eggs/PyWavelets-1.0.0-py3.7-linux-x86_64.egg/pywt/data/_wavelab_signals.py deleted file mode 100644 index 54520631..00000000 --- a/.eggs/PyWavelets-1.0.0-py3.7-linux-x86_64.egg/pywt/data/_wavelab_signals.py +++ /dev/null @@ -1,259 +0,0 @@ -# -*- coding:utf-8 -*- -from __future__ import division - -import numpy as np - -__all__ = ['demo_signal'] - -_implemented_signals = [ - 'Blocks', - 'Bumps', - 'HeaviSine', - 'Doppler', - 'Ramp', - 'HiSine', - 'LoSine', - 'LinChirp', - 'TwoChirp', - 'QuadChirp', - 'MishMash', - 'WernerSorrows', - 'HypChirps', - 'LinChirps', - 'Chirps', - 'Gabor', - 'sineoneoverx', - 'Piece-Regular', - 'Piece-Polynomial', - 'Riemann'] - - -def demo_signal(name='Bumps', n=None): - """Simple 1D wavelet test functions. - - This function can generate a number of common 1D test signals used in - papers by David Donoho and colleagues (e.g. [1]_) as well as the wavelet - book by Stéphane Mallat [2]_. - - Parameters - ---------- - name : {'Blocks', 'Bumps', 'HeaviSine', 'Doppler', ...} - The type of test signal to generate (`name` is case-insensitive). If - `name` is set to `'list'`, a list of the avialable test functions is - returned. - n : int or None - The length of the test signal. This should be provided for all test - signals except `'Gabor'` and `'sineoneoverx'` which have a fixed - length. - - Returns - ------- - f : np.ndarray - Array of length ``n`` corresponding to the specified test signal type. - - References - ---------- - .. [1] D.L. Donoho and I.M. Johnstone. Ideal spatial adaptation by - wavelet shrinkage. Biometrika, vol. 81, pp. 425–455, 1994. - .. [2] S. Mallat. A Wavelet Tour of Signal Processing: The Sparse Way. - Academic Press. 2009. - - Notes - ----- - This function is a partial reimplementation of the `MakeSignal` function - from the [Wavelab](https://statweb.stanford.edu/~wavelab/) toolbox. These - test signals are provided with permission of Dr. Donoho to encourage - reproducible research. - - """ - if name.lower() == 'list': - return _implemented_signals - - if n is not None: - if n < 1 or (n % 1) != 0: - raise ValueError("n must be an integer >= 1") - t = np.arange(1/n, 1 + 1/n, 1/n) - - # The following function types don't allow user-specified `n`. - n_hard_coded = ['gabor', 'sineoneoverx'] - - name = name.lower() - if name in n_hard_coded and n is not None: - raise ValueError( - "Parameter n must be set to None when name is {}".format(name)) - elif n is None and name not in n_hard_coded: - raise ValueError( - "Parameter n must be provided when name is {}".format(name)) - - if name == 'blocks': - t0s = [.1, .13, .15, .23, .25, .4, .44, .65, .76, .78, .81] - hs = [4, -5, 3, -4, 5, -4.2, 2.1, 4.3, -3.1, 2.1, -4.2] - f = 0 - for (t0, h) in zip(t0s, hs): - f += h * (1 + np.sign(t - t0)) / 2 - elif name == 'bumps': - t0s = [.1, .13, .15, .23, .25, .4, .44, .65, .76, .78, .81] - hs = [4, 5, 3, 4, 5, 4.2, 2.1, 4.3, 3.1, 5.1, 4.2] - ws = [.005, .005, .006, .01, .01, .03, .01, .01, .005, .008, .005] - f = 0 - for (t0, h, w) in zip(t0s, hs, ws): - f += h / (1 + np.abs((t - t0) / w))**4 - elif name == 'heavisine': - f = 4 * np.sin(4 * np.pi * t) - np.sign(t - 0.3) - np.sign(0.72 - t) - elif name == 'doppler': - f = np.sqrt(t * (1 - t)) * np.sin(2 * np.pi * 1.05 / (t + 0.05)) - elif name == 'ramp': - f = t - (t >= .37) - elif name == 'hisine': - f = np.sin(np.pi * (n * .6902) * t) - elif name == 'losine': - f = np.sin(np.pi * (n * .3333) * t) - elif name == 'linchirp': - f = np.sin(np.pi * t * ((n * .500) * t)) - elif name == 'twochirp': - f = np.sin(np.pi * t * (n * t)) + np.sin((np.pi / 3) * t * (n * t)) - elif name == 'quadchirp': - f = np.sin((np.pi / 3) * t * (n * t**2)) - elif name == 'mishmash': # QuadChirp + LinChirp + HiSine - f = np.sin((np.pi / 3) * t * (n * t**2)) - f += np.sin(np.pi * (n * .6902) * t) - f += np.sin(np.pi * t * (n * .125 * t)) - elif name == 'wernersorrows': - f = np.sin(np.pi * t * (n / 2 * t**2)) - f = f + np.sin(np.pi * (n * .6902) * t) - f = f + np.sin(np.pi * t * (n * t)) - pos = [.1, .13, .15, .23, .25, .40, .44, .65, .76, .78, .81] - hgt = [4, 5, 3, 4, 5, 4.2, 2.1, 4.3, 3.1, 5.1, 4.2] - wth = [.005, .005, .006, .01, .01, .03, .01, .01, .005, .008, .005] - for p, h, w in zip(pos, hgt, wth): - f += h / (1 + np.abs((t - p) / w))**4 - elif name == 'hypchirps': # Hyperbolic Chirps of Mallat's book - alpha = 15 * n * np.pi / 1024 - beta = 5 * n * np.pi / 1024 - t = np.arange(1.001, n + .001 + 1) / n - f1 = np.zeros(n) - f2 = np.zeros(n) - f1 = np.sin(alpha / (.8 - t)) * (0.1 < t) * (t < 0.68) - f2 = np.sin(beta / (.8 - t)) * (0.1 < t) * (t < 0.75) - m = int(np.round(0.65 * n)) - p = m // 4 - envelope = np.ones(m) # the rinp.sing cutoff function - tmp = np.arange(1, p + 1)-np.ones(p) - envelope[:p] = (1 + np.sin(-np.pi / 2 + tmp / (p - 1) * np.pi)) / 2 - envelope[m-p:m] = envelope[:p][::-1] - env = np.zeros(n) - env[int(np.ceil(n / 10)) - 1:m + int(np.ceil(n / 10)) - 1] = \ - envelope[:m] - f = (f1 + f2) * env - elif name == 'linchirps': # Linear Chirps of Mallat's book - b = 100 * n * np.pi / 1024 - a = 250 * n * np.pi / 1024 - t = np.arange(1, n + 1) / n - A1 = np.sqrt((t - 1 / n) * (1 - t)) - f = A1 * (np.cos(a * t**2) + np.cos(b * t + a * t**2)) - elif name == 'chirps': # Mixture of Chirps of Mallat's book - t = np.arange(1, n + 1)/n * 10 * np.pi - f1 = np.cos(t**2 * n / 1024) - a = 30 * n / 1024 - t = np.arange(1, n + 1)/n * np.pi - f2 = np.cos(a * (t**3)) - f2 = f2[::-1] - ix = np.arange(-n, n + 1) / n * 20 - g = np.exp(-ix**2 * 4 * n / 1024) - i1 = slice(n // 2, n // 2 + n) - i2 = slice(n // 8, n // 8 + n) - j = np.arange(1, n + 1) / n - f3 = g[i1] * np.cos(50 * np.pi * j * n / 1024) - f4 = g[i2] * np.cos(350 * np.pi * j * n / 1024) - f = f1 + f2 + f3 + f4 - envelope = np.ones(n) # the rinp.sing cutoff function - tmp = np.arange(1, n // 8 + 1) - np.ones(n // 8) - envelope[:n // 8] = ( - 1 + np.sin(-np.pi / 2 + tmp / (n / 8 - 1) * np.pi)) / 2 - envelope[7 * n // 8:n] = envelope[:n // 8][::-1] - f = f*envelope - elif name == 'gabor': # two modulated Gabor functions in Mallat's book - n = 512 - t = np.arange(-n, n + 1)*5 / n - j = np.arange(1, n + 1) / n - g = np.exp(-t**2 * 20) - i1 = slice(2*n // 4, 2 * n // 4 + n) - i2 = slice(n // 4, n // 4 + n) - f1 = 3 * g[i1] * np.exp(1j * (n // 16) * np.pi * j) - f2 = 3 * g[i2] * np.exp(1j * (n // 4) * np.pi * j) - f = f1 + f2 - elif name == 'sineoneoverx': # np.sin(1/x) in Mallat's book - n = 1024 - i1 = np.arange(-n + 1, n + 1, dtype=float) - i1[i1 == 0] = 1 / 100 - i1 = i1 / (n - 1) - f = np.sin(1.5 / i1) - f = f[512:1536] - elif name == 'piece-regular': - f = np.zeros(n) - n_12 = int(np.fix(n / 12)) - n_7 = int(np.fix(n / 7)) - n_5 = int(np.fix(n / 5)) - n_3 = int(np.fix(n / 3)) - n_2 = int(np.fix(n / 2)) - n_20 = int(np.fix(n / 20)) - f1 = -15 * demo_signal('bumps', n) - t = np.arange(1, n_12 + 1) / n_12 - f2 = -np.exp(4 * t) - t = np.arange(1, n_7 + 1) / n_7 - f5 = np.exp(4 * t)-np.exp(4) - t = np.arange(1, n_3 + 1) / n_3 - fma = 6 / 40 - f6 = -70 * np.exp(-((t - 0.5) * (t - 0.5)) / (2 * fma**2)) - f[:n_7] = f6[:n_7] - f[n_7:n_5] = 0.5 * f6[n_7:n_5] - f[n_5:n_3] = f6[n_5:n_3] - f[n_3:n_2] = f1[n_3:n_2] - f[n_2:n_2 + n_12] = f2 - f[n_2 + 2 * n_12 - 1:n_2 + n_12 - 1:-1] = f2 - f[n_2 + 2 * n_12 + n_20:n_2 + 2 * n_12 + 3 * n_20] = -np.ones( - n_2 + 2*n_12 + 3*n_20 - n_2 - 2*n_12 - n_20) * 25 - k = n_2 + 2 * n_12 + 3 * n_20 - f[k:k + n_7] = f5 - diff = n - 5 * n_5 - f[5 * n_5:n] = f[diff - 1::-1] - # zero-mean - bias = np.sum(f) / n - f = bias - f - elif name == 'piece-polynomial': - f = np.zeros(n) - n_5 = int(np.fix(n / 5)) - n_10 = int(np.fix(n / 10)) - n_20 = int(np.fix(n / 20)) - t = np.arange(1, n_5 + 1) / n_5 - f1 = 20 * (t**3 + t**2 + 4) - f3 = 40 * (2 * t**3 + t) + 100 - f2 = 10 * t**3 + 45 - f4 = 16 * t**2 + 8 * t + 16 - f5 = 20 * (t + 4) - f6 = np.ones(n_10) * 20 - f[:n_5] = f1 - f[2 * n_5 - 1:n_5 - 1:-1] = f2 - f[2 * n_5:3 * n_5] = f3 - f[3 * n_5:4 * n_5] = f4 - f[4 * n_5:5 * n_5] = f5[n_5::-1] - diff = n - 5*n_5 - f[5 * n_5:n] = f[diff - 1::-1] - f[n_20:n_20 + n_10] = np.ones(n_10) * 10 - f[n - n_10:n + n_20 - n_10] = np.ones(n_20) * 150 - # zero-mean - bias = np.sum(f) / n - f = f - bias - elif name == 'riemann': - # Riemann's Non-differentiable Function - sqn = int(np.round(np.sqrt(n))) - idx = np.arange(1, sqn + 1) - idx *= idx - f = np.zeros_like(t) - f[idx - 1] = 1. / np.arange(1, sqn + 1) - f = np.real(np.fft.ifft(f)) - else: - raise ValueError( - "unknown name: {}. name must be one of: {}".format( - name, _implemented_signals)) - return f diff --git a/.eggs/PyWavelets-1.0.0-py3.7-linux-x86_64.egg/pywt/data/aero.npz b/.eggs/PyWavelets-1.0.0-py3.7-linux-x86_64.egg/pywt/data/aero.npz deleted file mode 100644 index 98cdd2dc..00000000 Binary files a/.eggs/PyWavelets-1.0.0-py3.7-linux-x86_64.egg/pywt/data/aero.npz and /dev/null differ diff --git a/.eggs/PyWavelets-1.0.0-py3.7-linux-x86_64.egg/pywt/data/ascent.npz b/.eggs/PyWavelets-1.0.0-py3.7-linux-x86_64.egg/pywt/data/ascent.npz deleted file mode 100644 index 0230523f..00000000 Binary files a/.eggs/PyWavelets-1.0.0-py3.7-linux-x86_64.egg/pywt/data/ascent.npz and /dev/null differ diff --git a/.eggs/PyWavelets-1.0.0-py3.7-linux-x86_64.egg/pywt/data/camera.npz b/.eggs/PyWavelets-1.0.0-py3.7-linux-x86_64.egg/pywt/data/camera.npz deleted file mode 100644 index def16f42..00000000 Binary files a/.eggs/PyWavelets-1.0.0-py3.7-linux-x86_64.egg/pywt/data/camera.npz and /dev/null differ diff --git a/.eggs/PyWavelets-1.0.0-py3.7-linux-x86_64.egg/pywt/data/create_dat.py b/.eggs/PyWavelets-1.0.0-py3.7-linux-x86_64.egg/pywt/data/create_dat.py deleted file mode 100644 index f000fe4d..00000000 --- a/.eggs/PyWavelets-1.0.0-py3.7-linux-x86_64.egg/pywt/data/create_dat.py +++ /dev/null @@ -1,39 +0,0 @@ -#!/usr/bin/env python - -"""Helper script for creating image .dat files by numpy.save - -Usage: - - python create_dat.py - -Example (to create aero.dat): - - python create_dat.py aero.png aero.dat - -Requires Scipy and PIL. -""" - -from __future__ import print_function - -import sys - -import numpy as np - - -def main(): - from scipy.misc import imread - - if len(sys.argv) != 3: - print(__doc__) - exit() - - image_fname = sys.argv[1] - dat_fname = sys.argv[2] - - data = imread(image_fname) - - np.savez_compressed(dat_fname, data=data) - - -if __name__ == "__main__": - main() diff --git a/.eggs/PyWavelets-1.0.0-py3.7-linux-x86_64.egg/pywt/data/ecg.npy b/.eggs/PyWavelets-1.0.0-py3.7-linux-x86_64.egg/pywt/data/ecg.npy deleted file mode 100644 index 119916b0..00000000 Binary files a/.eggs/PyWavelets-1.0.0-py3.7-linux-x86_64.egg/pywt/data/ecg.npy and /dev/null differ diff --git a/.eggs/PyWavelets-1.0.0-py3.7-linux-x86_64.egg/pywt/data/sst_nino3.npz b/.eggs/PyWavelets-1.0.0-py3.7-linux-x86_64.egg/pywt/data/sst_nino3.npz deleted file mode 100644 index a59f0863..00000000 Binary files a/.eggs/PyWavelets-1.0.0-py3.7-linux-x86_64.egg/pywt/data/sst_nino3.npz and /dev/null differ diff --git a/.eggs/PyWavelets-1.0.0-py3.7-linux-x86_64.egg/pywt/tests/data/cwt_matlabR2015b_result.npz b/.eggs/PyWavelets-1.0.0-py3.7-linux-x86_64.egg/pywt/tests/data/cwt_matlabR2015b_result.npz deleted file mode 100644 index b4389385..00000000 Binary files a/.eggs/PyWavelets-1.0.0-py3.7-linux-x86_64.egg/pywt/tests/data/cwt_matlabR2015b_result.npz and /dev/null differ diff --git a/.eggs/PyWavelets-1.0.0-py3.7-linux-x86_64.egg/pywt/tests/data/dwt_matlabR2012a_result.npz b/.eggs/PyWavelets-1.0.0-py3.7-linux-x86_64.egg/pywt/tests/data/dwt_matlabR2012a_result.npz deleted file mode 100644 index 370728d3..00000000 Binary files a/.eggs/PyWavelets-1.0.0-py3.7-linux-x86_64.egg/pywt/tests/data/dwt_matlabR2012a_result.npz and /dev/null differ diff --git a/.eggs/PyWavelets-1.0.0-py3.7-linux-x86_64.egg/pywt/tests/data/generate_matlab_data.py b/.eggs/PyWavelets-1.0.0-py3.7-linux-x86_64.egg/pywt/tests/data/generate_matlab_data.py deleted file mode 100644 index f0570683..00000000 --- a/.eggs/PyWavelets-1.0.0-py3.7-linux-x86_64.egg/pywt/tests/data/generate_matlab_data.py +++ /dev/null @@ -1,96 +0,0 @@ -""" This script was used to generate dwt_matlabR2012a_result.npz by storing -the outputs from Matlab R2012a. """ - -from __future__ import division, print_function, absolute_import - -import numpy as np -import pywt - -try: - from pymatbridge import Matlab - mlab = Matlab() - _matlab_missing = False -except ImportError: - print("To run Matlab compatibility tests you need to have MathWorks " - "MATLAB, MathWorks Wavelet Toolbox and the pymatbridge Python " - "package installed.") - _matlab_missing = True - -if _matlab_missing: - raise EnvironmentError("Can't generate matlab data files without MATLAB") - -size_set = 'reduced' - -# list of mode names in pywt and matlab -modes = [('zero', 'zpd'), - ('constant', 'sp0'), - ('symmetric', 'sym'), - ('reflect', 'symw'), - ('periodic', 'ppd'), - ('smooth', 'sp1'), - ('periodization', 'per'), - ('antisymmetric', 'asym'), - ('antireflect', 'asymw')] - -families = ('db', 'sym', 'coif', 'bior', 'rbio') -wavelets = sum([pywt.wavelist(name) for name in families], []) - -rstate = np.random.RandomState(1234) -mlab.start() -try: - all_matlab_results = {} - for wavelet in wavelets: - w = pywt.Wavelet(wavelet) - mlab.set_variable('wavelet', wavelet) - if size_set == 'full': - data_sizes = list(range(w.dec_len, 40)) + \ - [100, 200, 500, 1000, 50000] - else: - data_sizes = (w.dec_len, w.dec_len + 1) - for N in data_sizes: - data = rstate.randn(N) - mlab.set_variable('data', data) - for pmode, mmode in modes: - # Matlab result - if np.any((wavelet == np.array(['coif6', 'coif7', 'coif8', 'coif9', 'coif10', 'coif11', 'coif12', 'coif13', 'coif14', 'coif15', 'coif16', 'coif17'])),axis=0): - mlab.set_variable('Lo_D', w.dec_lo) - mlab.set_variable('Hi_D', w.dec_hi) - mlab_code = ("[ma, md] = dwt(data, Lo_D, Hi_D, " - "'mode', '%s');" % mmode) - else: - mlab_code = ("[ma, md] = dwt(data, wavelet, " - "'mode', '%s');" % mmode) - res = mlab.run_code(mlab_code) - if not res['success']: - raise RuntimeError( - "Matlab failed to execute the provided code. " - "Check that the wavelet toolbox is installed.") - # need np.asarray because sometimes the output is type float - ma = np.asarray(mlab.get_variable('ma')) - md = np.asarray(mlab.get_variable('md')) - ma_key = '_'.join([mmode, wavelet, str(N), 'ma']) - md_key = '_'.join([mmode, wavelet, str(N), 'md']) - all_matlab_results[ma_key] = ma - all_matlab_results[md_key] = md - - # Matlab result - mlab.set_variable('Lo_D', w.dec_lo) - mlab.set_variable('Hi_D', w.dec_hi) - mlab_code = ("[ma, md] = dwt(data, Lo_D, Hi_D, " - "'mode', '%s');" % mmode) - res = mlab.run_code(mlab_code) - if not res['success']: - raise RuntimeError( - "Matlab failed to execute the provided code. " - "Check that the wavelet toolbox is installed.") - # need np.asarray because sometimes the output is type float - ma = np.asarray(mlab.get_variable('ma')) - md = np.asarray(mlab.get_variable('md')) - ma_key = '_'.join([mmode, wavelet, str(N), 'ma_pywtCoeffs']) - md_key = '_'.join([mmode, wavelet, str(N), 'md_pywtCoeffs']) - all_matlab_results[ma_key] = ma - all_matlab_results[md_key] = md -finally: - mlab.stop() - -np.savez('dwt_matlabR2012a_result.npz', **all_matlab_results) diff --git a/.eggs/PyWavelets-1.0.0-py3.7-linux-x86_64.egg/pywt/tests/data/generate_matlab_data_cwt.py b/.eggs/PyWavelets-1.0.0-py3.7-linux-x86_64.egg/pywt/tests/data/generate_matlab_data_cwt.py deleted file mode 100644 index d1f771e2..00000000 --- a/.eggs/PyWavelets-1.0.0-py3.7-linux-x86_64.egg/pywt/tests/data/generate_matlab_data_cwt.py +++ /dev/null @@ -1,86 +0,0 @@ -""" This script was used to generate dwt_matlabR2012a_result.npz by storing -the outputs from Matlab R2012a. """ - -from __future__ import division, print_function, absolute_import - -import numpy as np -import pywt - -try: - from pymatbridge import Matlab - mlab = Matlab() - _matlab_missing = False -except ImportError: - print("To run Matlab compatibility tests you need to have MathWorks " - "MATLAB, MathWorks Wavelet Toolbox and the pymatbridge Python " - "package installed.") - _matlab_missing = True - -if _matlab_missing: - raise EnvironmentError("Can't generate matlab data files without MATLAB") - -size_set = 'reduced' - -# list of mode names in pywt and matlab -modes = [('zero', 'zpd'), - ('constant', 'sp0'), - ('symmetric', 'sym'), - ('periodic', 'ppd'), - ('smooth', 'sp1'), - ('periodization', 'per')] - -families = ('gaus', 'mexh', 'morl', 'cgau', 'shan', 'fbsp', 'cmor') -wavelets = sum([pywt.wavelist(name) for name in families], []) - -rstate = np.random.RandomState(1234) -mlab.start() -try: - all_matlab_results = {} - for wavelet in wavelets: - w = pywt.Wavelet(wavelet) - if np.any((wavelet == np.array(['shan', 'cmor'])),axis=0): - mlab.set_variable('wavelet', wavelet+str(w.bandwidth_frequency)+'-'+str(w.center_frequency)) - elif wavelet == 'fbsp': - mlab.set_variable('wavelet', wavelet+str(w.fbsp_order)+'-'+str(w.bandwidth_frequency)+'-'+str(w.center_frequency)) - else: - mlab.set_variable('wavelet', wavelet) - if size_set == 'full': - data_sizes = list(range(100, 101)) + \ - [100, 200, 500, 1000, 50000] - Scales = (1,np.arange(1,3),np.arange(1,4),np.arange(1,5)) - else: - data_sizes = (1000, 1000 + 1) - Scales = (1,np.arange(1,3)) - mlab_code = ("psi = wavefun(wavelet,10)") - res = mlab.run_code(mlab_code) - if not res['success']: - raise RuntimeError( - "Matlab failed to execute the provided code. " - "Check that the wavelet toolbox is installed.") - psi = np.asarray(mlab.get_variable('psi')) - psi_key = '_'.join([wavelet, 'psi']) - all_matlab_results[psi_key] = psi - for N in data_sizes: - data = rstate.randn(N) - mlab.set_variable('data', data) - - # Matlab result - scale_count = 0 - for scales in Scales: - scale_count += 1 - mlab.set_variable('scales', scales) - mlab_code = ("coefs = cwt(data, scales, wavelet)") - res = mlab.run_code(mlab_code) - if not res['success']: - raise RuntimeError( - "Matlab failed to execute the provided code. " - "Check that the wavelet toolbox is installed.") - # need np.asarray because sometimes the output is type float - coefs = np.asarray(mlab.get_variable('coefs')) - coefs_key = '_'.join([str(scale_count), wavelet, str(N), 'coefs']) - all_matlab_results[coefs_key] = coefs - -finally: - mlab.stop() - -np.savez('cwt_matlabR2015b_result.npz', **all_matlab_results) diff --git a/.eggs/PyWavelets-1.0.0-py3.7-linux-x86_64.egg/pywt/tests/data/wavelab_test_signals.npz b/.eggs/PyWavelets-1.0.0-py3.7-linux-x86_64.egg/pywt/tests/data/wavelab_test_signals.npz deleted file mode 100644 index 517c6fca..00000000 Binary files a/.eggs/PyWavelets-1.0.0-py3.7-linux-x86_64.egg/pywt/tests/data/wavelab_test_signals.npz and /dev/null differ diff --git a/.eggs/PyWavelets-1.0.0-py3.7-linux-x86_64.egg/pywt/tests/test__pywt.py b/.eggs/PyWavelets-1.0.0-py3.7-linux-x86_64.egg/pywt/tests/test__pywt.py deleted file mode 100644 index 594125e3..00000000 --- a/.eggs/PyWavelets-1.0.0-py3.7-linux-x86_64.egg/pywt/tests/test__pywt.py +++ /dev/null @@ -1,175 +0,0 @@ -#!/usr/bin/env python - -from __future__ import division, print_function, absolute_import - -import numpy as np -from numpy.testing import (run_module_suite, assert_allclose, assert_, - assert_raises) - -import pywt - - -def test_upcoef_reconstruct(): - data = np.arange(3) - a = pywt.downcoef('a', data, 'haar') - d = pywt.downcoef('d', data, 'haar') - - rec = (pywt.upcoef('a', a, 'haar', take=3) + - pywt.upcoef('d', d, 'haar', take=3)) - assert_allclose(rec, data) - - -def test_downcoef_multilevel(): - rstate = np.random.RandomState(1234) - r = rstate.randn(16) - nlevels = 3 - # calling with level=1 nlevels times - a1 = r.copy() - for i in range(nlevels): - a1 = pywt.downcoef('a', a1, 'haar', level=1) - # call with level=nlevels once - a3 = pywt.downcoef('a', r, 'haar', level=nlevels) - assert_allclose(a1, a3) - - -def test_downcoef_complex(): - rstate = np.random.RandomState(1234) - r = rstate.randn(16) + 1j * rstate.randn(16) - nlevels = 3 - a = pywt.downcoef('a', r, 'haar', level=nlevels) - a_ref = pywt.downcoef('a', r.real, 'haar', level=nlevels) - a_ref = a_ref + 1j * pywt.downcoef('a', r.imag, 'haar', level=nlevels) - assert_allclose(a, a_ref) - - -def test_downcoef_errs(): - # invalid part string (not 'a' or 'd') - assert_raises(ValueError, pywt.downcoef, 'f', np.ones(16), 'haar') - - -def test_compare_downcoef_coeffs(): - rstate = np.random.RandomState(1234) - r = rstate.randn(16) - # compare downcoef against wavedec outputs - for nlevels in [1, 2, 3]: - for wavelet in pywt.wavelist(): - if wavelet in ['cmor', 'shan', 'fbsp']: - # skip these CWT families to avoid warnings - continue - wavelet = pywt.DiscreteContinuousWavelet(wavelet) - if isinstance(wavelet, pywt.Wavelet): - max_level = pywt.dwt_max_level(r.size, wavelet.dec_len) - if nlevels <= max_level: - a = pywt.downcoef('a', r, wavelet, level=nlevels) - d = pywt.downcoef('d', r, wavelet, level=nlevels) - coeffs = pywt.wavedec(r, wavelet, level=nlevels) - assert_allclose(a, coeffs[0]) - assert_allclose(d, coeffs[1]) - - -def test_upcoef_multilevel(): - rstate = np.random.RandomState(1234) - r = rstate.randn(4) - nlevels = 3 - # calling with level=1 nlevels times - a1 = r.copy() - for i in range(nlevels): - a1 = pywt.upcoef('a', a1, 'haar', level=1) - # call with level=nlevels once - a3 = pywt.upcoef('a', r, 'haar', level=nlevels) - assert_allclose(a1, a3) - - -def test_upcoef_complex(): - rstate = np.random.RandomState(1234) - r = rstate.randn(4) + 1j*rstate.randn(4) - nlevels = 3 - a = pywt.upcoef('a', r, 'haar', level=nlevels) - a_ref = pywt.upcoef('a', r.real, 'haar', level=nlevels) - a_ref = a_ref + 1j*pywt.upcoef('a', r.imag, 'haar', level=nlevels) - assert_allclose(a, a_ref) - - -def test_upcoef_errs(): - # invalid part string (not 'a' or 'd') - assert_raises(ValueError, pywt.upcoef, 'f', np.ones(4), 'haar') - - -def test_upcoef_and_downcoef_1d_only(): - # upcoef and downcoef raise a ValueError if data.ndim > 1d - for ndim in [2, 3]: - data = np.ones((8, )*ndim) - assert_raises(ValueError, pywt.downcoef, 'a', data, 'haar') - assert_raises(ValueError, pywt.upcoef, 'a', data, 'haar') - - -def test_wavelet_repr(): - from pywt._extensions import _pywt - wavelet = _pywt.Wavelet('sym8') - - repr_wavelet = eval(wavelet.__repr__()) - - assert_(wavelet.__repr__() == repr_wavelet.__repr__()) - - -def test_dwt_max_level(): - assert_(pywt.dwt_max_level(16, 2) == 4) - assert_(pywt.dwt_max_level(16, 8) == 1) - assert_(pywt.dwt_max_level(16, 9) == 1) - assert_(pywt.dwt_max_level(16, 10) == 0) - assert_(pywt.dwt_max_level(16, np.int8(10)) == 0) - assert_(pywt.dwt_max_level(16, 10.) == 0) - assert_(pywt.dwt_max_level(16, 18) == 0) - - # accepts discrete Wavelet object or string as well - assert_(pywt.dwt_max_level(32, pywt.Wavelet('sym5')) == 1) - assert_(pywt.dwt_max_level(32, 'sym5') == 1) - - # string input that is not a discrete wavelet - assert_raises(ValueError, pywt.dwt_max_level, 16, 'mexh') - - # filter_len must be an integer >= 2 - assert_raises(ValueError, pywt.dwt_max_level, 16, 1) - assert_raises(ValueError, pywt.dwt_max_level, 16, -1) - assert_raises(ValueError, pywt.dwt_max_level, 16, 3.3) - - -def test_ContinuousWavelet_errs(): - assert_raises(ValueError, pywt.ContinuousWavelet, 'qwertz') - - -def test_ContinuousWavelet_repr(): - from pywt._extensions import _pywt - wavelet = _pywt.ContinuousWavelet('gaus2') - - repr_wavelet = eval(wavelet.__repr__()) - - assert_(wavelet.__repr__() == repr_wavelet.__repr__()) - - -def test_wavelist(): - for name in pywt.wavelist(family='coif'): - assert_(name.startswith('coif')) - - assert_('cgau7' in pywt.wavelist(kind='continuous')) - assert_('sym20' in pywt.wavelist(kind='discrete')) - assert_(len(pywt.wavelist(kind='continuous')) + - len(pywt.wavelist(kind='discrete')) == - len(pywt.wavelist(kind='all'))) - - assert_raises(ValueError, pywt.wavelist, kind='foobar') - - -def test_wavelet_errormsgs(): - try: - pywt.Wavelet('gaus1') - except ValueError as e: - assert_(e.args[0].startswith('The `Wavelet` class')) - try: - pywt.Wavelet('cmord') - except ValueError as e: - assert_(e.args[0] == "Invalid wavelet name 'cmord'.") - - -if __name__ == '__main__': - run_module_suite() diff --git a/.eggs/PyWavelets-1.0.0-py3.7-linux-x86_64.egg/pywt/tests/test_concurrent.py b/.eggs/PyWavelets-1.0.0-py3.7-linux-x86_64.egg/pywt/tests/test_concurrent.py deleted file mode 100644 index ebc739ab..00000000 --- a/.eggs/PyWavelets-1.0.0-py3.7-linux-x86_64.egg/pywt/tests/test_concurrent.py +++ /dev/null @@ -1,121 +0,0 @@ -""" -Tests used to verify running PyWavelets transforms in parallel via -concurrent.futures.ThreadPoolExecutor does not raise errors. -""" - -from __future__ import division, print_function, absolute_import - -import sys -import warnings -import multiprocessing -import numpy as np -from functools import partial -from numpy.testing import (dec, run_module_suite, assert_array_equal, - assert_allclose) - -import pywt - -try: - if sys.version_info[0] == 2: - import futures - else: - from concurrent import futures - max_workers = multiprocessing.cpu_count() - futures_available = True -except ImportError: - futures_available = False - - -def _assert_all_coeffs_equal(coefs1, coefs2): - # return True only if all coefficients of SWT or DWT match over all levels - if len(coefs1) != len(coefs2): - return False - for (c1, c2) in zip(coefs1, coefs2): - if isinstance(c1, tuple): - # for swt, swt2, dwt, dwt2, wavedec, wavedec2 - for a1, a2 in zip(c1, c2): - assert_array_equal(a1, a2) - elif isinstance(c1, dict): - # for swtn, dwtn, wavedecn - for k, v in c1.items(): - assert_array_equal(v, c2[k]) - else: - return False - return True - - -@dec.skipif(not futures_available) -def test_concurrent_swt(): - # tests error-free concurrent operation (see gh-288) - # swt on 1D data calls the Cython swt - # other cases call swt_axes - with warnings.catch_warnings(): - # can remove catch_warnings once the swt2 FutureWarning is removed - warnings.simplefilter('ignore', FutureWarning) - for swt_func, x in zip([pywt.swt, pywt.swt2, pywt.swtn], - [np.ones(8), np.eye(16), np.eye(16)]): - transform = partial(swt_func, wavelet='haar', level=3) - for _ in range(10): - arrs = [x.copy() for _ in range(100)] - with futures.ThreadPoolExecutor(max_workers=max_workers) as ex: - results = list(ex.map(transform, arrs)) - - # validate result from one of the concurrent runs - expected_result = transform(x) - _assert_all_coeffs_equal(expected_result, results[-1]) - - -@dec.skipif(not futures_available) -def test_concurrent_wavedec(): - # wavedec on 1D data calls the Cython dwt_single - # other cases call dwt_axis - for wavedec_func, x in zip([pywt.wavedec, pywt.wavedec2, pywt.wavedecn], - [np.ones(8), np.eye(16), np.eye(16)]): - transform = partial(wavedec_func, wavelet='haar', level=1) - for _ in range(10): - arrs = [x.copy() for _ in range(100)] - with futures.ThreadPoolExecutor(max_workers=max_workers) as ex: - results = list(ex.map(transform, arrs)) - - # validate result from one of the concurrent runs - expected_result = transform(x) - _assert_all_coeffs_equal(expected_result, results[-1]) - - -@dec.skipif(not futures_available) -def test_concurrent_dwt(): - # dwt on 1D data calls the Cython dwt_single - # other cases call dwt_axis - for dwt_func, x in zip([pywt.dwt, pywt.dwt2, pywt.dwtn], - [np.ones(8), np.eye(16), np.eye(16)]): - transform = partial(dwt_func, wavelet='haar') - for _ in range(10): - arrs = [x.copy() for _ in range(100)] - with futures.ThreadPoolExecutor(max_workers=max_workers) as ex: - results = list(ex.map(transform, arrs)) - - # validate result from one of the concurrent runs - expected_result = transform(x) - _assert_all_coeffs_equal([expected_result, ], [results[-1], ]) - - -@dec.skipif(not futures_available) -def test_concurrent_cwt(): - atol = rtol = 1e-14 - time, sst = pywt.data.nino() - dt = time[1]-time[0] - transform = partial(pywt.cwt, scales=np.arange(1, 4), wavelet='cmor1.5-1', - sampling_period=dt) - for _ in range(10): - arrs = [sst.copy() for _ in range(50)] - with futures.ThreadPoolExecutor(max_workers=max_workers) as ex: - results = list(ex.map(transform, arrs)) - - # validate result from one of the concurrent runs - expected_result = transform(sst) - for a1, a2 in zip(expected_result, results[-1]): - assert_allclose(a1, a2, atol=atol, rtol=rtol) - - -if __name__ == '__main__': - run_module_suite() diff --git a/.eggs/PyWavelets-1.0.0-py3.7-linux-x86_64.egg/pywt/tests/test_cwt_wavelets.py b/.eggs/PyWavelets-1.0.0-py3.7-linux-x86_64.egg/pywt/tests/test_cwt_wavelets.py deleted file mode 100644 index 017c9e08..00000000 --- a/.eggs/PyWavelets-1.0.0-py3.7-linux-x86_64.egg/pywt/tests/test_cwt_wavelets.py +++ /dev/null @@ -1,376 +0,0 @@ -#!/usr/bin/env python -from __future__ import division, print_function, absolute_import - -from numpy.testing import (run_module_suite, assert_allclose, assert_warns, - assert_almost_equal, assert_raises) -import numpy as np -import pywt - - -def ref_gaus(LB, UB, N, num): - X = np.linspace(LB, UB, N) - F0 = (2./np.pi)**(1./4.)*np.exp(-(X**2)) - if (num == 1): - psi = -2.*X*F0 - elif (num == 2): - psi = -2/(3**(1/2))*(-1 + 2*X**2)*F0 - elif (num == 3): - psi = -4/(15**(1/2))*X*(3 - 2*X**2)*F0 - elif (num == 4): - psi = 4/(105**(1/2))*(3 - 12*X**2 + 4*X**4)*F0 - elif (num == 5): - psi = 8/(3*(105**(1/2)))*X*(-15 + 20*X**2 - 4*X**4)*F0 - elif (num == 6): - psi = -8/(3*(1155**(1/2)))*(-15 + 90*X**2 - 60*X**4 + 8*X**6)*F0 - elif (num == 7): - psi = -16/(3*(15015**(1/2)))*X*(105 - 210*X**2 + 84*X**4 - 8*X**6)*F0 - elif (num == 8): - psi = 16/(45*(1001**(1/2)))*(105 - 840*X**2 + 840*X**4 - - 224*X**6 + 16*X**8)*F0 - return (psi, X) - - -def ref_cgau(LB, UB, N, num): - X = np.linspace(LB, UB, N) - F0 = np.exp(-X**2) - F1 = np.exp(-1j*X) - F2 = (F1*F0)/(np.exp(-1/2)*2**(1/2)*np.pi**(1/2))**(1/2) - if (num == 1): - psi = F2*(-1j - 2*X)*2**(1/2) - elif (num == 2): - psi = 1/3*F2*(-3 + 4j*X + 4*X**2)*6**(1/2) - elif (num == 3): - psi = 1/15*F2*(7j + 18*X - 12j*X**2 - 8*X**3)*30**(1/2) - elif (num == 4): - psi = 1/105*F2*(25 - 56j*X - 72*X**2 + 32j*X**3 + 16*X**4)*210**(1/2) - elif (num == 5): - psi = 1/315*F2*(-81j - 250*X + 280j*X**2 + 240*X**3 - - 80j*X**4 - 32*X**5)*210**(1/2) - elif (num == 6): - psi = 1/3465*F2*(-331 + 972j*X + 1500*X**2 - 1120j*X**3 - 720*X**4 + - 192j*X**5 + 64*X**6)*2310**(1/2) - elif (num == 7): - psi = 1/45045*F2*( - 1303j + 4634*X - 6804j*X**2 - 7000*X**3 + 3920j*X**4 + 2016*X**5 - - 448j*X**6 - 128*X**7)*30030**(1/2) - elif (num == 8): - psi = 1/45045*F2*( - 5937 - 20848j*X - 37072*X**2 + 36288j*X**3 + 28000*X**4 - - 12544j*X**5 - 5376*X**6 + 1024j*X**7 + 256*X**8)*2002**(1/2) - - psi = psi/np.real(np.sqrt(np.real(np.sum(psi*np.conj(psi)))*(X[1] - X[0]))) - return (psi, X) - - -def sinc2(x): - y = np.ones_like(x) - k = np.where(x)[0] - y[k] = np.sin(np.pi*x[k])/(np.pi*x[k]) - return y - - -def ref_shan(LB, UB, N, Fb, Fc): - x = np.linspace(LB, UB, N) - psi = np.sqrt(Fb)*(sinc2(Fb*x)*np.exp(2j*np.pi*Fc*x)) - return (psi, x) - - -def ref_fbsp(LB, UB, N, m, Fb, Fc): - x = np.linspace(LB, UB, N) - psi = np.sqrt(Fb)*((sinc2(Fb*x/m)**m)*np.exp(2j*np.pi*Fc*x)) - return (psi, x) - - -def ref_cmor(LB, UB, N, Fb, Fc): - x = np.linspace(LB, UB, N) - psi = ((np.pi*Fb)**(-0.5))*np.exp(2j*np.pi*Fc*x)*np.exp(-(x**2)/Fb) - return (psi, x) - - -def ref_morl(LB, UB, N): - x = np.linspace(LB, UB, N) - psi = np.exp(-(x**2)/2)*np.cos(5*x) - return (psi, x) - - -def ref_mexh(LB, UB, N): - x = np.linspace(LB, UB, N) - psi = (2/(np.sqrt(3)*np.pi**0.25))*np.exp(-(x**2)/2)*(1 - (x**2)) - return (psi, x) - - -def test_gaus(): - LB = -5 - UB = 5 - N = 1000 - for num in np.arange(1, 9): - [psi, x] = ref_gaus(LB, UB, N, num) - w = pywt.ContinuousWavelet("gaus" + str(num)) - PSI, X = w.wavefun(length=N) - - assert_allclose(np.real(PSI), np.real(psi)) - assert_allclose(np.imag(PSI), np.imag(psi)) - assert_allclose(X, x) - - -def test_cgau(): - LB = -5 - UB = 5 - N = 1000 - for num in np.arange(1, 9): - [psi, x] = ref_cgau(LB, UB, N, num) - w = pywt.ContinuousWavelet("cgau" + str(num)) - PSI, X = w.wavefun(length=N) - - assert_allclose(np.real(PSI), np.real(psi)) - assert_allclose(np.imag(PSI), np.imag(psi)) - assert_allclose(X, x) - - -def test_shan(): - LB = -20 - UB = 20 - N = 1000 - Fb = 1 - Fc = 1.5 - - [psi, x] = ref_shan(LB, UB, N, Fb, Fc) - w = pywt.ContinuousWavelet("shan{}-{}".format(Fb, Fc)) - assert_almost_equal(w.center_frequency, Fc) - assert_almost_equal(w.bandwidth_frequency, Fb) - w.upper_bound = UB - w.lower_bound = LB - PSI, X = w.wavefun(length=N) - - assert_allclose(np.real(PSI), np.real(psi), atol=1e-15) - assert_allclose(np.imag(PSI), np.imag(psi), atol=1e-15) - assert_allclose(X, x, atol=1e-15) - - LB = -20 - UB = 20 - N = 1000 - Fb = 1.5 - Fc = 1 - - [psi, x] = ref_shan(LB, UB, N, Fb, Fc) - w = pywt.ContinuousWavelet("shan{}-{}".format(Fb, Fc)) - assert_almost_equal(w.center_frequency, Fc) - assert_almost_equal(w.bandwidth_frequency, Fb) - w.upper_bound = UB - w.lower_bound = LB - PSI, X = w.wavefun(length=N) - - assert_allclose(np.real(PSI), np.real(psi), atol=1e-15) - assert_allclose(np.imag(PSI), np.imag(psi), atol=1e-15) - assert_allclose(X, x, atol=1e-15) - - -def test_cmor(): - LB = -20 - UB = 20 - N = 1000 - Fb = 1 - Fc = 1.5 - - [psi, x] = ref_cmor(LB, UB, N, Fb, Fc) - w = pywt.ContinuousWavelet("cmor{}-{}".format(Fb, Fc)) - assert_almost_equal(w.center_frequency, Fc) - assert_almost_equal(w.bandwidth_frequency, Fb) - w.upper_bound = UB - w.lower_bound = LB - PSI, X = w.wavefun(length=N) - - assert_allclose(np.real(PSI), np.real(psi), atol=1e-15) - assert_allclose(np.imag(PSI), np.imag(psi), atol=1e-15) - assert_allclose(X, x, atol=1e-15) - - LB = -20 - UB = 20 - N = 1000 - Fb = 1.5 - Fc = 1 - - [psi, x] = ref_cmor(LB, UB, N, Fb, Fc) - w = pywt.ContinuousWavelet("cmor{}-{}".format(Fb, Fc)) - assert_almost_equal(w.center_frequency, Fc) - assert_almost_equal(w.bandwidth_frequency, Fb) - w.upper_bound = UB - w.lower_bound = LB - PSI, X = w.wavefun(length=N) - - assert_allclose(np.real(PSI), np.real(psi), atol=1e-15) - assert_allclose(np.imag(PSI), np.imag(psi), atol=1e-15) - assert_allclose(X, x, atol=1e-15) - - -def test_fbsp(): - LB = -20 - UB = 20 - N = 1000 - M = 2 - Fb = 1 - Fc = 1.5 - - [psi, x] = ref_fbsp(LB, UB, N, M, Fb, Fc) - - w = pywt.ContinuousWavelet("fbsp{}-{}-{}".format(M, Fb, Fc)) - assert_almost_equal(w.center_frequency, Fc) - assert_almost_equal(w.bandwidth_frequency, Fb) - w.fbsp_order = M - w.upper_bound = UB - w.lower_bound = LB - PSI, X = w.wavefun(length=N) - - assert_allclose(np.real(PSI), np.real(psi), atol=1e-15) - assert_allclose(np.imag(PSI), np.imag(psi), atol=1e-15) - assert_allclose(X, x, atol=1e-15) - - LB = -20 - UB = 20 - N = 1000 - M = 2 - Fb = 1.5 - Fc = 1 - - [psi, x] = ref_fbsp(LB, UB, N, M, Fb, Fc) - w = pywt.ContinuousWavelet("fbsp{}-{}-{}".format(M, Fb, Fc)) - assert_almost_equal(w.center_frequency, Fc) - assert_almost_equal(w.bandwidth_frequency, Fb) - w.fbsp_order = M - w.upper_bound = UB - w.lower_bound = LB - PSI, X = w.wavefun(length=N) - - assert_allclose(np.real(PSI), np.real(psi), atol=1e-15) - assert_allclose(np.imag(PSI), np.imag(psi), atol=1e-15) - assert_allclose(X, x, atol=1e-15) - - LB = -20 - UB = 20 - N = 1000 - M = 3 - Fb = 1.5 - Fc = 1.2 - - [psi, x] = ref_fbsp(LB, UB, N, M, Fb, Fc) - w = pywt.ContinuousWavelet("fbsp{}-{}-{}".format(M, Fb, Fc)) - assert_almost_equal(w.center_frequency, Fc) - assert_almost_equal(w.bandwidth_frequency, Fb) - w.fbsp_order = M - w.upper_bound = UB - w.lower_bound = LB - PSI, X = w.wavefun(length=N) - # TODO: investigate why atol = 1e-5 is necessary - assert_allclose(np.real(PSI), np.real(psi), atol=1e-5) - assert_allclose(np.imag(PSI), np.imag(psi), atol=1e-5) - assert_allclose(X, x, atol=1e-15) - - -def test_morl(): - LB = -5 - UB = 5 - N = 1000 - - [psi, x] = ref_morl(LB, UB, N) - w = pywt.ContinuousWavelet("morl") - w.upper_bound = UB - w.lower_bound = LB - PSI, X = w.wavefun(length=N) - - assert_allclose(np.real(PSI), np.real(psi)) - assert_allclose(np.imag(PSI), np.imag(psi)) - assert_allclose(X, x) - - -def test_mexh(): - LB = -5 - UB = 5 - N = 1000 - - [psi, x] = ref_mexh(LB, UB, N) - w = pywt.ContinuousWavelet("mexh") - w.upper_bound = UB - w.lower_bound = LB - PSI, X = w.wavefun(length=N) - - assert_allclose(np.real(PSI), np.real(psi)) - assert_allclose(np.imag(PSI), np.imag(psi)) - assert_allclose(X, x) - - LB = -5 - UB = 5 - N = 1001 - - [psi, x] = ref_mexh(LB, UB, N) - w = pywt.ContinuousWavelet("mexh") - w.upper_bound = UB - w.lower_bound = LB - PSI, X = w.wavefun(length=N) - - assert_allclose(np.real(PSI), np.real(psi)) - assert_allclose(np.imag(PSI), np.imag(psi)) - assert_allclose(X, x) - - -def test_cwt_parameters_in_names(): - - for func in [pywt.ContinuousWavelet, pywt.DiscreteContinuousWavelet]: - for name in ['fbsp', 'cmor', 'shan']: - # additional parameters should be specified within the name - assert_warns(FutureWarning, func, name) - - for name in ['cmor', 'shan']: - # valid names - func(name + '1.5-1.0') - func(name + '1-4') - - # invalid names - assert_raises(ValueError, func, name + '1.0') - assert_raises(ValueError, func, name + 'B-C') - assert_raises(ValueError, func, name + '1.0-1.0-1.0') - - # valid names - func('fbsp1-1.5-1.0') - func('fbsp1.0-1.5-1') - func('fbsp2-5-1') - - # invalid name (non-integer order) - assert_raises(ValueError, func, 'fbsp1.5-1-1') - assert_raises(ValueError, func, 'fbspM-B-C') - - # invalid name (too few or too many params) - assert_raises(ValueError, func, 'fbsp1.0') - assert_raises(ValueError, func, 'fbsp1.0-0.4') - assert_raises(ValueError, func, 'fbsp1-1-1-1') - - -def test_cwt_complex(): - for dtype in [np.float32, np.float64]: - time, sst = pywt.data.nino() - sst = np.asarray(sst, dtype=dtype) - dt = time[1] - time[0] - wavelet = 'cmor1.5-1.0' - scales = np.arange(1, 32) - - # real-valued tranfsorm - [cfs, f] = pywt.cwt(sst, scales, wavelet, dt) - - # complex-valued tranfsorm equals sum of the transforms of the real and - # imaginary components - [cfs_complex, f] = pywt.cwt(sst + 1j*sst, scales, wavelet, dt) - assert_almost_equal(cfs + 1j*cfs, cfs_complex) - - -def test_cwt_small_scales(): - data = np.zeros(32) - - # A scale of 0.1 was chosen specifically to give a filter of length 2 for - # mexh. This corner case should not raise an error. - cfs, f = pywt.cwt(data, scales=0.1, wavelet='mexh') - assert_allclose(cfs, np.zeros_like(cfs)) - - # extremely short scale factors raise a ValueError - assert_raises(ValueError, pywt.cwt, data, scales=0.01, wavelet='mexh') - -if __name__ == '__main__': - run_module_suite() diff --git a/.eggs/PyWavelets-1.0.0-py3.7-linux-x86_64.egg/pywt/tests/test_data.py b/.eggs/PyWavelets-1.0.0-py3.7-linux-x86_64.egg/pywt/tests/test_data.py deleted file mode 100644 index 36bef07a..00000000 --- a/.eggs/PyWavelets-1.0.0-py3.7-linux-x86_64.egg/pywt/tests/test_data.py +++ /dev/null @@ -1,82 +0,0 @@ -import os -import numpy as np -from numpy.testing import (assert_allclose, assert_raises, assert_, - run_module_suite) - -import pywt.data - -data_dir = os.path.join(os.path.dirname(__file__), 'data') -wavelab_data_file = os.path.join(data_dir, 'wavelab_test_signals.npz') -wavelab_result_dict = np.load(wavelab_data_file) - - -def test_data_aero(): - aero = pywt.data.aero() - - ref = np.array([[178, 178, 179], - [170, 173, 171], - [185, 174, 171]]) - - assert_allclose(aero[:3, :3], ref) - - -def test_data_ascent(): - ascent = pywt.data.ascent() - - ref = np.array([[83, 83, 83], - [82, 82, 83], - [80, 81, 83]]) - - assert_allclose(ascent[:3, :3], ref) - - -def test_data_camera(): - ascent = pywt.data.camera() - - ref = np.array([[156, 157, 160], - [156, 157, 159], - [158, 157, 156]]) - - assert_allclose(ascent[:3, :3], ref) - - -def test_data_ecg(): - ecg = pywt.data.ecg() - - ref = np.array([-86, -87, -87]) - - assert_allclose(ecg[:3], ref) - - -def test_wavelab_signals(): - """Comparison with results generated using WaveLab""" - rtol = atol = 1e-12 - - # get a list of the available signals - available_signals = pywt.data.demo_signal('list') - assert_('Doppler' in available_signals) - - for signal in available_signals: - # reference dictionary has lowercase names for the keys - key = signal.replace('-', '_').lower() - val = wavelab_result_dict[key] - if key in ['gabor', 'sineoneoverx']: - # these functions do not allow a size to be provided - assert_allclose(val, pywt.data.demo_signal(signal), - rtol=rtol, atol=atol) - assert_raises(ValueError, pywt.data.demo_signal, key, val.size) - else: - assert_allclose(val, pywt.data.demo_signal(signal, val.size), - rtol=rtol, atol=atol) - # these functions require a size to be provided - assert_raises(ValueError, pywt.data.demo_signal, key) - - # ValueError on unrecognized signal type - assert_raises(ValueError, pywt.data.demo_signal, 'unknown_signal', 512) - - # ValueError on invalid length - assert_raises(ValueError, pywt.data.demo_signal, 'Doppler', 0) - - -if __name__ == '__main__': - run_module_suite() diff --git a/.eggs/PyWavelets-1.0.0-py3.7-linux-x86_64.egg/pywt/tests/test_deprecations.py b/.eggs/PyWavelets-1.0.0-py3.7-linux-x86_64.egg/pywt/tests/test_deprecations.py deleted file mode 100644 index b4868efa..00000000 --- a/.eggs/PyWavelets-1.0.0-py3.7-linux-x86_64.egg/pywt/tests/test_deprecations.py +++ /dev/null @@ -1,93 +0,0 @@ -import warnings - -import numpy as np -from numpy.testing import assert_warns, run_module_suite, assert_array_equal - -import pywt - - -def test_intwave_deprecation(): - wavelet = pywt.Wavelet('db3') - assert_warns(DeprecationWarning, pywt.intwave, wavelet) - - -def test_centrfrq_deprecation(): - wavelet = pywt.Wavelet('db3') - assert_warns(DeprecationWarning, pywt.centrfrq, wavelet) - - -def test_scal2frq_deprecation(): - wavelet = pywt.Wavelet('db3') - assert_warns(DeprecationWarning, pywt.scal2frq, wavelet, 1) - - -def test_orthfilt_deprecation(): - assert_warns(DeprecationWarning, pywt.orthfilt, range(6)) - - -def test_integrate_wave_tuple(): - sig = [0, 1, 2, 3] - xgrid = [0, 1, 2, 3] - assert_warns(DeprecationWarning, pywt.integrate_wavelet, (sig, xgrid)) - - -old_modes = ['zpd', - 'cpd', - 'sym', - 'ppd', - 'sp1', - 'per', - ] - - -def test_MODES_from_object_deprecation(): - for mode in old_modes: - assert_warns(DeprecationWarning, pywt.Modes.from_object, mode) - - -def test_MODES_attributes_deprecation(): - def get_mode(Modes, name): - return getattr(Modes, name) - - for mode in old_modes: - assert_warns(DeprecationWarning, get_mode, pywt.Modes, mode) - - -def test_MODES_deprecation_new(): - def use_MODES_new(): - return pywt.MODES.symmetric - - assert_warns(DeprecationWarning, use_MODES_new) - - -def test_MODES_deprecation_old(): - def use_MODES_old(): - return pywt.MODES.sym - - assert_warns(DeprecationWarning, use_MODES_old) - - -def test_MODES_deprecation_getattr(): - def use_MODES_new(): - return getattr(pywt.MODES, 'symmetric') - - assert_warns(DeprecationWarning, use_MODES_new) - - -def test_mode_equivalence(): - old_new = [('zpd', 'zero'), - ('cpd', 'constant'), - ('sym', 'symmetric'), - ('ppd', 'periodic'), - ('sp1', 'smooth'), - ('per', 'periodization')] - x = np.arange(8.) - with warnings.catch_warnings(): - warnings.simplefilter('ignore', DeprecationWarning) - for old, new in old_new: - assert_array_equal(pywt.dwt(x, 'db2', mode=old), - pywt.dwt(x, 'db2', mode=new)) - - -if __name__ == '__main__': - run_module_suite() diff --git a/.eggs/PyWavelets-1.0.0-py3.7-linux-x86_64.egg/pywt/tests/test_doc.py b/.eggs/PyWavelets-1.0.0-py3.7-linux-x86_64.egg/pywt/tests/test_doc.py deleted file mode 100644 index e8590009..00000000 --- a/.eggs/PyWavelets-1.0.0-py3.7-linux-x86_64.egg/pywt/tests/test_doc.py +++ /dev/null @@ -1,20 +0,0 @@ -from __future__ import division, print_function, absolute_import - -import doctest -import glob -import os -import unittest - - -pdir = os.path.pardir -docs_base = os.path.abspath(os.path.join(os.path.dirname(__file__), - pdir, pdir, "doc", "source")) - -files = glob.glob(os.path.join(docs_base, "*.rst")) + \ - glob.glob(os.path.join(docs_base, "*", "*.rst")) - -suite = doctest.DocFileSuite(*files, module_relative=False, encoding="utf-8") - - -if __name__ == "__main__": - unittest.TextTestRunner().run(suite) diff --git a/.eggs/PyWavelets-1.0.0-py3.7-linux-x86_64.egg/pywt/tests/test_dwt_idwt.py b/.eggs/PyWavelets-1.0.0-py3.7-linux-x86_64.egg/pywt/tests/test_dwt_idwt.py deleted file mode 100644 index fe33621d..00000000 --- a/.eggs/PyWavelets-1.0.0-py3.7-linux-x86_64.egg/pywt/tests/test_dwt_idwt.py +++ /dev/null @@ -1,215 +0,0 @@ -#!/usr/bin/env python -from __future__ import division, print_function, absolute_import - -import numpy as np -from numpy.testing import (run_module_suite, assert_allclose, assert_, - assert_raises) - -import pywt - -# Check that float32, float64, complex64, complex128 are preserved. -# Other real types get converted to float64. -# complex256 gets converted to complex128 -dtypes_in = [np.int8, np.float16, np.float32, np.float64, np.complex64, - np.complex128] -dtypes_out = [np.float64, np.float32, np.float32, np.float64, np.complex64, - np.complex128] - -# test complex256 as well if it is available -try: - dtypes_in += [np.complex256, ] - dtypes_out += [np.complex128, ] -except AttributeError: - pass - - -def test_dwt_idwt_basic(): - x = [3, 7, 1, 1, -2, 5, 4, 6] - cA, cD = pywt.dwt(x, 'db2') - cA_expect = [5.65685425, 7.39923721, 0.22414387, 3.33677403, 7.77817459] - cD_expect = [-2.44948974, -1.60368225, -4.44140056, -0.41361256, - 1.22474487] - assert_allclose(cA, cA_expect) - assert_allclose(cD, cD_expect) - - x_roundtrip = pywt.idwt(cA, cD, 'db2') - assert_allclose(x_roundtrip, x, rtol=1e-10) - - # mismatched dtypes OK - x_roundtrip2 = pywt.idwt(cA.astype(np.float64), cD.astype(np.float32), - 'db2') - assert_allclose(x_roundtrip2, x, rtol=1e-7, atol=1e-7) - assert_(x_roundtrip.dtype == np.float64) - - -def test_dwt_idwt_dtypes(): - wavelet = pywt.Wavelet('haar') - for dt_in, dt_out in zip(dtypes_in, dtypes_out): - x = np.ones(4, dtype=dt_in) - errmsg = "wrong dtype returned for {0} input".format(dt_in) - - cA, cD = pywt.dwt(x, wavelet) - assert_(cA.dtype == cD.dtype == dt_out, "dwt: " + errmsg) - - x_roundtrip = pywt.idwt(cA, cD, wavelet) - assert_(x_roundtrip.dtype == dt_out, "idwt: " + errmsg) - - -def test_dwt_idwt_basic_complex(): - x = np.asarray([3, 7, 1, 1, -2, 5, 4, 6]) - x = x + 0.5j*x - cA, cD = pywt.dwt(x, 'db2') - cA_expect = np.asarray([5.65685425, 7.39923721, 0.22414387, 3.33677403, - 7.77817459]) - cA_expect = cA_expect + 0.5j*cA_expect - cD_expect = np.asarray([-2.44948974, -1.60368225, -4.44140056, -0.41361256, - 1.22474487]) - cD_expect = cD_expect + 0.5j*cD_expect - assert_allclose(cA, cA_expect) - assert_allclose(cD, cD_expect) - - x_roundtrip = pywt.idwt(cA, cD, 'db2') - assert_allclose(x_roundtrip, x, rtol=1e-10) - - -def test_dwt_idwt_partial_complex(): - x = np.asarray([3, 7, 1, 1, -2, 5, 4, 6]) - x = x + 0.5j*x - - cA, cD = pywt.dwt(x, 'haar') - cA_rec_expect = np.array([5.0+2.5j, 5.0+2.5j, 1.0+0.5j, 1.0+0.5j, - 1.5+0.75j, 1.5+0.75j, 5.0+2.5j, 5.0+2.5j]) - cA_rec = pywt.idwt(cA, None, 'haar') - assert_allclose(cA_rec, cA_rec_expect) - - cD_rec_expect = np.array([-2.0-1.0j, 2.0+1.0j, 0.0+0.0j, 0.0+0.0j, - -3.5-1.75j, 3.5+1.75j, -1.0-0.5j, 1.0+0.5j]) - cD_rec = pywt.idwt(None, cD, 'haar') - assert_allclose(cD_rec, cD_rec_expect) - - assert_allclose(cA_rec + cD_rec, x) - - -def test_dwt_wavelet_kwd(): - x = np.array([3, 7, 1, 1, -2, 5, 4, 6]) - w = pywt.Wavelet('sym3') - cA, cD = pywt.dwt(x, wavelet=w, mode='constant') - cA_expect = [4.38354585, 3.80302657, 7.31813271, -0.58565539, 4.09727044, - 7.81994027] - cD_expect = [-1.33068221, -2.78795192, -3.16825651, -0.67715519, - -0.09722957, -0.07045258] - assert_allclose(cA, cA_expect) - assert_allclose(cD, cD_expect) - - -def test_dwt_coeff_len(): - x = np.array([3, 7, 1, 1, -2, 5, 4, 6]) - w = pywt.Wavelet('sym3') - ln_modes = [pywt.dwt_coeff_len(len(x), w.dec_len, mode) for mode in - pywt.Modes.modes] - - expected_result = [6, ] * len(pywt.Modes.modes) - expected_result[pywt.Modes.modes.index('periodization')] = 4 - - assert_allclose(ln_modes, expected_result) - ln_modes = [pywt.dwt_coeff_len(len(x), w, mode) for mode in - pywt.Modes.modes] - assert_allclose(ln_modes, expected_result) - - -def test_idwt_none_input(): - # None input equals arrays of zeros of the right length - res1 = pywt.idwt([1, 2, 0, 1], None, 'db2', 'symmetric') - res2 = pywt.idwt([1, 2, 0, 1], [0, 0, 0, 0], 'db2', 'symmetric') - assert_allclose(res1, res2, rtol=1e-15, atol=1e-15) - - res1 = pywt.idwt(None, [1, 2, 0, 1], 'db2', 'symmetric') - res2 = pywt.idwt([0, 0, 0, 0], [1, 2, 0, 1], 'db2', 'symmetric') - assert_allclose(res1, res2, rtol=1e-15, atol=1e-15) - - # Only one argument at a time can be None - assert_raises(ValueError, pywt.idwt, None, None, 'db2', 'symmetric') - - -def test_idwt_invalid_input(): - # Too short, min length is 4 for 'db4': - assert_raises(ValueError, pywt.idwt, [1, 2, 4], [4, 1, 3], 'db4', 'symmetric') - - -def test_dwt_single_axis(): - x = [[3, 7, 1, 1], - [-2, 5, 4, 6]] - - cA, cD = pywt.dwt(x, 'db2', axis=-1) - - cA0, cD0 = pywt.dwt(x[0], 'db2') - cA1, cD1 = pywt.dwt(x[1], 'db2') - - assert_allclose(cA[0], cA0) - assert_allclose(cA[1], cA1) - - assert_allclose(cD[0], cD0) - assert_allclose(cD[1], cD1) - - -def test_idwt_single_axis(): - x = [[3, 7, 1, 1], - [-2, 5, 4, 6]] - - x = np.asarray(x) - x = x + 1j*x # test with complex data - cA, cD = pywt.dwt(x, 'db2', axis=-1) - - x0 = pywt.idwt(cA[0], cD[0], 'db2', axis=-1) - x1 = pywt.idwt(cA[1], cD[1], 'db2', axis=-1) - - assert_allclose(x[0], x0) - assert_allclose(x[1], x1) - - -def test_dwt_axis_arg(): - x = [[3, 7, 1, 1], - [-2, 5, 4, 6]] - - cA_, cD_ = pywt.dwt(x, 'db2', axis=-1) - cA, cD = pywt.dwt(x, 'db2', axis=1) - - assert_allclose(cA_, cA) - assert_allclose(cD_, cD) - - -def test_idwt_axis_arg(): - x = [[3, 7, 1, 1], - [-2, 5, 4, 6]] - - cA, cD = pywt.dwt(x, 'db2', axis=1) - - x_ = pywt.idwt(cA, cD, 'db2', axis=-1) - x = pywt.idwt(cA, cD, 'db2', axis=1) - - assert_allclose(x_, x) - - -def test_dwt_idwt_axis_excess(): - x = [[3, 7, 1, 1], - [-2, 5, 4, 6]] - # can't transform over axes that aren't there - assert_raises(ValueError, - pywt.dwt, x, 'db2', 'symmetric', axis=2) - - assert_raises(ValueError, - pywt.idwt, [1, 2, 4], [4, 1, 3], 'db2', 'symmetric', axis=1) - - -def test_error_on_continuous_wavelet(): - # A ValueError is raised if a Continuous wavelet is selected - data = np.ones((32, )) - for cwave in ['morl', pywt.DiscreteContinuousWavelet('morl')]: - assert_raises(ValueError, pywt.dwt, data, cwave) - - cA, cD = pywt.dwt(data, 'db1') - assert_raises(ValueError, pywt.idwt, cA, cD, cwave) - - -if __name__ == '__main__': - run_module_suite() diff --git a/.eggs/PyWavelets-1.0.0-py3.7-linux-x86_64.egg/pywt/tests/test_functions.py b/.eggs/PyWavelets-1.0.0-py3.7-linux-x86_64.egg/pywt/tests/test_functions.py deleted file mode 100644 index f60905b6..00000000 --- a/.eggs/PyWavelets-1.0.0-py3.7-linux-x86_64.egg/pywt/tests/test_functions.py +++ /dev/null @@ -1,43 +0,0 @@ -#!/usr/bin/env python -from __future__ import division, print_function, absolute_import - -from numpy.testing import (run_module_suite, assert_almost_equal, - assert_allclose) - -import pywt - - -def test_centrfreq(): - # db1 is Haar function, frequency=1 - w = pywt.Wavelet('db1') - expected = 1 - result = pywt.central_frequency(w, precision=12) - assert_almost_equal(result, expected, decimal=3) - # db2, frequency=2/3 - w = pywt.Wavelet('db2') - expected = 2/3. - result = pywt.central_frequency(w, precision=12) - assert_almost_equal(result, expected) - - -def test_scal2frq_scale(): - scale = 2 - w = pywt.Wavelet('db1') - expected = 1. / scale - result = pywt.scale2frequency(w, scale, precision=12) - assert_almost_equal(result, expected, decimal=3) - - -def test_intwave_orthogonal(): - w = pywt.Wavelet('db1') - int_psi, x = pywt.integrate_wavelet(w, precision=12) - ix = x < 0.5 - # For x < 0.5, the integral is equal to x - assert_allclose(int_psi[ix], x[ix]) - # For x > 0.5, the integral is equal to (1 - x) - # Ignore last point here, there x > 1 and something goes wrong - assert_allclose(int_psi[~ix][:-1], 1 - x[~ix][:-1], atol=1e-10) - - -if __name__ == '__main__': - run_module_suite() diff --git a/.eggs/PyWavelets-1.0.0-py3.7-linux-x86_64.egg/pywt/tests/test_matlab_compatibility.py b/.eggs/PyWavelets-1.0.0-py3.7-linux-x86_64.egg/pywt/tests/test_matlab_compatibility.py deleted file mode 100644 index b28c56e6..00000000 --- a/.eggs/PyWavelets-1.0.0-py3.7-linux-x86_64.egg/pywt/tests/test_matlab_compatibility.py +++ /dev/null @@ -1,183 +0,0 @@ -""" -Test used to verify PyWavelets Discrete Wavelet Transform computation -accuracy against MathWorks Wavelet Toolbox. -""" - -from __future__ import division, print_function, absolute_import - -import os -import numpy as np -from numpy.testing import assert_, dec, run_module_suite - -import pywt - -if 'PYWT_XSLOW' in os.environ: - # Run a more comprehensive set of problem sizes. This could take more than - # an hour to complete. - size_set = 'full' - use_precomputed = False -else: - size_set = 'reduced' - use_precomputed = True - -if use_precomputed: - data_dir = os.path.join(os.path.dirname(__file__), 'data') - matlab_data_file = os.path.join(data_dir, 'dwt_matlabR2012a_result.npz') - matlab_result_dict = np.load(matlab_data_file) -else: - try: - from pymatbridge import Matlab - mlab = Matlab() - _matlab_missing = False - except ImportError: - print("To run Matlab compatibility tests you need to have MathWorks " - "MATLAB, MathWorks Wavelet Toolbox and the pymatbridge Python " - "package installed.") - _matlab_missing = True - -# list of mode names in pywt and matlab -modes = [('zero', 'zpd'), - ('constant', 'sp0'), - ('symmetric', 'sym'), - ('reflect', 'symw'), - ('periodic', 'ppd'), - ('smooth', 'sp1'), - ('periodization', 'per'), - # TODO: Now have implemented asymmetric modes too. - # Would be nice to update the Matlab data to test these as well. - ('antisymmetric', 'asym'), - ('antireflect', 'asymw'), - ] - -families = ('db', 'sym', 'coif', 'bior', 'rbio') -wavelets = sum([pywt.wavelist(name) for name in families], []) - - -def _get_data_sizes(w): - """ Return the sizes to test for wavelet w. """ - if size_set == 'full': - data_sizes = list(range(w.dec_len, 40)) + \ - [100, 200, 500, 1000, 50000] - else: - data_sizes = (w.dec_len, w.dec_len + 1) - return data_sizes - - -@dec.skipif(use_precomputed or _matlab_missing) -@dec.slow -def test_accuracy_pymatbridge(): - rstate = np.random.RandomState(1234) - # max RMSE (was 1.0e-10, is reduced to 5.0e-5 due to different coefficents) - epsilon = 5.0e-5 - epsilon_pywt_coeffs = 1.0e-10 - mlab.start() - try: - for wavelet in wavelets: - w = pywt.Wavelet(wavelet) - mlab.set_variable('wavelet', wavelet) - for N in _get_data_sizes(w): - data = rstate.randn(N) - mlab.set_variable('data', data) - for pmode, mmode in modes: - ma, md = _compute_matlab_result(data, wavelet, mmode) - yield _check_accuracy, data, w, pmode, ma, md, wavelet, epsilon - ma, md = _load_matlab_result_pywt_coeffs(data, wavelet, mmode) - yield _check_accuracy, data, w, pmode, ma, md, wavelet, epsilon_pywt_coeffs - - finally: - mlab.stop() - - -@dec.skipif(not use_precomputed) -@dec.slow -def test_accuracy_precomputed(): - # Keep this specific random seed to match the precomputed Matlab result. - rstate = np.random.RandomState(1234) - # max RMSE (was 1.0e-10, is reduced to 5.0e-5 due to different coefficents) - epsilon = 5.0e-5 - epsilon_pywt_coeffs = 1.0e-10 - for wavelet in wavelets: - w = pywt.Wavelet(wavelet) - for N in _get_data_sizes(w): - data = rstate.randn(N) - for pmode, mmode in modes: - ma, md = _load_matlab_result(data, wavelet, mmode) - yield _check_accuracy, data, w, pmode, ma, md, wavelet, epsilon - ma, md = _load_matlab_result_pywt_coeffs(data, wavelet, mmode) - yield _check_accuracy, data, w, pmode, ma, md, wavelet, epsilon_pywt_coeffs - - -def _compute_matlab_result(data, wavelet, mmode): - """ Compute the result using MATLAB. - - This function assumes that the Matlab variables `wavelet` and `data` have - already been set externally. - """ - if np.any((wavelet == np.array(['coif6', 'coif7', 'coif8', 'coif9', 'coif10', 'coif11', 'coif12', 'coif13', 'coif14', 'coif15', 'coif16', 'coif17'])),axis=0): - w = pywt.Wavelet(wavelet) - mlab.set_variable('Lo_D', w.dec_lo) - mlab.set_variable('Hi_D', w.dec_hi) - mlab_code = ("[ma, md] = dwt(data, Lo_D, Hi_D, 'mode', '%s');" % mmode) - else: - mlab_code = "[ma, md] = dwt(data, wavelet, 'mode', '%s');" % mmode - res = mlab.run_code(mlab_code) - if not res['success']: - raise RuntimeError("Matlab failed to execute the provided code. " - "Check that the wavelet toolbox is installed.") - # need np.asarray because sometimes the output is a single float64 - ma = np.asarray(mlab.get_variable('ma')) - md = np.asarray(mlab.get_variable('md')) - return ma, md - - -def _load_matlab_result(data, wavelet, mmode): - """ Load the precomputed result. - """ - N = len(data) - ma_key = '_'.join([mmode, wavelet, str(N), 'ma']) - md_key = '_'.join([mmode, wavelet, str(N), 'md']) - if (ma_key not in matlab_result_dict) or \ - (md_key not in matlab_result_dict): - raise KeyError( - "Precompted Matlab result not found for wavelet: " - "{0}, mode: {1}, size: {2}".format(wavelet, mmode, N)) - ma = matlab_result_dict[ma_key] - md = matlab_result_dict[md_key] - return ma, md - - -def _load_matlab_result_pywt_coeffs(data, wavelet, mmode): - """ Load the precomputed result. - """ - N = len(data) - ma_key = '_'.join([mmode, wavelet, str(N), 'ma_pywtCoeffs']) - md_key = '_'.join([mmode, wavelet, str(N), 'md_pywtCoeffs']) - if (ma_key not in matlab_result_dict) or \ - (md_key not in matlab_result_dict): - raise KeyError( - "Precompted Matlab result not found for wavelet: " - "{0}, mode: {1}, size: {2}".format(wavelet, mmode, N)) - ma = matlab_result_dict[ma_key] - md = matlab_result_dict[md_key] - return ma, md - - -def _check_accuracy(data, w, pmode, ma, md, wavelet, epsilon): - # PyWavelets result - pa, pd = pywt.dwt(data, w, pmode) - - # calculate error measures - rms_a = np.sqrt(np.mean((pa - ma) ** 2)) - rms_d = np.sqrt(np.mean((pd - md) ** 2)) - - msg = ('[RMS_A > EPSILON] for Mode: %s, Wavelet: %s, ' - 'Length: %d, rms=%.3g' % (pmode, wavelet, len(data), rms_a)) - assert_(rms_a < epsilon, msg=msg) - - msg = ('[RMS_D > EPSILON] for Mode: %s, Wavelet: %s, ' - 'Length: %d, rms=%.3g' % (pmode, wavelet, len(data), rms_d)) - assert_(rms_d < epsilon, msg=msg) - - -if __name__ == '__main__': - run_module_suite() diff --git a/.eggs/PyWavelets-1.0.0-py3.7-linux-x86_64.egg/pywt/tests/test_matlab_compatibility_cwt.py b/.eggs/PyWavelets-1.0.0-py3.7-linux-x86_64.egg/pywt/tests/test_matlab_compatibility_cwt.py deleted file mode 100644 index 8fd31a17..00000000 --- a/.eggs/PyWavelets-1.0.0-py3.7-linux-x86_64.egg/pywt/tests/test_matlab_compatibility_cwt.py +++ /dev/null @@ -1,190 +0,0 @@ -""" -Test used to verify PyWavelets Continuous Wavelet Transform computation -accuracy against MathWorks Wavelet Toolbox. -""" - -from __future__ import division, print_function, absolute_import - -import warnings -import os -import numpy as np -from numpy.testing import assert_, dec, run_module_suite - -import pywt - -if 'PYWT_XSLOW' in os.environ: - # Run a more comprehensive set of problem sizes. This could take more than - # an hour to complete. - size_set = 'full' - use_precomputed = False -else: - size_set = 'reduced' - use_precomputed = True - -if use_precomputed: - data_dir = os.path.join(os.path.dirname(__file__), 'data') - matlab_data_file = os.path.join(data_dir, 'cwt_matlabR2015b_result.npz') - matlab_result_dict = np.load(matlab_data_file) -else: - try: - from pymatbridge import Matlab - mlab = Matlab() - _matlab_missing = False - except ImportError: - print("To run Matlab compatibility tests you need to have MathWorks " - "MATLAB, MathWorks Wavelet Toolbox and the pymatbridge Python " - "package installed.") - _matlab_missing = True - -families = ('gaus', 'mexh', 'morl', 'cgau', 'shan', 'fbsp', 'cmor') -wavelets = sum([pywt.wavelist(name) for name in families], []) - - -def _get_data_sizes(w): - """ Return the sizes to test for wavelet w. """ - if size_set == 'full': - data_sizes = list(range(100, 101)) + \ - [100, 200, 500, 1000, 50000] - else: - data_sizes = (1000, 1000 + 1) - return data_sizes - - -def _get_scales(w): - """ Return the scales to test for wavelet w. """ - if size_set == 'full': - Scales = (1,np.arange(1,3),np.arange(1,4),np.arange(1,5)) - else: - Scales = (1,np.arange(1,3)) - return Scales - - -@dec.skipif(use_precomputed or _matlab_missing) -@dec.slow -def test_accuracy_pymatbridge_cwt(): - rstate = np.random.RandomState(1234) - # max RMSE (was 1.0e-10, is reduced to 5.0e-5 due to different coefficents) - epsilon = 1e-15 - epsilon_psi = 1e-15 - mlab.start() - try: - for wavelet in wavelets: - with warnings.catch_warnings(): - warnings.simplefilter('ignore', FutureWarning) - w = pywt.ContinuousWavelet(wavelet) - if np.any((wavelet == np.array(['shan', 'cmor'])),axis=0): - mlab.set_variable('wavelet', wavelet+str(w.bandwidth_frequency)+'-'+str(w.center_frequency)) - elif wavelet == 'fbsp': - mlab.set_variable('wavelet', wavelet+str(w.fbsp_order)+'-'+str(w.bandwidth_frequency)+'-'+str(w.center_frequency)) - else: - mlab.set_variable('wavelet', wavelet) - mlab_code = ("psi = wavefun(wavelet,10)") - res = mlab.run_code(mlab_code) - psi = np.asarray(mlab.get_variable('psi')) - yield _check_accuracy_psi, w, psi, wavelet, epsilon_psi - for N in _get_data_sizes(w): - data = rstate.randn(N) - mlab.set_variable('data', data) - for scales in _get_scales(w): - coefs = _compute_matlab_result(data, wavelet, scales) - yield _check_accuracy, data, w, scales, coefs, wavelet, epsilon - - finally: - mlab.stop() - - -@dec.skipif(not use_precomputed) -@dec.slow -def test_accuracy_precomputed_cwt(): - # Keep this specific random seed to match the precomputed Matlab result. - rstate = np.random.RandomState(1234) - # has to be improved - epsilon = 1e-15 - epsilon32 = 1e-5 - epsilon_psi = 1e-15 - for wavelet in wavelets: - with warnings.catch_warnings(): - warnings.simplefilter('ignore', FutureWarning) - w = pywt.ContinuousWavelet(wavelet) - w32 = pywt.ContinuousWavelet(wavelet,dtype=np.float32) - psi = _load_matlab_result_psi(wavelet) - yield _check_accuracy_psi, w, psi, wavelet, epsilon_psi - - for N in _get_data_sizes(w): - data = rstate.randn(N) - data32 = data.astype(np.float32) - scales_count = 0 - for scales in _get_scales(w): - scales_count += 1 - coefs = _load_matlab_result(data, wavelet, scales_count) - yield _check_accuracy, data, w, scales, coefs, wavelet, epsilon - yield _check_accuracy, data32, w32, scales, coefs, wavelet, epsilon32 - - -def _compute_matlab_result(data, wavelet, scales): - """ Compute the result using MATLAB. - - This function assumes that the Matlab variables `wavelet` and `data` have - already been set externally. - """ - mlab.set_variable('scales', scales) - mlab_code = ("coefs = cwt(data, scales, wavelet)") - res = mlab.run_code(mlab_code) - if not res['success']: - raise RuntimeError("Matlab failed to execute the provided code. " - "Check that the wavelet toolbox is installed.") - # need np.asarray because sometimes the output is a single float64 - coefs = np.asarray(mlab.get_variable('coefs')) - return coefs - - -def _load_matlab_result(data, wavelet, scales): - """ Load the precomputed result. - """ - N = len(data) - coefs_key = '_'.join([str(scales), wavelet, str(N), 'coefs']) - if (coefs_key not in matlab_result_dict): - raise KeyError( - "Precompted Matlab result not found for wavelet: " - "{0}, mode: {1}, size: {2}".format(wavelet, scales, N)) - coefs = matlab_result_dict[coefs_key] - return coefs - - -def _load_matlab_result_psi(wavelet): - """ Load the precomputed result. - """ - psi_key = '_'.join([wavelet, 'psi']) - if (psi_key not in matlab_result_dict): - raise KeyError( - "Precompted Matlab psi result not found for wavelet: " - "{0}}".format(wavelet)) - psi = matlab_result_dict[psi_key] - return psi - - -def _check_accuracy(data, w, scales, coefs, wavelet, epsilon): - # PyWavelets result - coefs_pywt, freq = pywt.cwt(data, scales, w) - - # calculate error measures - rms = np.real(np.sqrt(np.mean((coefs_pywt - coefs) ** 2))) - - msg = ('[RMS > EPSILON] for Scale: %s, Wavelet: %s, ' - 'Length: %d, rms=%.3g' % (scales, wavelet, len(data), rms)) - assert_(rms < epsilon, msg=msg) - - -def _check_accuracy_psi(w, psi, wavelet, epsilon): - # PyWavelets result - psi_pywt, x = w.wavefun(length=1024) - - # calculate error measures - rms = np.real(np.sqrt(np.mean((psi_pywt.flatten() - psi.flatten()) ** 2))) - - msg = ('[RMS > EPSILON] for Wavelet: %s, ' - 'rms=%.3g' % (wavelet, rms)) - assert_(rms < epsilon, msg=msg) - -if __name__ == '__main__': - run_module_suite() diff --git a/.eggs/PyWavelets-1.0.0-py3.7-linux-x86_64.egg/pywt/tests/test_modes.py b/.eggs/PyWavelets-1.0.0-py3.7-linux-x86_64.egg/pywt/tests/test_modes.py deleted file mode 100644 index 80a490b7..00000000 --- a/.eggs/PyWavelets-1.0.0-py3.7-linux-x86_64.egg/pywt/tests/test_modes.py +++ /dev/null @@ -1,114 +0,0 @@ -#!/usr/bin/env python -from __future__ import division, print_function, absolute_import - -import numpy as np -from numpy.testing import (assert_raises, run_module_suite, - assert_equal, assert_allclose) - -import pywt - - -def test_available_modes(): - modes = ['zero', 'constant', 'symmetric', 'periodic', 'smooth', - 'periodization', 'reflect', 'antisymmetric', 'antireflect'] - assert_equal(pywt.Modes.modes, modes) - assert_equal(pywt.Modes.from_object('constant'), 2) - - -def test_invalid_modes(): - x = np.arange(4) - assert_raises(ValueError, pywt.dwt, x, 'db2', 'unknown') - assert_raises(ValueError, pywt.dwt, x, 'db2', -1) - assert_raises(ValueError, pywt.dwt, x, 'db2', 9) - assert_raises(TypeError, pywt.dwt, x, 'db2', None) - - assert_raises(ValueError, pywt.Modes.from_object, 'unknown') - assert_raises(ValueError, pywt.Modes.from_object, -1) - assert_raises(ValueError, pywt.Modes.from_object, 9) - assert_raises(TypeError, pywt.Modes.from_object, None) - - -def test_dwt_idwt_allmodes(): - # Test that :func:`dwt` and :func:`idwt` can be performed using every mode - x = [1, 2, 1, 5, -1, 8, 4, 6] - dwt_results = { - 'zero': ([-0.03467518, 1.73309178, 3.40612438, 6.32928585, 6.95094948], - [-0.12940952, -2.15599552, -5.95034847, -1.21545369, - -1.8625013]), - 'constant': ([1.28480404, 1.73309178, 3.40612438, 6.32928585, - 7.51935555], - [-0.48296291, -2.15599552, -5.95034847, -1.21545369, - 0.25881905]), - 'symmetric': ([1.76776695, 1.73309178, 3.40612438, 6.32928585, - 7.77817459], - [-0.61237244, -2.15599552, -5.95034847, -1.21545369, - 1.22474487]), - 'reflect': ([2.12132034, 1.73309178, 3.40612438, 6.32928585, - 6.81224877], - [-0.70710678, -2.15599552, -5.95034847, -1.21545369, - -2.38013939]), - 'periodic': ([6.9162743, 1.73309178, 3.40612438, 6.32928585, - 6.9162743], - [-1.99191082, -2.15599552, -5.95034847, -1.21545369, - -1.99191082]), - 'smooth': ([-0.51763809, 1.73309178, 3.40612438, 6.32928585, - 7.45000519], - [0, -2.15599552, -5.95034847, -1.21545369, 0]), - 'periodization': ([4.053172, 3.05257099, 2.85381112, 8.42522221], - [0.18946869, 4.18258152, 4.33737503, 2.60428326]), - 'antisymmetric': ([-1.83711731, 1.73309178, 3.40612438, 6.32928585, - 6.12372436], - [0.353553391, -2.15599552, -5.95034847, -1.21545369, - -4.94974747]), - 'antireflect': ([0.44828774, 1.73309178, 3.40612438, 6.32928585, - 8.22646233], - [-0.25881905, -2.15599552, -5.95034847, -1.21545369, - 2.89777748]) - } - - for mode in pywt.Modes.modes: - cA, cD = pywt.dwt(x, 'db2', mode) - assert_allclose(cA, dwt_results[mode][0], rtol=1e-7, atol=1e-8) - assert_allclose(cD, dwt_results[mode][1], rtol=1e-7, atol=1e-8) - assert_allclose(pywt.idwt(cA, cD, 'db2', mode), x, rtol=1e-10) - - -def test_dwt_short_input_allmodes(): - # some test cases where the input is shorter than the DWT filter - x = [1, 3, 2] - wavelet = 'db2' - # manually pad each end by the filter size (4 for 'db2' used here) - padded_x = {'zero': [0, 0, 0, 0, 1, 3, 2, 0, 0, 0, 0], - 'constant': [1, 1, 1, 1, 1, 3, 2, 2, 2, 2, 2], - 'symmetric': [2, 2, 3, 1, 1, 3, 2, 2, 3, 1, 1], - 'reflect': [1, 3, 2, 3, 1, 3, 2, 3, 1, 3, 2], - 'periodic': [2, 1, 3, 2, 1, 3, 2, 1, 3, 2, 1], - 'smooth': [-7, -5, -3, -1, 1, 3, 2, 1, 0, -1, -2], - 'antisymmetric': [2, -2, -3, -1, 1, 3, 2, -2, -3, -1, 1], - 'antireflect': [1, -1, 0, -1, 1, 3, 2, 1, 3, 5, 4], - } - for mode, xpad in padded_x.items(): - # DWT of the manually padded array. will discard edges later so - # symmetric mode used here doesn't matter. - cApad, cDpad = pywt.dwt(xpad, wavelet, mode='symmetric') - - # central region of the padded output (unaffected by mode ) - expected_result = (cApad[2:-2], cDpad[2:-2]) - - cA, cD = pywt.dwt(x, wavelet, mode) - assert_allclose(cA, expected_result[0], rtol=1e-7, atol=1e-8) - assert_allclose(cD, expected_result[1], rtol=1e-7, atol=1e-8) - - -def test_default_mode(): - # The default mode should be 'symmetric' - x = [1, 2, 1, 5, -1, 8, 4, 6] - cA, cD = pywt.dwt(x, 'db2') - cA2, cD2 = pywt.dwt(x, 'db2', mode='symmetric') - assert_allclose(cA, cA2) - assert_allclose(cD, cD2) - assert_allclose(pywt.idwt(cA, cD, 'db2'), x) - - -if __name__ == '__main__': - run_module_suite() diff --git a/.eggs/PyWavelets-1.0.0-py3.7-linux-x86_64.egg/pywt/tests/test_multidim.py b/.eggs/PyWavelets-1.0.0-py3.7-linux-x86_64.egg/pywt/tests/test_multidim.py deleted file mode 100644 index 4baf2934..00000000 --- a/.eggs/PyWavelets-1.0.0-py3.7-linux-x86_64.egg/pywt/tests/test_multidim.py +++ /dev/null @@ -1,432 +0,0 @@ -#!/usr/bin/env python - -from __future__ import division, print_function, absolute_import - -import numpy as np -from itertools import combinations -from numpy.testing import (run_module_suite, assert_allclose, assert_, - assert_raises, assert_equal) - -import pywt -# Check that float32, float64, complex64, complex128 are preserved. -# Other real types get converted to float64. -# complex256 gets converted to complex128 -dtypes_in = [np.int8, np.float16, np.float32, np.float64, np.complex64, - np.complex128] -dtypes_out = [np.float64, np.float32, np.float32, np.float64, np.complex64, - np.complex128] - -# test complex256 as well if it is available -try: - dtypes_in += [np.complex256, ] - dtypes_out += [np.complex128, ] -except AttributeError: - pass - - -def test_dwtn_input(): - # Array-like must be accepted - pywt.dwtn([1, 2, 3, 4], 'haar') - # Others must not - data = dict() - assert_raises(TypeError, pywt.dwtn, data, 'haar') - # Must be at least 1D - assert_raises(ValueError, pywt.dwtn, 2, 'haar') - - -def test_3D_reconstruct(): - data = np.array([ - [[0, 4, 1, 5, 1, 4], - [0, 5, 26, 3, 2, 1], - [5, 8, 2, 33, 4, 9], - [2, 5, 19, 4, 19, 1]], - [[1, 5, 1, 2, 3, 4], - [7, 12, 6, 52, 7, 8], - [2, 12, 3, 52, 6, 8], - [5, 2, 6, 78, 12, 2]]]) - - wavelet = pywt.Wavelet('haar') - for mode in pywt.Modes.modes: - d = pywt.dwtn(data, wavelet, mode=mode) - assert_allclose(data, pywt.idwtn(d, wavelet, mode=mode), - rtol=1e-13, atol=1e-13) - - -def test_dwdtn_idwtn_allwavelets(): - rstate = np.random.RandomState(1234) - r = rstate.randn(16, 16) - # test 2D case only for all wavelet types - wavelist = pywt.wavelist() - if 'dmey' in wavelist: - wavelist.remove('dmey') - for wavelet in wavelist: - if wavelet in ['cmor', 'shan', 'fbsp']: - # skip these CWT families to avoid warnings - continue - if isinstance(pywt.DiscreteContinuousWavelet(wavelet), pywt.Wavelet): - for mode in pywt.Modes.modes: - coeffs = pywt.dwtn(r, wavelet, mode=mode) - assert_allclose(pywt.idwtn(coeffs, wavelet, mode=mode), - r, rtol=1e-7, atol=1e-7) - - -def test_stride(): - wavelet = pywt.Wavelet('haar') - - for dtype in ('float32', 'float64'): - data = np.array([[0, 4, 1, 5, 1, 4], - [0, 5, 6, 3, 2, 1], - [2, 5, 19, 4, 19, 1]], - dtype=dtype) - - for mode in pywt.Modes.modes: - expected = pywt.dwtn(data, wavelet) - strided = np.ones((3, 12), dtype=data.dtype) - strided[::-1, ::2] = data - strided_dwtn = pywt.dwtn(strided[::-1, ::2], wavelet) - for key in expected.keys(): - assert_allclose(strided_dwtn[key], expected[key]) - - -def test_byte_offset(): - wavelet = pywt.Wavelet('haar') - for dtype in ('float32', 'float64'): - data = np.array([[0, 4, 1, 5, 1, 4], - [0, 5, 6, 3, 2, 1], - [2, 5, 19, 4, 19, 1]], - dtype=dtype) - - for mode in pywt.Modes.modes: - expected = pywt.dwtn(data, wavelet) - padded = np.ones((3, 6), dtype=np.dtype({'data': (data.dtype, 0), - 'pad': ('byte', data.dtype.itemsize)}, - align=True)) - padded[:] = data - padded_dwtn = pywt.dwtn(padded['data'], wavelet) - for key in expected.keys(): - assert_allclose(padded_dwtn[key], expected[key]) - - -def test_3D_reconstruct_complex(): - # All dimensions even length so `take` does not need to be specified - data = np.array([ - [[0, 4, 1, 5, 1, 4], - [0, 5, 26, 3, 2, 1], - [5, 8, 2, 33, 4, 9], - [2, 5, 19, 4, 19, 1]], - [[1, 5, 1, 2, 3, 4], - [7, 12, 6, 52, 7, 8], - [2, 12, 3, 52, 6, 8], - [5, 2, 6, 78, 12, 2]]]) - data = data + 1j - - wavelet = pywt.Wavelet('haar') - d = pywt.dwtn(data, wavelet) - # idwtn creates even-length shapes (2x dwtn size) - original_shape = tuple([slice(None, s) for s in data.shape]) - assert_allclose(data, pywt.idwtn(d, wavelet)[original_shape], - rtol=1e-13, atol=1e-13) - - -def test_idwtn_idwt2(): - data = np.array([ - [0, 4, 1, 5, 1, 4], - [0, 5, 6, 3, 2, 1], - [2, 5, 19, 4, 19, 1]]) - - wavelet = pywt.Wavelet('haar') - - LL, (HL, LH, HH) = pywt.dwt2(data, wavelet) - d = {'aa': LL, 'da': HL, 'ad': LH, 'dd': HH} - - for mode in pywt.Modes.modes: - assert_allclose(pywt.idwt2((LL, (HL, LH, HH)), wavelet, mode=mode), - pywt.idwtn(d, wavelet, mode=mode), - rtol=1e-14, atol=1e-14) - - -def test_idwtn_idwt2_complex(): - data = np.array([ - [0, 4, 1, 5, 1, 4], - [0, 5, 6, 3, 2, 1], - [2, 5, 19, 4, 19, 1]]) - data = data + 1j - wavelet = pywt.Wavelet('haar') - - LL, (HL, LH, HH) = pywt.dwt2(data, wavelet) - d = {'aa': LL, 'da': HL, 'ad': LH, 'dd': HH} - - for mode in pywt.Modes.modes: - assert_allclose(pywt.idwt2((LL, (HL, LH, HH)), wavelet, mode=mode), - pywt.idwtn(d, wavelet, mode=mode), - rtol=1e-14, atol=1e-14) - - -def test_idwtn_missing(): - # Test to confirm missing data behave as zeroes - data = np.array([ - [0, 4, 1, 5, 1, 4], - [0, 5, 6, 3, 2, 1], - [2, 5, 19, 4, 19, 1]]) - - wavelet = pywt.Wavelet('haar') - - coefs = pywt.dwtn(data, wavelet) - - # No point removing zero, or all - for num_missing in range(1, len(coefs)): - for missing in combinations(coefs.keys(), num_missing): - missing_coefs = coefs.copy() - for key in missing: - del missing_coefs[key] - LL = missing_coefs.get('aa', None) - HL = missing_coefs.get('da', None) - LH = missing_coefs.get('ad', None) - HH = missing_coefs.get('dd', None) - - assert_allclose(pywt.idwt2((LL, (HL, LH, HH)), wavelet), - pywt.idwtn(missing_coefs, 'haar'), atol=1e-15) - - -def test_idwtn_all_coeffs_None(): - coefs = dict(aa=None, da=None, ad=None, dd=None) - assert_raises(ValueError, pywt.idwtn, coefs, 'haar') - - -def test_error_on_invalid_keys(): - data = np.array([ - [0, 4, 1, 5, 1, 4], - [0, 5, 6, 3, 2, 1], - [2, 5, 19, 4, 19, 1]]) - - wavelet = pywt.Wavelet('haar') - - LL, (HL, LH, HH) = pywt.dwt2(data, wavelet) - - # unexpected key - d = {'aa': LL, 'da': HL, 'ad': LH, 'dd': HH, 'ff': LH} - assert_raises(ValueError, pywt.idwtn, d, wavelet) - - # mismatched key lengths - d = {'a': LL, 'da': HL, 'ad': LH, 'dd': HH} - assert_raises(ValueError, pywt.idwtn, d, wavelet) - - -def test_error_mismatched_size(): - data = np.array([ - [0, 4, 1, 5, 1, 4], - [0, 5, 6, 3, 2, 1], - [2, 5, 19, 4, 19, 1]]) - - wavelet = pywt.Wavelet('haar') - - LL, (HL, LH, HH) = pywt.dwt2(data, wavelet) - - # Pass/fail depends on first element being shorter than remaining ones so - # set 3/4 to an incorrect size to maximize chances. Order of dict items - # is random so may not trigger on every test run. Dict is constructed - # inside idwtn function so no use using an OrderedDict here. - LL = LL[:, :-1] - LH = LH[:, :-1] - HH = HH[:, :-1] - d = {'aa': LL, 'da': HL, 'ad': LH, 'dd': HH} - - assert_raises(ValueError, pywt.idwtn, d, wavelet) - - -def test_dwt2_idwt2_dtypes(): - wavelet = pywt.Wavelet('haar') - for dt_in, dt_out in zip(dtypes_in, dtypes_out): - x = np.ones((4, 4), dtype=dt_in) - errmsg = "wrong dtype returned for {0} input".format(dt_in) - - cA, (cH, cV, cD) = pywt.dwt2(x, wavelet) - assert_(cA.dtype == cH.dtype == cV.dtype == cD.dtype, - "dwt2: " + errmsg) - - x_roundtrip = pywt.idwt2((cA, (cH, cV, cD)), wavelet) - assert_(x_roundtrip.dtype == dt_out, "idwt2: " + errmsg) - - -def test_dwtn_axes(): - data = np.array([[0, 1, 2, 3], - [1, 1, 1, 1], - [1, 4, 2, 8]]) - data = data + 1j*data # test with complex data - coefs = pywt.dwtn(data, 'haar', axes=(1,)) - expected_a = list(map(lambda x: pywt.dwt(x, 'haar')[0], data)) - assert_equal(coefs['a'], expected_a) - expected_d = list(map(lambda x: pywt.dwt(x, 'haar')[1], data)) - assert_equal(coefs['d'], expected_d) - - coefs = pywt.dwtn(data, 'haar', axes=(1, 1)) - expected_aa = list(map(lambda x: pywt.dwt(x, 'haar')[0], expected_a)) - assert_equal(coefs['aa'], expected_aa) - expected_ad = list(map(lambda x: pywt.dwt(x, 'haar')[1], expected_a)) - assert_equal(coefs['ad'], expected_ad) - - -def test_idwtn_axes(): - data = np.array([[0, 1, 2, 3], - [1, 1, 1, 1], - [1, 4, 2, 8]]) - data = data + 1j*data # test with complex data - coefs = pywt.dwtn(data, 'haar', axes=(1, 1)) - assert_allclose(pywt.idwtn(coefs, 'haar', axes=(1, 1)), data, atol=1e-14) - - -def test_idwt2_none_coeffs(): - data = np.array([[0, 1, 2, 3], - [1, 1, 1, 1], - [1, 4, 2, 8]]) - data = data + 1j*data # test with complex data - cA, (cH, cV, cD) = pywt.dwt2(data, 'haar', axes=(1, 1)) - - # verify setting coefficients to None is the same as zeroing them - cD = np.zeros_like(cD) - result_zeros = pywt.idwt2((cA, (cH, cV, cD)), 'haar', axes=(1, 1)) - - cD = None - result_none = pywt.idwt2((cA, (cH, cV, cD)), 'haar', axes=(1, 1)) - - assert_equal(result_zeros, result_none) - - -def test_idwtn_none_coeffs(): - data = np.array([[0, 1, 2, 3], - [1, 1, 1, 1], - [1, 4, 2, 8]]) - data = data + 1j*data # test with complex data - coefs = pywt.dwtn(data, 'haar', axes=(1, 1)) - - # verify setting coefficients to None is the same as zeroing them - coefs['dd'] = np.zeros_like(coefs['dd']) - result_zeros = pywt.idwtn(coefs, 'haar', axes=(1, 1)) - - coefs['dd'] = None - result_none = pywt.idwtn(coefs, 'haar', axes=(1, 1)) - - assert_equal(result_zeros, result_none) - - -def test_idwt2_axes(): - data = np.array([[0, 1, 2, 3], - [1, 1, 1, 1], - [1, 4, 2, 8]]) - coefs = pywt.dwt2(data, 'haar', axes=(1, 1)) - assert_allclose(pywt.idwt2(coefs, 'haar', axes=(1, 1)), data, atol=1e-14) - - # too many axes - assert_raises(ValueError, pywt.idwt2, coefs, 'haar', axes=(0, 1, 1)) - - -def test_idwt2_axes_subsets(): - data = np.array(np.random.standard_normal((4, 4, 4))) - # test all combinations of 2 out of 3 axes transformed - for axes in combinations((0, 1, 2), 2): - coefs = pywt.dwt2(data, 'haar', axes=axes) - assert_allclose(pywt.idwt2(coefs, 'haar', axes=axes), data, atol=1e-14) - - -def test_idwtn_axes_subsets(): - data = np.array(np.random.standard_normal((4, 4, 4, 4))) - # test all combinations of 3 out of 4 axes transformed - for axes in combinations((0, 1, 2, 3), 3): - coefs = pywt.dwtn(data, 'haar', axes=axes) - assert_allclose(pywt.idwtn(coefs, 'haar', axes=axes), data, atol=1e-14) - - -def test_negative_axes(): - data = np.array([[0, 1, 2, 3], - [1, 1, 1, 1], - [1, 4, 2, 8]]) - coefs1 = pywt.dwtn(data, 'haar', axes=(1, 1)) - coefs2 = pywt.dwtn(data, 'haar', axes=(-1, -1)) - assert_equal(coefs1, coefs2) - - rec1 = pywt.idwtn(coefs1, 'haar', axes=(1, 1)) - rec2 = pywt.idwtn(coefs1, 'haar', axes=(-1, -1)) - assert_equal(rec1, rec2) - - -def test_dwtn_idwtn_dtypes(): - wavelet = pywt.Wavelet('haar') - for dt_in, dt_out in zip(dtypes_in, dtypes_out): - x = np.ones((4, 4), dtype=dt_in) - errmsg = "wrong dtype returned for {0} input".format(dt_in) - - coeffs = pywt.dwtn(x, wavelet) - for k, v in coeffs.items(): - assert_(v.dtype == dt_out, "dwtn: " + errmsg) - - x_roundtrip = pywt.idwtn(coeffs, wavelet) - assert_(x_roundtrip.dtype == dt_out, "idwtn: " + errmsg) - - -def test_idwt2_size_mismatch_error(): - LL = np.zeros((6, 6)) - LH = HL = HH = np.zeros((5, 5)) - - assert_raises(ValueError, pywt.idwt2, (LL, (LH, HL, HH)), wavelet='haar') - - -def test_dwt2_dimension_error(): - data = np.ones(16) - wavelet = pywt.Wavelet('haar') - - # wrong number of input dimensions - assert_raises(ValueError, pywt.dwt2, data, wavelet) - - # too many axes - data2 = np.ones((8, 8)) - assert_raises(ValueError, pywt.dwt2, data2, wavelet, axes=(0, 1, 1)) - - -def test_per_axis_wavelets_and_modes(): - # tests seperate wavelet and edge mode for each axis. - rstate = np.random.RandomState(1234) - data = rstate.randn(16, 16, 16) - - # wavelet can be a string or wavelet object - wavelets = (pywt.Wavelet('haar'), 'sym2', 'db4') - - # mode can be a string or a Modes enum - modes = ('symmetric', 'periodization', - pywt._extensions._pywt.Modes.reflect) - - coefs = pywt.dwtn(data, wavelets, modes) - assert_allclose(pywt.idwtn(coefs, wavelets, modes), data, atol=1e-14) - - coefs = pywt.dwtn(data, wavelets[:1], modes) - assert_allclose(pywt.idwtn(coefs, wavelets[:1], modes), data, atol=1e-14) - - coefs = pywt.dwtn(data, wavelets, modes[:1]) - assert_allclose(pywt.idwtn(coefs, wavelets, modes[:1]), data, atol=1e-14) - - # length of wavelets or modes doesn't match the length of axes - assert_raises(ValueError, pywt.dwtn, data, wavelets[:2]) - assert_raises(ValueError, pywt.dwtn, data, wavelets, mode=modes[:2]) - assert_raises(ValueError, pywt.idwtn, coefs, wavelets[:2]) - assert_raises(ValueError, pywt.idwtn, coefs, wavelets, mode=modes[:2]) - - # dwt2/idwt2 also support per-axis wavelets/modes - data2 = data[..., 0] - coefs2 = pywt.dwt2(data2, wavelets[:2], modes[:2]) - assert_allclose(pywt.idwt2(coefs2, wavelets[:2], modes[:2]), data2, - atol=1e-14) - - -def test_error_on_continuous_wavelet(): - # A ValueError is raised if a Continuous wavelet is selected - data = np.ones((16, 16)) - for dec_fun, rec_fun in zip([pywt.dwt2, pywt.dwtn], - [pywt.idwt2, pywt.idwtn]): - for cwave in ['morl', pywt.DiscreteContinuousWavelet('morl')]: - assert_raises(ValueError, dec_fun, data, wavelet=cwave) - - c = dec_fun(data, 'db1') - assert_raises(ValueError, rec_fun, c, wavelet=cwave) - - -if __name__ == '__main__': - run_module_suite() diff --git a/.eggs/PyWavelets-1.0.0-py3.7-linux-x86_64.egg/pywt/tests/test_multilevel.py b/.eggs/PyWavelets-1.0.0-py3.7-linux-x86_64.egg/pywt/tests/test_multilevel.py deleted file mode 100644 index 50219a96..00000000 --- a/.eggs/PyWavelets-1.0.0-py3.7-linux-x86_64.egg/pywt/tests/test_multilevel.py +++ /dev/null @@ -1,947 +0,0 @@ -#!/usr/bin/env python - -from __future__ import division, print_function, absolute_import - -import warnings -from itertools import combinations -import numpy as np -from numpy.testing import (run_module_suite, assert_almost_equal, - assert_allclose, assert_, assert_equal, - assert_raises, assert_raises_regex, dec, - assert_array_equal, assert_warns) -import pywt -# Check that float32, float64, complex64, complex128 are preserved. -# Other real types get converted to float64. -# complex256 gets converted to complex128 -dtypes_in = [np.int8, np.float16, np.float32, np.float64, np.complex64, - np.complex128] -dtypes_out = [np.float64, np.float32, np.float32, np.float64, np.complex64, - np.complex128] - -# tolerances used in accuracy comparisons -tol_single = 1e-6 -tol_double = 1e-13 -dtypes_and_tolerances = [(np.float16, tol_single), (np.float32, tol_single), - (np.float64, tol_double), (np.int8, tol_double), - (np.complex64, tol_single), - (np.complex128, tol_double)] - -# test complex256 as well if it is available -try: - dtypes_in += [np.complex256, ] - dtypes_out += [np.complex128, ] - dtypes_and_tolerances += [(np.complex256, tol_double), ] -except AttributeError: - pass - - -# determine which wavelets to test -wavelist = pywt.wavelist() -if 'dmey' in wavelist: - # accuracy is very low for dmey, so omit it - wavelist.remove('dmey') - -# removing wavelets with dwt_possible == False -del_list = [] -for wavelet in wavelist: - with warnings.catch_warnings(): - warnings.simplefilter('ignore', FutureWarning) - if not isinstance(pywt.DiscreteContinuousWavelet(wavelet), - pywt.Wavelet): - del_list.append(wavelet) -for del_ind in del_list: - wavelist.remove(del_ind) - - -#### -# 1d multilevel dwt tests -#### - -def test_wavedec(): - x = [3, 7, 1, 1, -2, 5, 4, 6] - db1 = pywt.Wavelet('db1') - cA3, cD3, cD2, cD1 = pywt.wavedec(x, db1) - assert_almost_equal(cA3, [8.83883476]) - assert_almost_equal(cD3, [-0.35355339]) - assert_allclose(cD2, [4., -3.5]) - assert_allclose(cD1, [-2.82842712, 0, -4.94974747, -1.41421356]) - assert_(pywt.dwt_max_level(len(x), db1) == 3) - - -def test_waverec_invalid_inputs(): - # input must be list or tuple - assert_raises(ValueError, pywt.waverec, np.ones(8), 'haar') - - # input list cannot be empty - assert_raises(ValueError, pywt.waverec, [], 'haar') - - # 'array_to_coeffs must specify 'output_format' to perform waverec - x = [3, 7, 1, 1, -2, 5, 4, 6] - coeffs = pywt.wavedec(x, 'db1') - arr, coeff_slices = pywt.coeffs_to_array(coeffs) - coeffs_from_arr = pywt.array_to_coeffs(arr, coeff_slices) - message = "Wrong coefficient format, if using 'array_to_coeffs' please specify the 'output_format' parameter" - assert_raises_regex(AttributeError, message, pywt.waverec, coeffs_from_arr, 'haar') - - -def test_waverec_accuracies(): - rstate = np.random.RandomState(1234) - x0 = rstate.randn(8) - for dt, tol in dtypes_and_tolerances: - x = x0.astype(dt) - if np.iscomplexobj(x): - x += 1j*rstate.randn(8).astype(x.real.dtype) - coeffs = pywt.wavedec(x, 'db1') - assert_allclose(pywt.waverec(coeffs, 'db1'), x, atol=tol, rtol=tol) - - -def test_waverec_none(): - x = [3, 7, 1, 1, -2, 5, 4, 6] - coeffs = pywt.wavedec(x, 'db1') - - # set some coefficients to None - coeffs[2] = None - coeffs[0] = None - assert_(pywt.waverec(coeffs, 'db1').size, len(x)) - - -def test_waverec_odd_length(): - x = [3, 7, 1, 1, -2, 5] - coeffs = pywt.wavedec(x, 'db1') - assert_allclose(pywt.waverec(coeffs, 'db1'), x, rtol=1e-12) - - -def test_waverec_complex(): - x = np.array([3, 7, 1, 1, -2, 5, 4, 6]) - x = x + 1j - coeffs = pywt.wavedec(x, 'db1') - assert_allclose(pywt.waverec(coeffs, 'db1'), x, rtol=1e-12) - - -def test_multilevel_dtypes_1d(): - # only checks that the result is of the expected type - wavelet = pywt.Wavelet('haar') - for dt_in, dt_out in zip(dtypes_in, dtypes_out): - # wavedec, waverec - x = np.ones(8, dtype=dt_in) - errmsg = "wrong dtype returned for {0} input".format(dt_in) - - coeffs = pywt.wavedec(x, wavelet, level=2) - for c in coeffs: - assert_(c.dtype == dt_out, "wavedec: " + errmsg) - x_roundtrip = pywt.waverec(coeffs, wavelet) - assert_(x_roundtrip.dtype == dt_out, "waverec: " + errmsg) - - -def test_waverec_all_wavelets_modes(): - # test 2D case using all wavelets and modes - rstate = np.random.RandomState(1234) - r = rstate.randn(80) - for wavelet in wavelist: - for mode in pywt.Modes.modes: - coeffs = pywt.wavedec(r, wavelet, mode=mode) - assert_allclose(pywt.waverec(coeffs, wavelet, mode=mode), - r, rtol=tol_single, atol=tol_single) - -#### -# 2d multilevel dwt function tests -#### - - -def test_waverec2_accuracies(): - rstate = np.random.RandomState(1234) - x0 = rstate.randn(4, 4) - for dt, tol in dtypes_and_tolerances: - x = x0.astype(dt) - if np.iscomplexobj(x): - x += 1j*rstate.randn(4, 4).astype(x.real.dtype) - coeffs = pywt.wavedec2(x, 'db1') - assert_(len(coeffs) == 3) - assert_allclose(pywt.waverec2(coeffs, 'db1'), x, atol=tol, rtol=tol) - - -def test_multilevel_dtypes_2d(): - wavelet = pywt.Wavelet('haar') - for dt_in, dt_out in zip(dtypes_in, dtypes_out): - # wavedec2, waverec2 - x = np.ones((8, 8), dtype=dt_in) - errmsg = "wrong dtype returned for {0} input".format(dt_in) - cA, coeffsD2, coeffsD1 = pywt.wavedec2(x, wavelet, level=2) - assert_(cA.dtype == dt_out, "wavedec2: " + errmsg) - for c in coeffsD1: - assert_(c.dtype == dt_out, "wavedec2: " + errmsg) - for c in coeffsD2: - assert_(c.dtype == dt_out, "wavedec2: " + errmsg) - x_roundtrip = pywt.waverec2([cA, coeffsD2, coeffsD1], wavelet) - assert_(x_roundtrip.dtype == dt_out, "waverec2: " + errmsg) - - -@dec.slow -def test_waverec2_all_wavelets_modes(): - # test 2D case using all wavelets and modes - rstate = np.random.RandomState(1234) - r = rstate.randn(80, 96) - for wavelet in wavelist: - for mode in pywt.Modes.modes: - coeffs = pywt.wavedec2(r, wavelet, mode=mode) - assert_allclose(pywt.waverec2(coeffs, wavelet, mode=mode), - r, rtol=tol_single, atol=tol_single) - - -def test_wavedec2_complex(): - data = np.ones((4, 4)) + 1j - coeffs = pywt.wavedec2(data, 'db1') - assert_(len(coeffs) == 3) - assert_allclose(pywt.waverec2(coeffs, 'db1'), data, rtol=1e-12) - - -def test_wavedec2_invalid_inputs(): - # input array has too few dimensions - data = np.ones(4) - assert_raises(ValueError, pywt.wavedec2, data, 'haar') - - -def test_waverec2_invalid_inputs(): - # input must be list or tuple - assert_raises(ValueError, pywt.waverec2, np.ones((8, 8)), 'haar') - - # input list cannot be empty - assert_raises(ValueError, pywt.waverec2, [], 'haar') - - -def test_waverec2_coeff_shape_mismatch(): - x = np.ones((8, 8)) - coeffs = pywt.wavedec2(x, 'db1') - - # introduce a shape mismatch in the coefficients - coeffs = list(coeffs) - coeffs[1] = list(coeffs[1]) - coeffs[1][1] = np.zeros((16, 1)) - assert_raises(ValueError, pywt.waverec2, coeffs, 'db1') - - -def test_waverec2_odd_length(): - x = np.ones((10, 6)) - coeffs = pywt.wavedec2(x, 'db1') - assert_allclose(pywt.waverec2(coeffs, 'db1'), x, rtol=1e-12) - - -def test_waverec2_none_coeffs(): - x = np.arange(24).reshape(6, 4) - coeffs = pywt.wavedec2(x, 'db1') - coeffs[1] = (None, None, None) - assert_(x.shape == pywt.waverec2(coeffs, 'db1').shape) - -#### -# nd multilevel dwt function tests -#### - - -def test_waverecn(): - rstate = np.random.RandomState(1234) - # test 1D through 4D cases - for nd in range(1, 5): - x = rstate.randn(*(4, )*nd) - coeffs = pywt.wavedecn(x, 'db1') - assert_(len(coeffs) == 3) - assert_allclose(pywt.waverecn(coeffs, 'db1'), x, rtol=tol_double) - - -def test_waverecn_empty_coeff(): - coeffs = [np.ones((2, 2, 2)), {}, {}] - assert_equal(pywt.waverecn(coeffs, 'db1').shape, (8, 8, 8)) - - assert_equal(pywt.waverecn(coeffs, 'db1').shape, (8, 8, 8)) - coeffs = [np.ones((2, 2, 2)), {}, {'daa': np.ones((4, 4, 4))}] - - coeffs = [np.ones((2, 2, 2)), {}, {}, {'daa': np.ones((8, 8, 8))}] - assert_equal(pywt.waverecn(coeffs, 'db1').shape, (16, 16, 16)) - - -def test_waverecn_invalid_coeffs(): - # approximation coeffs as None and no valid detail oeffs - coeffs = [None, {}] - assert_raises(ValueError, pywt.waverecn, coeffs, 'db1') - - # use of None for a coefficient value - coeffs = [np.ones((2, 2, 2)), {}, {'daa': None}, ] - assert_raises(ValueError, pywt.waverecn, coeffs, 'db1') - - # invalid key names in coefficient list - coeffs = [np.ones((4, 4, 4)), {'daa': np.ones((4, 4, 4)), - 'foo': np.ones((4, 4, 4))}] - assert_raises(ValueError, pywt.waverecn, coeffs, 'db1') - - # mismatched key name lengths - coeffs = [np.ones((4, 4, 4)), {'daa': np.ones((4, 4, 4)), - 'da': np.ones((4, 4, 4))}] - assert_raises(ValueError, pywt.waverecn, coeffs, 'db1') - - # key name lengths don't match the array dimensions - coeffs = [[[[1.0]]], {'ad': [[[0.0]]], 'da': [[[0.0]]], 'dd': [[[0.0]]]}] - assert_raises(ValueError, pywt.waverecn, coeffs, 'db1') - - # input list cannot be empty - assert_raises(ValueError, pywt.waverecn, [], 'haar') - - -def test_waverecn_lists(): - # support coefficient arrays specified as lists instead of arrays - coeffs = [[[1.0]], {'ad': [[0.0]], 'da': [[0.0]], 'dd': [[0.0]]}] - assert_equal(pywt.waverecn(coeffs, 'db1').shape, (2, 2)) - - -def test_waverecn_invalid_coeffs2(): - # shape mismatch should raise an error - coeffs = [np.ones((4, 4, 4)), {'ada': np.ones((4, 4))}] - assert_raises(ValueError, pywt.waverecn, coeffs, 'db1') - - -def test_wavedecn_invalid_inputs(): - # input array has too few dimensions - data = np.array(0) - assert_raises(ValueError, pywt.wavedecn, data, 'haar') - - # invalid number of levels - data = np.ones(16) - assert_raises(ValueError, pywt.wavedecn, data, 'haar', level=-1) - - -def test_wavedecn_many_levels(): - # perfect reconstruction even when level > pywt.dwt_max_level - data = np.arange(64).reshape(8, 8) - tol = 1e-12 - dec_funcs = [pywt.wavedec, pywt.wavedec2, pywt.wavedecn] - rec_funcs = [pywt.waverec, pywt.waverec2, pywt.waverecn] - with warnings.catch_warnings(): - warnings.simplefilter('ignore', UserWarning) - for dec_func, rec_func in zip(dec_funcs, rec_funcs): - for mode in ['periodization', 'symmetric']: - coeffs = dec_func(data, 'haar', mode=mode, level=20) - r = rec_func(coeffs, 'haar', mode=mode) - assert_allclose(data, r, atol=tol, rtol=tol) - - -def test_waverecn_accuracies(): - # testing 3D only here - rstate = np.random.RandomState(1234) - x0 = rstate.randn(4, 4, 4) - for dt, tol in dtypes_and_tolerances: - x = x0.astype(dt) - if np.iscomplexobj(x): - x += 1j*rstate.randn(4, 4, 4).astype(x.real.dtype) - coeffs = pywt.wavedecn(x.astype(dt), 'db1') - assert_allclose(pywt.waverecn(coeffs, 'db1'), x, atol=tol, rtol=tol) - - -def test_multilevel_dtypes_nd(): - wavelet = pywt.Wavelet('haar') - for dt_in, dt_out in zip(dtypes_in, dtypes_out): - # wavedecn, waverecn - x = np.ones((8, 8), dtype=dt_in) - errmsg = "wrong dtype returned for {0} input".format(dt_in) - cA, coeffsD2, coeffsD1 = pywt.wavedecn(x, wavelet, level=2) - assert_(cA.dtype == dt_out, "wavedecn: " + errmsg) - for key, c in coeffsD1.items(): - assert_(c.dtype == dt_out, "wavedecn: " + errmsg) - for key, c in coeffsD2.items(): - assert_(c.dtype == dt_out, "wavedecn: " + errmsg) - x_roundtrip = pywt.waverecn([cA, coeffsD2, coeffsD1], wavelet) - assert_(x_roundtrip.dtype == dt_out, "waverecn: " + errmsg) - - -def test_wavedecn_complex(): - data = np.ones((4, 4, 4)) + 1j - coeffs = pywt.wavedecn(data, 'db1') - assert_allclose(pywt.waverecn(coeffs, 'db1'), data, rtol=1e-12) - - -def test_waverecn_dtypes(): - x = np.ones((4, 4, 4)) - for dt, tol in dtypes_and_tolerances: - coeffs = pywt.wavedecn(x.astype(dt), 'db1') - assert_allclose(pywt.waverecn(coeffs, 'db1'), x, atol=tol, rtol=tol) - - -@dec.slow -def test_waverecn_all_wavelets_modes(): - # test 2D case using all wavelets and modes - rstate = np.random.RandomState(1234) - r = rstate.randn(80, 96) - for wavelet in wavelist: - for mode in pywt.Modes.modes: - coeffs = pywt.wavedecn(r, wavelet, mode=mode) - assert_allclose(pywt.waverecn(coeffs, wavelet, mode=mode), - r, rtol=tol_single, atol=tol_single) - - -def test_coeffs_to_array(): - # single element list returns the first element - a_coeffs = [np.arange(8).reshape(2, 4), ] - arr, arr_slices = pywt.coeffs_to_array(a_coeffs) - assert_allclose(arr, a_coeffs[0]) - assert_allclose(arr, arr[arr_slices[0]]) - - assert_raises(ValueError, pywt.coeffs_to_array, []) - # invalid second element: array as in wavedec, but not 1D - assert_raises(ValueError, pywt.coeffs_to_array, [a_coeffs[0], ] * 2) - # invalid second element: tuple as in wavedec2, but not a 3-tuple - assert_raises(ValueError, pywt.coeffs_to_array, [a_coeffs[0], - (a_coeffs[0], )]) - # coefficients as None is not supported - assert_raises(ValueError, pywt.coeffs_to_array, [None, ]) - assert_raises(ValueError, pywt.coeffs_to_array, [a_coeffs, - (None, None, None)]) - - # invalid type for second coefficient list element - assert_raises(ValueError, pywt.coeffs_to_array, [a_coeffs, None]) - - # use an invalid key name in the coef dictionary - coeffs = [np.array([0]), dict(d=np.array([0]), c=np.array([0]))] - assert_raises(ValueError, pywt.coeffs_to_array, coeffs) - - -def test_wavedecn_coeff_reshape_even(): - # verify round trip is correct: - # wavedecn - >coeffs_to_array-> array_to_coeffs -> waverecn - # This is done for wavedec{1, 2, n} - rng = np.random.RandomState(1234) - params = {'wavedec': {'d': 1, 'dec': pywt.wavedec, 'rec': pywt.waverec}, - 'wavedec2': {'d': 2, 'dec': pywt.wavedec2, 'rec': pywt.waverec2}, - 'wavedecn': {'d': 3, 'dec': pywt.wavedecn, 'rec': pywt.waverecn}} - N = 28 - for f in params: - x1 = rng.randn(*([N] * params[f]['d'])) - for mode in pywt.Modes.modes: - for wave in wavelist: - w = pywt.Wavelet(wave) - maxlevel = pywt.dwt_max_level(np.min(x1.shape), w.dec_len) - if maxlevel == 0: - continue - - coeffs = params[f]['dec'](x1, w, mode=mode) - coeff_arr, coeff_slices = pywt.coeffs_to_array(coeffs) - coeffs2 = pywt.array_to_coeffs(coeff_arr, coeff_slices, - output_format=f) - x1r = params[f]['rec'](coeffs2, w, mode=mode) - - assert_allclose(x1, x1r, rtol=1e-4, atol=1e-4) - - -def test_wavedecn_coeff_reshape_axes_subset(): - # verify round trip is correct when only a subset of axes are transformed: - # wavedecn - >coeffs_to_array-> array_to_coeffs -> waverecn - # This is done for wavedec{1, 2, n} - rng = np.random.RandomState(1234) - mode = 'symmetric' - w = pywt.Wavelet('db2') - N = 16 - ndim = 3 - for axes in [(-1, ), (0, ), (1, ), (0, 1), (1, 2), (0, 2), None]: - x1 = rng.randn(*([N] * ndim)) - coeffs = pywt.wavedecn(x1, w, mode=mode, axes=axes) - coeff_arr, coeff_slices = pywt.coeffs_to_array(coeffs, axes=axes) - if axes is not None: - # if axes is not None, it must be provided to coeffs_to_array - assert_raises(ValueError, pywt.coeffs_to_array, coeffs) - - # mismatched axes size - assert_raises(ValueError, pywt.coeffs_to_array, coeffs, - axes=(0, 1, 2, 3)) - assert_raises(ValueError, pywt.coeffs_to_array, coeffs, - axes=()) - - coeffs2 = pywt.array_to_coeffs(coeff_arr, coeff_slices) - x1r = pywt.waverecn(coeffs2, w, mode=mode, axes=axes) - - assert_allclose(x1, x1r, rtol=1e-4, atol=1e-4) - - -def test_coeffs_to_array_padding(): - rng = np.random.RandomState(1234) - x1 = rng.randn(32, 32) - mode = 'symmetric' - coeffs = pywt.wavedecn(x1, 'db2', mode=mode) - - # padding=None raises a ValueError when tight packing is not possible - assert_raises(ValueError, pywt.coeffs_to_array, coeffs, padding=None) - - # set padded values to nan - coeff_arr, coeff_slices = pywt.coeffs_to_array(coeffs, padding=np.nan) - npad = np.sum(np.isnan(coeff_arr)) - assert_(npad > 0) - - # pad with zeros - coeff_arr, coeff_slices = pywt.coeffs_to_array(coeffs, padding=0) - assert_(np.sum(np.isnan(coeff_arr)) == 0) - assert_(np.sum(coeff_arr == 0) == npad) - - # Haar case with N as a power of 2 can be tightly packed - coeffs_haar = pywt.wavedecn(x1, 'haar', mode=mode) - coeff_arr, coeff_slices = pywt.coeffs_to_array(coeffs_haar, padding=None) - # shape of coeff_arr will match in this case, but not in general - assert_equal(coeff_arr.shape, x1.shape) - - -def test_waverecn_coeff_reshape_odd(): - # verify round trip is correct: - # wavedecn - >coeffs_to_array-> array_to_coeffs -> waverecn - rng = np.random.RandomState(1234) - x1 = rng.randn(35, 33) - for mode in pywt.Modes.modes: - for wave in ['haar', ]: - w = pywt.Wavelet(wave) - maxlevel = pywt.dwt_max_level(np.min(x1.shape), w.dec_len) - if maxlevel == 0: - continue - coeffs = pywt.wavedecn(x1, w, mode=mode) - coeff_arr, coeff_slices = pywt.coeffs_to_array(coeffs) - coeffs2 = pywt.array_to_coeffs(coeff_arr, coeff_slices) - x1r = pywt.waverecn(coeffs2, w, mode=mode) - # truncate reconstructed values to original shape - x1r = x1r[tuple([slice(s) for s in x1.shape])] - assert_allclose(x1, x1r, rtol=1e-4, atol=1e-4) - - -def test_array_to_coeffs_invalid_inputs(): - coeffs = pywt.wavedecn(np.ones(2), 'haar') - arr, arr_slices = pywt.coeffs_to_array(coeffs) - - # empty list of array slices - assert_raises(ValueError, pywt.array_to_coeffs, arr, []) - - # invalid format name - assert_raises(ValueError, pywt.array_to_coeffs, arr, arr_slices, 'foo') - - -def test_wavedecn_coeff_ravel(): - # verify round trip is correct: - # wavedecn - >ravel_coeffs-> unravel_coeffs -> waverecn - # This is done for wavedec{1, 2, n} - rng = np.random.RandomState(1234) - params = {'wavedec': {'d': 1, 'dec': pywt.wavedec, 'rec': pywt.waverec}, - 'wavedec2': {'d': 2, 'dec': pywt.wavedec2, 'rec': pywt.waverec2}, - 'wavedecn': {'d': 3, 'dec': pywt.wavedecn, 'rec': pywt.waverecn}} - N = 12 - for f in params: - x1 = rng.randn(*([N] * params[f]['d'])) - for mode in pywt.Modes.modes: - for wave in wavelist: - w = pywt.Wavelet(wave) - maxlevel = pywt.dwt_max_level(np.min(x1.shape), w.dec_len) - if maxlevel == 0: - continue - - coeffs = params[f]['dec'](x1, w, mode=mode) - coeff_arr, slices, shapes = pywt.ravel_coeffs(coeffs) - coeffs2 = pywt.unravel_coeffs(coeff_arr, slices, shapes, - output_format=f) - x1r = params[f]['rec'](coeffs2, w, mode=mode) - - assert_allclose(x1, x1r, rtol=1e-4, atol=1e-4) - - -def test_wavedecn_coeff_ravel_zero_level(): - # verify round trip is correct: - # wavedecn - >ravel_coeffs-> unravel_coeffs -> waverecn - # This is done for wavedec{1, 2, n} - rng = np.random.RandomState(1234) - params = {'wavedec': {'d': 1, 'dec': pywt.wavedec, 'rec': pywt.waverec}, - 'wavedec2': {'d': 2, 'dec': pywt.wavedec2, 'rec': pywt.waverec2}, - 'wavedecn': {'d': 3, 'dec': pywt.wavedecn, 'rec': pywt.waverecn}} - N = 16 - for f in params: - x1 = rng.randn(*([N] * params[f]['d'])) - for mode in pywt.Modes.modes: - w = pywt.Wavelet('db2') - - coeffs = params[f]['dec'](x1, w, mode=mode, level=0) - coeff_arr, slices, shapes = pywt.ravel_coeffs(coeffs) - coeffs2 = pywt.unravel_coeffs(coeff_arr, slices, shapes, - output_format=f) - x1r = params[f]['rec'](coeffs2, w, mode=mode) - - assert_allclose(x1, x1r, rtol=1e-4, atol=1e-4) - - -def test_waverecn_coeff_ravel_odd(): - # verify round trip is correct: - # wavedecn - >ravel_coeffs-> unravel_coeffs -> waverecn - rng = np.random.RandomState(1234) - x1 = rng.randn(35, 33) - for mode in pywt.Modes.modes: - for wave in ['haar', ]: - w = pywt.Wavelet(wave) - maxlevel = pywt.dwt_max_level(np.min(x1.shape), w.dec_len) - if maxlevel == 0: - continue - coeffs = pywt.wavedecn(x1, w, mode=mode) - coeff_arr, slices, shapes = pywt.ravel_coeffs(coeffs) - coeffs2 = pywt.unravel_coeffs(coeff_arr, slices, shapes) - x1r = pywt.waverecn(coeffs2, w, mode=mode) - # truncate reconstructed values to original shape - x1r = x1r[tuple([slice(s) for s in x1.shape])] - assert_allclose(x1, x1r, rtol=1e-4, atol=1e-4) - - -def test_ravel_wavedec2_with_lists(): - x1 = np.ones((8, 8)) - wav = pywt.Wavelet('haar') - coeffs = pywt.wavedec2(x1, wav) - - # list [cHn, cVn, cDn] instead of tuple is okay - coeffs[1:] = [list(c) for c in coeffs[1:]] - coeff_arr, slices, shapes = pywt.ravel_coeffs(coeffs) - coeffs2 = pywt.unravel_coeffs(coeff_arr, slices, shapes, - output_format='wavedec2') - x1r = pywt.waverec2(coeffs2, wav) - assert_allclose(x1, x1r, rtol=1e-4, atol=1e-4) - - # wrong length list will cause a ValueError - coeffs[1:] = [list(c[:-1]) for c in coeffs[1:]] # truncate diag coeffs - assert_raises(ValueError, pywt.ravel_coeffs, coeffs) - - -def test_ravel_invalid_input(): - # wavedec ravel does not support any coefficient arrays being set to None - coeffs = pywt.wavedec(np.ones(8), 'haar') - coeffs[1] = None - assert_raises(ValueError, pywt.ravel_coeffs, coeffs) - - # wavedec2 ravel cannot have None or a tuple/list of None - coeffs = pywt.wavedec2(np.ones((8, 8)), 'haar') - coeffs[1] = (None, None, None) - assert_raises(ValueError, pywt.ravel_coeffs, coeffs) - coeffs[1] = [None, None, None] - assert_raises(ValueError, pywt.ravel_coeffs, coeffs) - coeffs[1] = None - assert_raises(ValueError, pywt.ravel_coeffs, coeffs) - - # wavedecn ravel cannot have any dictionary elements as None - coeffs = pywt.wavedecn(np.ones((8, 8, 8)), 'haar') - coeffs[1]['ddd'] = None - assert_raises(ValueError, pywt.ravel_coeffs, coeffs) - - -def test_unravel_invalid_inputs(): - coeffs = pywt.wavedecn(np.ones(2), 'haar') - arr, slices, shapes = pywt.ravel_coeffs(coeffs) - - # empty list for slices or shapes - assert_raises(ValueError, pywt.unravel_coeffs, arr, slices, []) - assert_raises(ValueError, pywt.unravel_coeffs, arr, [], shapes) - - # unequal length for slices/shapes - assert_raises(ValueError, pywt.unravel_coeffs, arr, slices[:-1], shapes) - - # invalid format name - assert_raises(ValueError, pywt.unravel_coeffs, arr, slices, shapes, 'foo') - - -def test_wavedecn_shapes_and_size(): - wav = pywt.Wavelet('db2') - for data_shape in [(33, ), (64, 32), (1, 15, 30)]: - for axes in [None, 0, -1]: - for mode in pywt.Modes.modes: - coeffs = pywt.wavedecn(np.ones(data_shape), wav, - mode=mode, axes=axes) - - # verify that the shapes match the coefficient shapes - shapes = pywt.wavedecn_shapes(data_shape, wav, - mode=mode, axes=axes) - - assert_equal(coeffs[0].shape, shapes[0]) - expected_size = coeffs[0].size - for level in range(1, len(coeffs)): - for k, v in coeffs[level].items(): - expected_size += v.size - assert_equal(shapes[level][k], v.shape) - - # size can be determined from either the shapes or coeffs - size = pywt.wavedecn_size(shapes) - assert_equal(size, expected_size) - - size = pywt.wavedecn_size(coeffs) - assert_equal(size, expected_size) - - -def test_dwtn_max_level(): - # predicted and empirical dwtn_max_level match - for wav in [pywt.Wavelet('db2'), 'sym8']: - for data_shape in [(33, ), (64, 32), (1, 15, 30)]: - for axes in [None, 0, -1]: - for mode in pywt.Modes.modes: - coeffs = pywt.wavedecn(np.ones(data_shape), wav, - mode=mode, axes=axes) - max_lev = pywt.dwtn_max_level(data_shape, wav, axes) - assert_equal(len(coeffs[1:]), max_lev) - - -def test_waverec_axes_subsets(): - rstate = np.random.RandomState(0) - data = rstate.standard_normal((8, 8, 8)) - # test all combinations of 1 out of 3 axes transformed - for axis in [0, 1, 2]: - coefs = pywt.wavedec(data, 'haar', axis=axis) - rec = pywt.waverec(coefs, 'haar', axis=axis) - assert_allclose(rec, data, atol=1e-14) - - -def test_waverec_axis_db2(): - # test for fix to issue gh-293 - rstate = np.random.RandomState(0) - data = rstate.standard_normal((16, 16)) - for axis in [0, 1]: - coefs = pywt.wavedec(data, 'db2', axis=axis) - rec = pywt.waverec(coefs, 'db2', axis=axis) - assert_allclose(rec, data, atol=1e-14) - - -def test_waverec2_axes_subsets(): - rstate = np.random.RandomState(0) - data = rstate.standard_normal((8, 8, 8)) - # test all combinations of 2 out of 3 axes transformed - for axes in combinations((0, 1, 2), 2): - coefs = pywt.wavedec2(data, 'haar', axes=axes) - rec = pywt.waverec2(coefs, 'haar', axes=axes) - assert_allclose(rec, data, atol=1e-14) - - -def test_waverecn_axes_subsets(): - rstate = np.random.RandomState(0) - data = rstate.standard_normal((8, 8, 8, 8)) - # test all combinations of 3 out of 4 axes transformed - for axes in combinations((0, 1, 2, 3), 3): - coefs = pywt.wavedecn(data, 'haar', axes=axes) - rec = pywt.waverecn(coefs, 'haar', axes=axes) - assert_allclose(rec, data, atol=1e-14) - - -def test_waverecn_int_axis(): - # waverecn should also work for axes as an integer - rstate = np.random.RandomState(0) - data = rstate.standard_normal((8, 8)) - for axis in [0, 1]: - coefs = pywt.wavedecn(data, 'haar', axes=axis) - rec = pywt.waverecn(coefs, 'haar', axes=axis) - assert_allclose(rec, data, atol=1e-14) - - -def test_wavedec_axis_error(): - data = np.ones(4) - # out of range axis not allowed - assert_raises(ValueError, pywt.wavedec, data, 'haar', axis=1) - - -def test_waverec_axis_error(): - c = pywt.wavedec(np.ones(4), 'haar') - # out of range axis not allowed - assert_raises(ValueError, pywt.waverec, c, 'haar', axis=1) - - -def test_waverec_shape_mismatch_error(): - c = pywt.wavedec(np.ones(16), 'haar') - # truncate a detail coefficient to an incorrect shape - c[3] = c[3][:-1] - assert_raises(ValueError, pywt.waverec, c, 'haar', axis=1) - - -def test_wavedec2_axes_errors(): - data = np.ones((4, 4)) - # integer axes not allowed - assert_raises(TypeError, pywt.wavedec2, data, 'haar', axes=1) - # non-unique axes not allowed - assert_raises(ValueError, pywt.wavedec2, data, 'haar', axes=(0, 0)) - # out of range axis not allowed - assert_raises(ValueError, pywt.wavedec2, data, 'haar', axes=(0, 2)) - - -def test_waverec2_axes_errors(): - data = np.ones((4, 4)) - c = pywt.wavedec2(data, 'haar') - # integer axes not allowed - assert_raises(TypeError, pywt.waverec2, c, 'haar', axes=1) - # non-unique axes not allowed - assert_raises(ValueError, pywt.waverec2, c, 'haar', axes=(0, 0)) - # out of range axis not allowed - assert_raises(ValueError, pywt.waverec2, c, 'haar', axes=(0, 2)) - - -def test_wavedecn_axes_errors(): - data = np.ones((8, 8, 8)) - # repeated axes not allowed - assert_raises(ValueError, pywt.wavedecn, data, 'haar', axes=(1, 1)) - # out of range axis not allowed - assert_raises(ValueError, pywt.wavedecn, data, 'haar', axes=(0, 1, 3)) - - -def test_waverecn_axes_errors(): - data = np.ones((8, 8, 8)) - c = pywt.wavedecn(data, 'haar') - # repeated axes not allowed - assert_raises(ValueError, pywt.waverecn, c, 'haar', axes=(1, 1)) - # out of range axis not allowed - assert_raises(ValueError, pywt.waverecn, c, 'haar', axes=(0, 1, 3)) - - -def test_per_axis_wavelets_and_modes(): - # tests seperate wavelet and edge mode for each axis. - rstate = np.random.RandomState(1234) - data = rstate.randn(24, 24, 16) - - # wavelet can be a string or wavelet object - wavelets = (pywt.Wavelet('haar'), 'sym2', 'db2') - - # The default number of levels should be the minimum over this list - max_levels = [pywt._dwt.dwt_max_level(nd, nf) for nd, nf in - zip(data.shape, wavelets)] - - # mode can be a string or a Modes enum - modes = ('symmetric', 'periodization', - pywt._extensions._pywt.Modes.reflect) - - coefs = pywt.wavedecn(data, wavelets, modes) - assert_allclose(pywt.waverecn(coefs, wavelets, modes), data, atol=1e-14) - assert_equal(min(max_levels), len(coefs[1:])) - - coefs = pywt.wavedecn(data, wavelets[:1], modes) - assert_allclose(pywt.waverecn(coefs, wavelets[:1], modes), data, - atol=1e-14) - - coefs = pywt.wavedecn(data, wavelets, modes[:1]) - assert_allclose(pywt.waverecn(coefs, wavelets, modes[:1]), data, - atol=1e-14) - - # length of wavelets or modes doesn't match the length of axes - assert_raises(ValueError, pywt.wavedecn, data, wavelets[:2]) - assert_raises(ValueError, pywt.wavedecn, data, wavelets, mode=modes[:2]) - assert_raises(ValueError, pywt.waverecn, coefs, wavelets[:2]) - assert_raises(ValueError, pywt.waverecn, coefs, wavelets, mode=modes[:2]) - - # dwt2/idwt2 also support per-axis wavelets/modes - data2 = data[..., 0] - coefs2 = pywt.wavedec2(data2, wavelets[:2], modes[:2]) - assert_allclose(pywt.waverec2(coefs2, wavelets[:2], modes[:2]), data2, - atol=1e-14) - assert_equal(min(max_levels[:2]), len(coefs2[1:])) - -# Tests for fully separable multi-level transforms - - -def test_fswavedecn_fswaverecn_roundtrip(): - # verify proper round trip result for 1D through 4D data - # same DWT as wavedecn/waverecn so don't need to test all modes/wavelets - rstate = np.random.RandomState(0) - for ndim in range(1, 5): - for dt_in, dt_out in zip(dtypes_in, dtypes_out): - for levels in (1, None): - data = rstate.standard_normal((8, )*ndim) - data = data.astype(dt_in) - T = pywt.fswavedecn(data, 'haar', levels=levels) - rec = pywt.fswaverecn(T) - if data.real.dtype in [np.float32, np.float16]: - assert_allclose(rec, data, rtol=1e-6, atol=1e-6) - else: - assert_allclose(rec, data, rtol=1e-14, atol=1e-14) - assert_(T.coeffs.dtype == dt_out) - assert_(rec.dtype == dt_out) - - -def test_fswavedecn_fswaverecn_zero_levels(): - # zero level transform gives coefs matching the original data - rstate = np.random.RandomState(0) - ndim = 2 - data = rstate.standard_normal((8, )*ndim) - T = pywt.fswavedecn(data, 'haar', levels=0) - assert_array_equal(T.coeffs, data) - rec = pywt.fswaverecn(T) - assert_array_equal(T.coeffs, rec) - - -def test_fswavedecn_fswaverecn_variable_levels(): - # test with differing number of transform levels per axis - rstate = np.random.RandomState(0) - ndim = 3 - data = rstate.standard_normal((16, )*ndim) - T = pywt.fswavedecn(data, 'haar', levels=(1, 2, 3)) - rec = pywt.fswaverecn(T) - assert_allclose(rec, data, atol=1e-14) - - # levels doesn't match number of axes - assert_raises(ValueError, pywt.fswavedecn, data, 'haar', levels=(1, 1)) - assert_raises(ValueError, pywt.fswavedecn, data, 'haar', levels=(1, 1, 1, 1)) - - # levels too large for array size - assert_warns(UserWarning, pywt.fswavedecn, data, 'haar', - levels=int(np.log2(np.min(data.shape)))+1) - - -def test_fswavedecn_fswaverecn_variable_wavelets_and_modes(): - # test with differing number of transform levels per axis - rstate = np.random.RandomState(0) - ndim = 3 - data = rstate.standard_normal((16, )*ndim) - wavelets = ('haar', 'db2', 'sym3') - modes = ('periodic', 'symmetric', 'periodization') - T = pywt.fswavedecn(data, wavelet=wavelets, mode=modes) - for ax in range(ndim): - # expect approx + dwt_max_level detail coeffs along each axis - assert_equal(len(T.coeff_slices[ax]), - pywt.dwt_max_level(data.shape[ax], wavelets[ax])+1) - - rec = pywt.fswaverecn(T) - assert_allclose(rec, data, atol=1e-14) - - # number of wavelets doesn't match number of axes - assert_raises(ValueError, pywt.fswavedecn, data, wavelets[:2]) - - # number of modes doesn't match number of axes - assert_raises(ValueError, pywt.fswavedecn, data, wavelets[0], mode=modes[:2]) - - -def test_fswavedecn_fswaverecn_axes_subsets(): - """Fully separable DWT over only a subset of axes""" - rstate = np.random.RandomState(0) - # use anisotropic data to result in unique number of levels per axis - data = rstate.standard_normal((4, 8, 16, 32)) - # test all combinations of 3 out of 4 axes transformed - for axes in combinations((0, 1, 2, 3), 3): - T = pywt.fswavedecn(data, 'haar', axes=axes) - rec = pywt.fswaverecn(T) - assert_allclose(rec, data, atol=1e-14) - - # some axes exceed data dimensions - assert_raises(ValueError, pywt.fswavedecn, data, 'haar', axes=(1, 5)) - - -def test_error_on_continuous_wavelet(): - # A ValueError is raised if a Continuous wavelet is selected - data = np.ones((16, 16)) - for dec_fun, rec_fun in zip([pywt.wavedec, pywt.wavedec2, pywt.wavedecn], - [pywt.waverec, pywt.waverec2, pywt.waverecn]): - for cwave in ['morl', pywt.DiscreteContinuousWavelet('morl')]: - assert_raises(ValueError, dec_fun, data, wavelet=cwave) - - c = dec_fun(data, 'db1') - assert_raises(ValueError, rec_fun, c, wavelet=cwave) - - -def test_default_level(): - # default level is the maximum permissible for the transformed axes - data = np.ones((128, 32, 4)) - wavelet = ('db8', 'db1') - for dec_func in [pywt.wavedec2, pywt.wavedecn]: - for axes in [(0, 1), (2, 1), (0, 2)]: - c = dec_func(data, wavelet, axes=axes) - max_lev = np.min([pywt.dwt_max_level(data.shape[ax], wav) - for ax, wav in zip(axes, wavelet)]) - assert_equal(len(c[1:]), max_lev) - - for ax in [0, 1]: - c = pywt.wavedecn(data, wavelet[ax], axes=(ax, )) - assert_equal(len(c[1:]), - pywt.dwt_max_level(data.shape[ax], wavelet[ax])) - - -if __name__ == '__main__': - run_module_suite() diff --git a/.eggs/PyWavelets-1.0.0-py3.7-linux-x86_64.egg/pywt/tests/test_perfect_reconstruction.py b/.eggs/PyWavelets-1.0.0-py3.7-linux-x86_64.egg/pywt/tests/test_perfect_reconstruction.py deleted file mode 100644 index 0466b839..00000000 --- a/.eggs/PyWavelets-1.0.0-py3.7-linux-x86_64.egg/pywt/tests/test_perfect_reconstruction.py +++ /dev/null @@ -1,65 +0,0 @@ -#!/usr/bin/env python - -""" -Verify DWT perfect reconstruction. -""" - -from __future__ import division, print_function, absolute_import - -import numpy as np -from numpy.testing import assert_, run_module_suite - -import pywt - - -def test_perfect_reconstruction(): - families = ('db', 'sym', 'coif', 'bior', 'rbio') - wavelets = sum([pywt.wavelist(name) for name in families], []) - # list of mode names in pywt and matlab - modes = [('zero', 'zpd'), - ('constant', 'sp0'), - ('symmetric', 'sym'), - ('periodic', 'ppd'), - ('smooth', 'sp1'), - ('periodization', 'per')] - - dtypes = (np.float32, np.float64) - - for wavelet in wavelets: - for pmode, mmode in modes: - for dt in dtypes: - yield check_reconstruction, pmode, mmode, wavelet, dt - - -def check_reconstruction(pmode, mmode, wavelet, dtype): - data_size = list(range(2, 40)) + [100, 200, 500, 1000, 2000, 10000, - 50000, 100000] - np.random.seed(12345) - # TODO: smoke testing - more failures for different seeds - - if dtype == np.float32: - # was 3e-7 has to be lowered as db21, db29, db33, db35, coif14, coif16 were failing - epsilon = 6e-7 - else: - epsilon = 5e-11 - - for N in data_size: - data = np.asarray(np.random.random(N), dtype) - - # compute dwt coefficients - pa, pd = pywt.dwt(data, wavelet, pmode) - - # compute reconstruction - rec = pywt.idwt(pa, pd, wavelet, pmode) - - if len(data) % 2: - rec = rec[:len(data)] - - rms_rec = np.sqrt(np.mean((data-rec)**2)) - msg = ('[RMS_REC > EPSILON] for Mode: %s, Wavelet: %s, ' - 'Length: %d, rms=%.3g' % (pmode, wavelet, len(data), rms_rec)) - assert_(rms_rec < epsilon, msg=msg) - - -if __name__ == '__main__': - run_module_suite() diff --git a/.eggs/PyWavelets-1.0.0-py3.7-linux-x86_64.egg/pywt/tests/test_swt.py b/.eggs/PyWavelets-1.0.0-py3.7-linux-x86_64.egg/pywt/tests/test_swt.py deleted file mode 100644 index 478d2848..00000000 --- a/.eggs/PyWavelets-1.0.0-py3.7-linux-x86_64.egg/pywt/tests/test_swt.py +++ /dev/null @@ -1,431 +0,0 @@ -#!/usr/bin/env python - -from __future__ import division, print_function, absolute_import - -import warnings -from copy import deepcopy -from itertools import combinations -import numpy as np -from numpy.testing import (run_module_suite, dec, assert_allclose, assert_, - assert_equal, assert_raises, assert_array_equal, - assert_warns) - -import pywt -from pywt._extensions._swt import swt_axis - -# Check that float32 and complex64 are preserved. Other real types get -# converted to float64. -dtypes_in = [np.int8, np.float16, np.float32, np.float64, np.complex64, - np.complex128] -dtypes_out = [np.float64, np.float32, np.float32, np.float64, np.complex64, - np.complex128] - -# tolerances used in accuracy comparisons -tol_single = 1e-6 -tol_double = 1e-13 - -#### -# 1d multilevel swt tests -#### - - -def test_swt_decomposition(): - x = [3, 7, 1, 3, -2, 6, 4, 6] - db1 = pywt.Wavelet('db1') - atol = tol_double - (cA3, cD3), (cA2, cD2), (cA1, cD1) = pywt.swt(x, db1, level=3) - expected_cA1 = [7.07106781, 5.65685425, 2.82842712, 0.70710678, - 2.82842712, 7.07106781, 7.07106781, 6.36396103] - assert_allclose(cA1, expected_cA1, rtol=1e-8, atol=atol) - expected_cD1 = [-2.82842712, 4.24264069, -1.41421356, 3.53553391, - -5.65685425, 1.41421356, -1.41421356, 2.12132034] - assert_allclose(cD1, expected_cD1, rtol=1e-8, atol=atol) - expected_cA2 = [7, 4.5, 4, 5.5, 7, 9.5, 10, 8.5] - assert_allclose(cA2, expected_cA2, rtol=tol_double, atol=atol) - expected_cD2 = [3, 3.5, 0, -4.5, -3, 0.5, 0, 0.5] - assert_allclose(cD2, expected_cD2, rtol=tol_double, atol=atol) - expected_cA3 = [9.89949494, ] * 8 - assert_allclose(cA3, expected_cA3, rtol=1e-8, atol=atol) - expected_cD3 = [0.00000000, -3.53553391, -4.24264069, -2.12132034, - 0.00000000, 3.53553391, 4.24264069, 2.12132034] - assert_allclose(cD3, expected_cD3, rtol=1e-8, atol=atol) - - # level=1, start_level=1 decomposition should match level=2 - res = pywt.swt(cA1, db1, level=1, start_level=1) - cA2, cD2 = res[0] - assert_allclose(cA2, expected_cA2, rtol=tol_double, atol=atol) - assert_allclose(cD2, expected_cD2, rtol=tol_double, atol=atol) - - coeffs = pywt.swt(x, db1) - assert_(len(coeffs) == 3) - assert_(pywt.swt_max_level(len(x)), 3) - - -def test_swt_max_level(): - # odd sized signal will warn about no levels of decomposition possible - assert_warns(UserWarning, pywt.swt_max_level, 11) - with warnings.catch_warnings(): - warnings.simplefilter('ignore', UserWarning) - assert_equal(pywt.swt_max_level(11), 0) - - # no warnings when >= 1 level of decomposition possible - assert_equal(pywt.swt_max_level(2), 1) # divisible by 2**1 - assert_equal(pywt.swt_max_level(4*3), 2) # divisible by 2**2 - assert_equal(pywt.swt_max_level(16), 4) # divisible by 2**4 - assert_equal(pywt.swt_max_level(16*3), 4) # divisible by 2**4 - - -def test_swt_axis(): - x = [3, 7, 1, 3, -2, 6, 4, 6] - - db1 = pywt.Wavelet('db1') - (cA2, cD2), (cA1, cD1) = pywt.swt(x, db1, level=2) - - # test cases use 2D arrays based on tiling x along an axis and then - # calling swt along the other axis. - for order in ['C', 'F']: - # test SWT of 2D data along default axis (-1) - x_2d = np.asarray(x).reshape((1, -1)) - x_2d = np.concatenate((x_2d, )*5, axis=0) - if order == 'C': - x_2d = np.ascontiguousarray(x_2d) - elif order == 'F': - x_2d = np.asfortranarray(x_2d) - (cA2_2d, cD2_2d), (cA1_2d, cD1_2d) = pywt.swt(x_2d, db1, level=2) - - for c in [cA2_2d, cD2_2d, cA1_2d, cD1_2d]: - assert_(c.shape == x_2d.shape) - # each row should match the 1D result - for row in cA1_2d: - assert_array_equal(row, cA1) - for row in cA2_2d: - assert_array_equal(row, cA2) - for row in cD1_2d: - assert_array_equal(row, cD1) - for row in cD2_2d: - assert_array_equal(row, cD2) - - # test SWT of 2D data along other axis (0) - x_2d = np.asarray(x).reshape((-1, 1)) - x_2d = np.concatenate((x_2d, )*5, axis=1) - if order == 'C': - x_2d = np.ascontiguousarray(x_2d) - elif order == 'F': - x_2d = np.asfortranarray(x_2d) - (cA2_2d, cD2_2d), (cA1_2d, cD1_2d) = pywt.swt(x_2d, db1, level=2, - axis=0) - - for c in [cA2_2d, cD2_2d, cA1_2d, cD1_2d]: - assert_(c.shape == x_2d.shape) - # each column should match the 1D result - for row in cA1_2d.transpose((1, 0)): - assert_array_equal(row, cA1) - for row in cA2_2d.transpose((1, 0)): - assert_array_equal(row, cA2) - for row in cD1_2d.transpose((1, 0)): - assert_array_equal(row, cD1) - for row in cD2_2d.transpose((1, 0)): - assert_array_equal(row, cD2) - - # axis too large - assert_raises(ValueError, pywt.swt, x, db1, level=2, axis=5) - - -def test_swt_iswt_integration(): - # This function performs a round-trip swt/iswt transform test on - # all available types of wavelets in PyWavelets - except the - # 'dmey' wavelet. The latter has been excluded because it does not - # produce very precise results. This is likely due to the fact - # that the 'dmey' wavelet is a discrete approximation of a - # continuous wavelet. All wavelets are tested up to 3 levels. The - # test validates neither swt or iswt as such, but it does ensure - # that they are each other's inverse. - - max_level = 3 - wavelets = pywt.wavelist(kind='discrete') - if 'dmey' in wavelets: - # The 'dmey' wavelet seems to be a bit special - disregard it for now - wavelets.remove('dmey') - for current_wavelet_str in wavelets: - current_wavelet = pywt.Wavelet(current_wavelet_str) - input_length_power = int(np.ceil(np.log2(max( - current_wavelet.dec_len, - current_wavelet.rec_len)))) - input_length = 2**(input_length_power + max_level - 1) - X = np.arange(input_length) - coeffs = pywt.swt(X, current_wavelet, max_level) - Y = pywt.iswt(coeffs, current_wavelet) - assert_allclose(Y, X, rtol=1e-5, atol=1e-7) - - -def test_swt_dtypes(): - wavelet = pywt.Wavelet('haar') - for dt_in, dt_out in zip(dtypes_in, dtypes_out): - errmsg = "wrong dtype returned for {0} input".format(dt_in) - - # swt - x = np.ones(8, dtype=dt_in) - (cA2, cD2), (cA1, cD1) = pywt.swt(x, wavelet, level=2) - assert_(cA2.dtype == cD2.dtype == cA1.dtype == cD1.dtype == dt_out, - "swt: " + errmsg) - - # swt2 - x = np.ones((8, 8), dtype=dt_in) - cA, (cH, cV, cD) = pywt.swt2(x, wavelet, level=1)[0] - assert_(cA.dtype == cH.dtype == cV.dtype == cD.dtype == dt_out, - "swt2: " + errmsg) - - -def test_swt_roundtrip_dtypes(): - # verify perfect reconstruction for all dtypes - rstate = np.random.RandomState(5) - wavelet = pywt.Wavelet('haar') - for dt_in, dt_out in zip(dtypes_in, dtypes_out): - # swt, iswt - x = rstate.standard_normal((8, )).astype(dt_in) - c = pywt.swt(x, wavelet, level=2) - xr = pywt.iswt(c, wavelet) - assert_allclose(x, xr, rtol=1e-6, atol=1e-7) - - # swt2, iswt2 - x = rstate.standard_normal((8, 8)).astype(dt_in) - c = pywt.swt2(x, wavelet, level=2) - xr = pywt.iswt2(c, wavelet) - assert_allclose(x, xr, rtol=1e-6, atol=1e-7) - - -def test_swt_default_level_by_axis(): - # make sure default number of levels matches the max level along the axis - wav = 'db2' - x = np.ones((2**3, 2**4, 2**5)) - for axis in (0, 1, 2): - sdec = pywt.swt(x, wav, level=None, start_level=0, axis=axis) - assert_equal(len(sdec), pywt.swt_max_level(x.shape[axis])) - - -def test_swt2_ndim_error(): - x = np.ones(8) - with warnings.catch_warnings(): - warnings.simplefilter('ignore', FutureWarning) - assert_raises(ValueError, pywt.swt2, x, 'haar', level=1) - - -@dec.slow -def test_swt2_iswt2_integration(wavelets=None): - # This function performs a round-trip swt2/iswt2 transform test on - # all available types of wavelets in PyWavelets - except the - # 'dmey' wavelet. The latter has been excluded because it does not - # produce very precise results. This is likely due to the fact - # that the 'dmey' wavelet is a discrete approximation of a - # continuous wavelet. All wavelets are tested up to 3 levels. The - # test validates neither swt2 or iswt2 as such, but it does ensure - # that they are each other's inverse. - - max_level = 3 - if wavelets is None: - wavelets = pywt.wavelist(kind='discrete') - if 'dmey' in wavelets: - # The 'dmey' wavelet is a special case - disregard it for now - wavelets.remove('dmey') - for current_wavelet_str in wavelets: - current_wavelet = pywt.Wavelet(current_wavelet_str) - input_length_power = int(np.ceil(np.log2(max( - current_wavelet.dec_len, - current_wavelet.rec_len)))) - input_length = 2**(input_length_power + max_level - 1) - X = np.arange(input_length**2).reshape(input_length, input_length) - - coeffs = pywt.swt2(X, current_wavelet, max_level) - Y = pywt.iswt2(coeffs, current_wavelet) - assert_allclose(Y, X, rtol=1e-5, atol=1e-5) - - -def test_swt2_iswt2_quick(): - test_swt2_iswt2_integration(wavelets=['db1', ]) - - -def test_swt2_iswt2_non_square(wavelets=None): - for nrows in [8, 16, 48]: - X = np.arange(nrows*32).reshape(nrows, 32) - current_wavelet = 'db1' - with warnings.catch_warnings(): - warnings.simplefilter('ignore', FutureWarning) - coeffs = pywt.swt2(X, current_wavelet, level=2) - Y = pywt.iswt2(coeffs, current_wavelet) - assert_allclose(Y, X, rtol=tol_single, atol=tol_single) - - -def test_swt2_axes(): - atol = 1e-14 - current_wavelet = pywt.Wavelet('db2') - input_length_power = int(np.ceil(np.log2(max( - current_wavelet.dec_len, - current_wavelet.rec_len)))) - input_length = 2**(input_length_power) - X = np.arange(input_length**2).reshape(input_length, input_length) - - (cA1, (cH1, cV1, cD1)) = pywt.swt2(X, current_wavelet, level=1)[0] - # opposite order - (cA2, (cH2, cV2, cD2)) = pywt.swt2(X, current_wavelet, level=1, - axes=(1, 0))[0] - assert_allclose(cA1, cA2, atol=atol) - assert_allclose(cH1, cV2, atol=atol) - assert_allclose(cV1, cH2, atol=atol) - assert_allclose(cD1, cD2, atol=atol) - - # duplicate axes not allowed - assert_raises(ValueError, pywt.swt2, X, current_wavelet, 1, - axes=(0, 0)) - # too few axes - assert_raises(ValueError, pywt.swt2, X, current_wavelet, 1, axes=(0, )) - - -def test_iswt2_2d_only(): - # iswt2 is not currently compatible with data that is not 2D - x_3d = np.ones((4, 4, 4)) - c = pywt.swt2(x_3d, 'haar', level=1) - assert_raises(ValueError, pywt.iswt2, c, 'haar') - - -def test_swtn_axes(): - atol = 1e-14 - current_wavelet = pywt.Wavelet('db2') - input_length_power = int(np.ceil(np.log2(max( - current_wavelet.dec_len, - current_wavelet.rec_len)))) - input_length = 2**(input_length_power) - X = np.arange(input_length**2).reshape(input_length, input_length) - coeffs = pywt.swtn(X, current_wavelet, level=1, axes=None)[0] - # opposite order - coeffs2 = pywt.swtn(X, current_wavelet, level=1, axes=(1, 0))[0] - assert_allclose(coeffs['aa'], coeffs2['aa'], atol=atol) - assert_allclose(coeffs['ad'], coeffs2['da'], atol=atol) - assert_allclose(coeffs['da'], coeffs2['ad'], atol=atol) - assert_allclose(coeffs['dd'], coeffs2['dd'], atol=atol) - - # 0-level transform - empty = pywt.swtn(X, current_wavelet, level=0) - assert_equal(empty, []) - - # duplicate axes not allowed - assert_raises(ValueError, pywt.swtn, X, current_wavelet, 1, axes=(0, 0)) - - # data.ndim = 0 - assert_raises(ValueError, pywt.swtn, np.asarray([]), current_wavelet, 1) - - # start_level too large - assert_raises(ValueError, pywt.swtn, X, current_wavelet, - level=1, start_level=2) - - # level < 1 in swt_axis call - assert_raises(ValueError, swt_axis, X, current_wavelet, level=0, - start_level=0) - # odd-sized data not allowed - assert_raises(ValueError, swt_axis, X[:-1, :], current_wavelet, level=0, - start_level=0, axis=0) - - -@dec.slow -def test_swtn_iswtn_integration(wavelets=None): - # This function performs a round-trip swtn/iswtn transform for various - # possible combinations of: - # 1.) 1 out of 2 axes of a 2D array - # 2.) 2 out of 3 axes of a 3D array - # - # To keep test time down, only wavelets of length <= 8 are run. - # - # This test does not validate swtn or iswtn individually, but only - # confirms that iswtn yields an (almost) perfect reconstruction of swtn. - max_level = 3 - if wavelets is None: - wavelets = pywt.wavelist(kind='discrete') - if 'dmey' in wavelets: - # The 'dmey' wavelet is a special case - disregard it for now - wavelets.remove('dmey') - for ndim_transform in range(1, 3): - ndim = ndim_transform + 1 - for axes in combinations(range(ndim), ndim_transform): - for current_wavelet_str in wavelets: - wav = pywt.Wavelet(current_wavelet_str) - if wav.dec_len > 8: - continue # avoid excessive test duration - input_length_power = int(np.ceil(np.log2(max( - wav.dec_len, - wav.rec_len)))) - N = 2**(input_length_power + max_level - 1) - X = np.arange(N**ndim).reshape((N, )*ndim) - - coeffs = pywt.swtn(X, wav, max_level, axes=axes) - coeffs_copy = deepcopy(coeffs) - Y = pywt.iswtn(coeffs, wav, axes=axes) - assert_allclose(Y, X, rtol=1e-5, atol=1e-5) - - # verify the inverse transform didn't modify any coeffs - for c, c2 in zip(coeffs, coeffs_copy): - for k, v in c.items(): - assert_array_equal(c2[k], v) - - -def test_swtn_iswtn_quick(): - test_swtn_iswtn_integration(wavelets=['db1', ]) - - -def test_iswtn_errors(): - x = np.arange(8**3).reshape(8, 8, 8) - max_level = 2 - axes = (0, 1) - w = pywt.Wavelet('db1') - coeffs = pywt.swtn(x, w, max_level, axes=axes) - - # more axes than dimensions transformed - assert_raises(ValueError, pywt.iswtn, coeffs, w, axes=(0, 1, 2)) - # duplicate axes not allowed - assert_raises(ValueError, pywt.iswtn, coeffs, w, axes=(0, 0)) - # mismatched coefficient size - coeffs[0]['da'] = coeffs[0]['da'][:-1, :] - assert_raises(RuntimeError, pywt.iswtn, coeffs, w, axes=axes) - - -def test_per_axis_wavelets(): - # tests seperate wavelet for each axis. - rstate = np.random.RandomState(1234) - data = rstate.randn(16, 16, 16) - level = 3 - - # wavelet can be a string or wavelet object - wavelets = (pywt.Wavelet('haar'), 'sym2', 'db4') - - coefs = pywt.swtn(data, wavelets, level=level) - assert_allclose(pywt.iswtn(coefs, wavelets), data, atol=1e-14) - - # 1-tuple also okay - coefs = pywt.swtn(data, wavelets[:1], level=level) - assert_allclose(pywt.iswtn(coefs, wavelets[:1]), data, atol=1e-14) - - # length of wavelets doesn't match the length of axes - assert_raises(ValueError, pywt.swtn, data, wavelets[:2], level) - assert_raises(ValueError, pywt.iswtn, coefs, wavelets[:2]) - - with warnings.catch_warnings(): - warnings.simplefilter('ignore', FutureWarning) - # swt2/iswt2 also support per-axis wavelets/modes - data2 = data[..., 0] - coefs2 = pywt.swt2(data2, wavelets[:2], level) - assert_allclose(pywt.iswt2(coefs2, wavelets[:2]), data2, atol=1e-14) - - -def test_error_on_continuous_wavelet(): - # A ValueError is raised if a Continuous wavelet is selected - data = np.ones((16, 16)) - for dec_func, rec_func in zip([pywt.swt, pywt.swt2, pywt.swtn], - [pywt.iswt, pywt.iswt2, pywt.iswtn]): - for cwave in ['morl', pywt.DiscreteContinuousWavelet('morl')]: - assert_raises(ValueError, dec_func, data, wavelet=cwave, - level=3) - - c = dec_func(data, 'db1', level=3) - assert_raises(ValueError, rec_func, c, wavelet=cwave) - - -if __name__ == '__main__': - run_module_suite() diff --git a/.eggs/PyWavelets-1.0.0-py3.7-linux-x86_64.egg/pywt/tests/test_thresholding.py b/.eggs/PyWavelets-1.0.0-py3.7-linux-x86_64.egg/pywt/tests/test_thresholding.py deleted file mode 100644 index b618b94a..00000000 --- a/.eggs/PyWavelets-1.0.0-py3.7-linux-x86_64.egg/pywt/tests/test_thresholding.py +++ /dev/null @@ -1,174 +0,0 @@ -from __future__ import division, print_function, absolute_import -import numpy as np -from numpy.testing import (assert_allclose, run_module_suite, assert_raises, - assert_, assert_equal) - -import pywt - - -float_dtypes = [np.float32, np.float64, np.complex64, np.complex128] -real_dtypes = [np.float32, np.float64] - - -def _sign(x): - # Matlab-like sign function (numpy uses a different convention). - return x / np.abs(x) - - -def _soft(x, thresh): - """soft thresholding supporting complex values. - - Notes - ----- - This version is not robust to zeros in x. - """ - return _sign(x) * np.maximum(np.abs(x) - thresh, 0) - - -def test_threshold(): - data = np.linspace(1, 4, 7) - - # soft - soft_result = [0., 0., 0., 0.5, 1., 1.5, 2.] - assert_allclose(pywt.threshold(data, 2, 'soft'), - np.array(soft_result), rtol=1e-12) - assert_allclose(pywt.threshold(-data, 2, 'soft'), - -np.array(soft_result), rtol=1e-12) - assert_allclose(pywt.threshold([[1, 2]] * 2, 1, 'soft'), - [[0, 1]] * 2, rtol=1e-12) - assert_allclose(pywt.threshold([[1, 2]] * 2, 2, 'soft'), - [[0, 0]] * 2, rtol=1e-12) - - # soft thresholding complex values - assert_allclose(pywt.threshold([[1j, 2j]] * 2, 1, 'soft'), - [[0j, 1j]] * 2, rtol=1e-12) - assert_allclose(pywt.threshold([[1+1j, 2+2j]] * 2, 6, 'soft'), - [[0, 0]] * 2, rtol=1e-12) - complex_data = [[1+2j, 2+2j]]*2 - for thresh in [1, 2]: - assert_allclose(pywt.threshold(complex_data, thresh, 'soft'), - _soft(complex_data, thresh), rtol=1e-12) - - # test soft thresholding with non-default substitute argument - s = 5 - assert_allclose(pywt.threshold([[1j, 2]] * 2, 1.5, 'soft', substitute=s), - [[s, 0.5]] * 2, rtol=1e-12) - - # soft: no divide by zero warnings when input contains zeros - assert_allclose(pywt.threshold(np.zeros(16), 2, 'soft'), - np.zeros(16), rtol=1e-12) - - # hard - hard_result = [0., 0., 2., 2.5, 3., 3.5, 4.] - assert_allclose(pywt.threshold(data, 2, 'hard'), - np.array(hard_result), rtol=1e-12) - assert_allclose(pywt.threshold(-data, 2, 'hard'), - -np.array(hard_result), rtol=1e-12) - assert_allclose(pywt.threshold([[1, 2]] * 2, 1, 'hard'), - [[1, 2]] * 2, rtol=1e-12) - assert_allclose(pywt.threshold([[1, 2]] * 2, 2, 'hard'), - [[0, 2]] * 2, rtol=1e-12) - assert_allclose(pywt.threshold([[1, 2]] * 2, 2, 'hard', substitute=s), - [[s, 2]] * 2, rtol=1e-12) - assert_allclose(pywt.threshold([[1+1j, 2+2j]] * 2, 2, 'hard'), - [[0, 2+2j]] * 2, rtol=1e-12) - - # greater - greater_result = [0., 0., 2., 2.5, 3., 3.5, 4.] - assert_allclose(pywt.threshold(data, 2, 'greater'), - np.array(greater_result), rtol=1e-12) - assert_allclose(pywt.threshold([[1, 2]] * 2, 1, 'greater'), - [[1, 2]] * 2, rtol=1e-12) - assert_allclose(pywt.threshold([[1, 2]] * 2, 2, 'greater'), - [[0, 2]] * 2, rtol=1e-12) - assert_allclose(pywt.threshold([[1, 2]] * 2, 2, 'greater', substitute=s), - [[s, 2]] * 2, rtol=1e-12) - # greater doesn't allow complex-valued inputs - assert_raises(ValueError, pywt.threshold, [1j, 2j], 2, 'greater') - - # less - assert_allclose(pywt.threshold(data, 2, 'less'), - np.array([1., 1.5, 2., 0., 0., 0., 0.]), rtol=1e-12) - assert_allclose(pywt.threshold([[1, 2]] * 2, 1, 'less'), - [[1, 0]] * 2, rtol=1e-12) - assert_allclose(pywt.threshold([[1, 2]] * 2, 1, 'less', substitute=s), - [[1, s]] * 2, rtol=1e-12) - assert_allclose(pywt.threshold([[1, 2]] * 2, 2, 'less'), - [[1, 2]] * 2, rtol=1e-12) - - # less doesn't allow complex-valued inputs - assert_raises(ValueError, pywt.threshold, [1j, 2j], 2, 'less') - - # invalid - assert_raises(ValueError, pywt.threshold, data, 2, 'foo') - - -def test_nonnegative_garotte(): - thresh = 0.3 - data_real = np.linspace(-1, 1, 100) - for dtype in float_dtypes: - if dtype in real_dtypes: - data = np.asarray(data_real, dtype=dtype) - else: - data = np.asarray(data_real + 0.1j, dtype=dtype) - d_hard = pywt.threshold(data, thresh, 'hard') - d_soft = pywt.threshold(data, thresh, 'soft') - d_garotte = pywt.threshold(data, thresh, 'garotte') - - # check dtypes - assert_equal(d_hard.dtype, data.dtype) - assert_equal(d_soft.dtype, data.dtype) - assert_equal(d_garotte.dtype, data.dtype) - - # values < threshold are zero - lt = np.where(np.abs(data) < thresh) - assert_(np.all(d_garotte[lt] == 0)) - - # values > than the threshold are intermediate between soft and hard - gt = np.where(np.abs(data) > thresh) - gt_abs_garotte = np.abs(d_garotte[gt]) - assert_(np.all(gt_abs_garotte < np.abs(d_hard[gt]))) - assert_(np.all(gt_abs_garotte > np.abs(d_soft[gt]))) - - -def test_threshold_firm(): - thresh = 0.2 - thresh2 = 3 * thresh - data_real = np.linspace(-1, 1, 100) - for dtype in float_dtypes: - if dtype in real_dtypes: - data = np.asarray(data_real, dtype=dtype) - else: - data = np.asarray(data_real + 0.1j, dtype=dtype) - if data.real.dtype == np.float32: - rtol = atol = 1e-6 - else: - rtol = atol = 1e-14 - d_hard = pywt.threshold(data, thresh, 'hard') - d_soft = pywt.threshold(data, thresh, 'soft') - d_firm = pywt.threshold_firm(data, thresh, thresh2) - - # check dtypes - assert_equal(d_hard.dtype, data.dtype) - assert_equal(d_soft.dtype, data.dtype) - assert_equal(d_firm.dtype, data.dtype) - - # values < threshold are zero - lt = np.where(np.abs(data) < thresh) - assert_(np.all(d_firm[lt] == 0)) - - # values > than the threshold are equal to hard-thresholding - gt = np.where(np.abs(data) >= thresh2) - assert_allclose(np.abs(d_hard[gt]), np.abs(d_firm[gt]), - rtol=rtol, atol=atol) - - # other values are intermediate between soft and hard thresholding - mt = np.where(np.logical_and(np.abs(data) > thresh, - np.abs(data) < thresh2)) - mt_abs_firm = np.abs(d_firm[mt]) - assert_(np.all(mt_abs_firm < np.abs(d_hard[mt]))) - assert_(np.all(mt_abs_firm > np.abs(d_soft[mt]))) - - -if __name__ == '__main__': - run_module_suite() diff --git a/.eggs/PyWavelets-1.0.0-py3.7-linux-x86_64.egg/pywt/tests/test_wavelet.py b/.eggs/PyWavelets-1.0.0-py3.7-linux-x86_64.egg/pywt/tests/test_wavelet.py deleted file mode 100644 index 99187f24..00000000 --- a/.eggs/PyWavelets-1.0.0-py3.7-linux-x86_64.egg/pywt/tests/test_wavelet.py +++ /dev/null @@ -1,270 +0,0 @@ -#!/usr/bin/env python -from __future__ import division, print_function, absolute_import - -import numpy as np -from numpy.testing import run_module_suite, assert_allclose, assert_ - -import pywt - - -def test_wavelet_properties(): - w = pywt.Wavelet('db3') - - # Name - assert_(w.name == 'db3') - assert_(w.short_family_name == 'db') - assert_(w.family_name, 'Daubechies') - - # String representation - fields = ('Family name', 'Short name', 'Filters length', 'Orthogonal', - 'Biorthogonal', 'Symmetry') - for field in fields: - assert_(field in str(w)) - - # Filter coefficients - dec_lo = [0.03522629188210, -0.08544127388224, -0.13501102001039, - 0.45987750211933, 0.80689150931334, 0.33267055295096] - dec_hi = [-0.33267055295096, 0.80689150931334, -0.45987750211933, - -0.13501102001039, 0.08544127388224, 0.03522629188210] - rec_lo = [0.33267055295096, 0.80689150931334, 0.45987750211933, - -0.13501102001039, -0.08544127388224, 0.03522629188210] - rec_hi = [0.03522629188210, 0.08544127388224, -0.13501102001039, - -0.45987750211933, 0.80689150931334, -0.33267055295096] - assert_allclose(w.dec_lo, dec_lo) - assert_allclose(w.dec_hi, dec_hi) - assert_allclose(w.rec_lo, rec_lo) - assert_allclose(w.rec_hi, rec_hi) - - assert_(len(w.filter_bank) == 4) - - # Orthogonality - assert_(w.orthogonal) - assert_(w.biorthogonal) - - # Symmetry - assert_(w.symmetry) - - # Vanishing moments - assert_(w.vanishing_moments_phi == 0) - assert_(w.vanishing_moments_psi == 3) - - -def test_wavelet_coefficients(): - families = ('db', 'sym', 'coif', 'bior', 'rbio') - wavelets = sum([pywt.wavelist(name) for name in families], []) - for wavelet in wavelets: - if (pywt.Wavelet(wavelet).orthogonal): - yield check_coefficients_orthogonal, wavelet - elif(pywt.Wavelet(wavelet).biorthogonal): - yield check_coefficients_biorthogonal, wavelet - else: - yield check_coefficients, wavelet - - -def check_coefficients_orthogonal(wavelet): - - epsilon = 5e-11 - level = 5 - w = pywt.Wavelet(wavelet) - phi, psi, x = w.wavefun(level=level) - - # Lowpass filter coefficients sum to sqrt2 - res = np.sum(w.dec_lo)-np.sqrt(2) - msg = ('[RMS_REC > EPSILON] for Wavelet: %s, rms=%.3g' % (wavelet, res)) - assert_(res < epsilon, msg=msg) - # sum even coef = sum odd coef = 1 / sqrt(2) - res = np.sum(w.dec_lo[::2])-1./np.sqrt(2) - msg = ('[RMS_REC > EPSILON] for Wavelet: %s, rms=%.3g' % (wavelet, res)) - assert_(res < epsilon, msg=msg) - - res = np.sum(w.dec_lo[1::2])-1./np.sqrt(2) - msg = ('[RMS_REC > EPSILON] for Wavelet: %s, rms=%.3g' % (wavelet, res)) - assert_(res < epsilon, msg=msg) - # Highpass filter coefficients sum to zero - res = np.sum(w.dec_hi) - msg = ('[RMS_REC > EPSILON] for Wavelet: %s, rms=%.3g' % (wavelet, res)) - assert_(res < epsilon, msg=msg) - # Scaling function integrates to unity - - res = np.sum(phi) - 2**level - msg = ('[RMS_REC > EPSILON] for Wavelet: %s, rms=%.3g' % (wavelet, res)) - assert_(res < epsilon, msg=msg) - # Wavelet function is orthogonal to the scaling function at the same scale - res = np.sum(phi*psi) - msg = ('[RMS_REC > EPSILON] for Wavelet: %s, rms=%.3g' % (wavelet, res)) - assert_(res < epsilon, msg=msg) - # The lowpass and highpass filter coefficients are orthogonal - res = np.sum(np.array(w.dec_lo)*np.array(w.dec_hi)) - msg = ('[RMS_REC > EPSILON] for Wavelet: %s, rms=%.3g' % (wavelet, res)) - assert_(res < epsilon, msg=msg) - - -def check_coefficients_biorthogonal(wavelet): - - epsilon = 5e-11 - level = 5 - w = pywt.Wavelet(wavelet) - phi_d, psi_d, phi_r, psi_r, x = w.wavefun(level=level) - - # Lowpass filter coefficients sum to sqrt2 - res = np.sum(w.dec_lo)-np.sqrt(2) - msg = ('[RMS_REC > EPSILON] for Wavelet: %s, rms=%.3g' % (wavelet, res)) - assert_(res < epsilon, msg=msg) - # sum even coef = sum odd coef = 1 / sqrt(2) - res = np.sum(w.dec_lo[::2])-1./np.sqrt(2) - msg = ('[RMS_REC > EPSILON] for Wavelet: %s, rms=%.3g' % (wavelet, res)) - assert_(res < epsilon, msg=msg) - res = np.sum(w.dec_lo[1::2])-1./np.sqrt(2) - msg = ('[RMS_REC > EPSILON] for Wavelet: %s, rms=%.3g' % (wavelet, res)) - assert_(res < epsilon, msg=msg) - # Highpass filter coefficients sum to zero - res = np.sum(w.dec_hi) - msg = ('[RMS_REC > EPSILON] for Wavelet: %s, rms=%.3g' % (wavelet, res)) - assert_(res < epsilon, msg=msg) - # Scaling function integrates to unity - res = np.sum(phi_d) - 2**level - msg = ('[RMS_REC > EPSILON] for Wavelet: %s, rms=%.3g' % (wavelet, res)) - assert_(res < epsilon, msg=msg) - res = np.sum(phi_r) - 2**level - msg = ('[RMS_REC > EPSILON] for Wavelet: %s, rms=%.3g' % (wavelet, res)) - assert_(res < epsilon, msg=msg) - - -def check_coefficients(wavelet): - epsilon = 5e-11 - level = 10 - w = pywt.Wavelet(wavelet) - # Lowpass filter coefficients sum to sqrt2 - res = np.sum(w.dec_lo)-np.sqrt(2) - msg = ('[RMS_REC > EPSILON] for Wavelet: %s, rms=%.3g' % (wavelet, res)) - assert_(res < epsilon, msg=msg) - # sum even coef = sum odd coef = 1 / sqrt(2) - res = np.sum(w.dec_lo[::2])-1./np.sqrt(2) - msg = ('[RMS_REC > EPSILON] for Wavelet: %s, rms=%.3g' % (wavelet, res)) - assert_(res < epsilon, msg=msg) - - res = np.sum(w.dec_lo[1::2])-1./np.sqrt(2) - msg = ('[RMS_REC > EPSILON] for Wavelet: %s, rms=%.3g' % (wavelet, res)) - assert_(res < epsilon, msg=msg) - # Highpass filter coefficients sum to zero - res = np.sum(w.dec_hi) - msg = ('[RMS_REC > EPSILON] for Wavelet: %s, rms=%.3g' % (wavelet, res)) - assert_(res < epsilon, msg=msg) - - -class _CustomHaarFilterBank(object): - @property - def filter_bank(self): - val = np.sqrt(2) / 2 - return ([val]*2, [-val, val], [val]*2, [val, -val]) - - -def test_custom_wavelet(): - haar_custom1 = pywt.Wavelet('Custom Haar Wavelet', - filter_bank=_CustomHaarFilterBank()) - haar_custom1.orthogonal = True - haar_custom1.biorthogonal = True - - val = np.sqrt(2) / 2 - filter_bank = ([val]*2, [-val, val], [val]*2, [val, -val]) - haar_custom2 = pywt.Wavelet('Custom Haar Wavelet', - filter_bank=filter_bank) - - # check expected default wavelet properties - assert_(~haar_custom2.orthogonal) - assert_(~haar_custom2.biorthogonal) - assert_(haar_custom2.symmetry == 'unknown') - assert_(haar_custom2.family_name == '') - assert_(haar_custom2.short_family_name == '') - assert_(haar_custom2.vanishing_moments_phi == 0) - assert_(haar_custom2.vanishing_moments_psi == 0) - - # Some properties can be set by the user - haar_custom2.orthogonal = True - haar_custom2.biorthogonal = True - - -def test_wavefun_sym3(): - w = pywt.Wavelet('sym3') - # sym3 is an orthogonal wavelet, so 3 outputs from wavefun - phi, psi, x = w.wavefun(level=3) - assert_(phi.size == 41) - assert_(psi.size == 41) - assert_(x.size == 41) - - assert_allclose(x, np.linspace(0, 5, num=x.size)) - phi_expect = np.array([0.00000000e+00, 1.04132926e-01, 2.52574126e-01, - 3.96525521e-01, 5.70356539e-01, 7.18934305e-01, - 8.70293448e-01, 1.05363620e+00, 1.24921722e+00, - 1.15296888e+00, 9.41669683e-01, 7.55875887e-01, - 4.96118565e-01, 3.28293151e-01, 1.67624969e-01, - -7.33690312e-02, -3.35452855e-01, -3.31221131e-01, - -2.32061503e-01, -1.66854239e-01, -4.34091324e-02, - -2.86152390e-02, -3.63563035e-02, 2.06034491e-02, - 8.30280254e-02, 7.17779073e-02, 3.85914311e-02, - 1.47527100e-02, -2.31896077e-02, -1.86122172e-02, - -1.56211329e-03, -8.70615088e-04, 3.20760857e-03, - 2.34142153e-03, -7.73737194e-04, -2.99879354e-04, - 1.23636238e-04, 0.00000000e+00, 0.00000000e+00, - 0.00000000e+00, 0.00000000e+00]) - - psi_expect = np.array([0.00000000e+00, 1.10265752e-02, 2.67449277e-02, - 4.19878574e-02, 6.03947231e-02, 7.61275365e-02, - 9.21548684e-02, 1.11568926e-01, 1.32278887e-01, - 6.45829680e-02, -3.97635130e-02, -1.38929884e-01, - -2.62428322e-01, -3.62246804e-01, -4.62843343e-01, - -5.89607507e-01, -7.25363076e-01, -3.36865858e-01, - 2.67715108e-01, 8.40176767e-01, 1.55574430e+00, - 1.18688954e+00, 4.20276324e-01, -1.51697311e-01, - -9.42076108e-01, -7.93172332e-01, -3.26343710e-01, - -1.24552779e-01, 2.12909254e-01, 1.75770320e-01, - 1.47523075e-02, 8.22192707e-03, -3.02920592e-02, - -2.21119497e-02, 7.30703025e-03, 2.83200488e-03, - -1.16759765e-03, 0.00000000e+00, 0.00000000e+00, - 0.00000000e+00, 0.00000000e+00]) - - assert_allclose(phi, phi_expect) - assert_allclose(psi, psi_expect) - - -def test_wavefun_bior13(): - w = pywt.Wavelet('bior1.3') - # bior1.3 is not an orthogonal wavelet, so 5 outputs from wavefun - phi_d, psi_d, phi_r, psi_r, x = w.wavefun(level=3) - for arr in [phi_d, psi_d, phi_r, psi_r]: - assert_(arr.size == 40) - - phi_d_expect = np.array([0., -0.00195313, 0.00195313, 0.01757813, - 0.01367188, 0.00390625, -0.03515625, -0.12890625, - -0.15234375, -0.125, -0.09375, -0.0625, 0.03125, - 0.15234375, 0.37890625, 0.78515625, 0.99609375, - 1.08203125, 1.13671875, 1.13671875, 1.08203125, - 0.99609375, 0.78515625, 0.37890625, 0.15234375, - 0.03125, -0.0625, -0.09375, -0.125, -0.15234375, - -0.12890625, -0.03515625, 0.00390625, 0.01367188, - 0.01757813, 0.00195313, -0.00195313, 0., 0., 0.]) - phi_r_expect = np.zeros(x.size, dtype=np.float) - phi_r_expect[15:23] = 1 - - psi_d_expect = np.array([0, 0, 0, 0, 0, 0, 0, 0, 0, - 0.015625, -0.015625, -0.140625, -0.109375, - -0.03125, 0.28125, 1.03125, 1.21875, 1.125, 0.625, - -0.625, -1.125, -1.21875, -1.03125, -0.28125, - 0.03125, 0.109375, 0.140625, 0.015625, -0.015625, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0]) - - psi_r_expect = np.zeros(x.size, dtype=np.float) - psi_r_expect[7:15] = -0.125 - psi_r_expect[15:19] = 1 - psi_r_expect[19:23] = -1 - psi_r_expect[23:31] = 0.125 - - assert_allclose(x, np.linspace(0, 5, x.size, endpoint=False)) - assert_allclose(phi_d, phi_d_expect, rtol=1e-5, atol=1e-9) - assert_allclose(phi_r, phi_r_expect, rtol=1e-10, atol=1e-12) - assert_allclose(psi_d, psi_d_expect, rtol=1e-10, atol=1e-12) - assert_allclose(psi_r, psi_r_expect, rtol=1e-10, atol=1e-12) - - -if __name__ == '__main__': - run_module_suite() diff --git a/.eggs/PyWavelets-1.0.0-py3.7-linux-x86_64.egg/pywt/tests/test_wp.py b/.eggs/PyWavelets-1.0.0-py3.7-linux-x86_64.egg/pywt/tests/test_wp.py deleted file mode 100644 index 9025b00e..00000000 --- a/.eggs/PyWavelets-1.0.0-py3.7-linux-x86_64.egg/pywt/tests/test_wp.py +++ /dev/null @@ -1,193 +0,0 @@ -#!/usr/bin/env python - -from __future__ import division, print_function, absolute_import - -import numpy as np -from numpy.testing import (run_module_suite, assert_allclose, assert_, - assert_raises, assert_equal) - -import pywt - - -def test_wavelet_packet_structure(): - x = [1, 2, 3, 4, 5, 6, 7, 8] - wp = pywt.WaveletPacket(data=x, wavelet='db1', mode='symmetric') - - assert_(wp.data == [1, 2, 3, 4, 5, 6, 7, 8]) - assert_(wp.path == '') - assert_(wp.level == 0) - assert_(wp['ad'].maxlevel == 3) - - -def test_traversing_wp_tree(): - x = [1, 2, 3, 4, 5, 6, 7, 8] - wp = pywt.WaveletPacket(data=x, wavelet='db1', mode='symmetric') - - assert_(wp.maxlevel == 3) - - # First level - assert_allclose(wp['a'].data, np.array([2.12132034356, 4.949747468306, - 7.778174593052, 10.606601717798]), - rtol=1e-12) - - # Second level - assert_allclose(wp['aa'].data, np.array([5., 13.]), rtol=1e-12) - - # Third level - assert_allclose(wp['aaa'].data, np.array([12.727922061358]), rtol=1e-12) - - -def test_acess_path(): - x = [1, 2, 3, 4, 5, 6, 7, 8] - wp = pywt.WaveletPacket(data=x, wavelet='db1', mode='symmetric') - - assert_(wp['a'].path == 'a') - assert_(wp['aa'].path == 'aa') - assert_(wp['aaa'].path == 'aaa') - - # Maximum level reached: - assert_raises(IndexError, lambda: wp['aaaa'].path) - - # Wrong path - assert_raises(ValueError, lambda: wp['ac'].path) - - -def test_access_node_atributes(): - x = [1, 2, 3, 4, 5, 6, 7, 8] - wp = pywt.WaveletPacket(data=x, wavelet='db1', mode='symmetric') - - assert_allclose(wp['ad'].data, np.array([-2., -2.]), rtol=1e-12) - assert_(wp['ad'].path == 'ad') - assert_(wp['ad'].node_name == 'd') - assert_(wp['ad'].parent.path == 'a') - assert_(wp['ad'].level == 2) - assert_(wp['ad'].maxlevel == 3) - assert_(wp['ad'].mode == 'symmetric') - - -def test_collecting_nodes(): - x = [1, 2, 3, 4, 5, 6, 7, 8] - wp = pywt.WaveletPacket(data=x, wavelet='db1', mode='symmetric') - - # All nodes in natural order - assert_([node.path for node in wp.get_level(3, 'natural')] == - ['aaa', 'aad', 'ada', 'add', 'daa', 'dad', 'dda', 'ddd']) - - # and in frequency order. - assert_([node.path for node in wp.get_level(3, 'freq')] == - ['aaa', 'aad', 'add', 'ada', 'dda', 'ddd', 'dad', 'daa']) - - -def test_reconstructing_data(): - x = [1, 2, 3, 4, 5, 6, 7, 8] - wp = pywt.WaveletPacket(data=x, wavelet='db1', mode='symmetric') - - # Create another Wavelet Packet and feed it with some data. - new_wp = pywt.WaveletPacket(data=None, wavelet='db1', mode='symmetric') - new_wp['aa'] = wp['aa'].data - new_wp['ad'] = [-2., -2.] - - # For convenience, :attr:`Node.data` gets automatically extracted - # from the :class:`Node` object: - new_wp['d'] = wp['d'] - - # Reconstruct data from aa, ad, and d packets. - assert_allclose(new_wp.reconstruct(update=False), x, rtol=1e-12) - - # The node's :attr:`~Node.data` will not be updated - assert_(new_wp.data is None) - - # When `update` is True: - assert_allclose(new_wp.reconstruct(update=True), x, rtol=1e-12) - assert_allclose(new_wp.data, np.arange(1, 9), rtol=1e-12) - - assert_([n.path for n in new_wp.get_leaf_nodes(False)] == - ['aa', 'ad', 'd']) - assert_([n.path for n in new_wp.get_leaf_nodes(True)] == - ['aaa', 'aad', 'ada', 'add', 'daa', 'dad', 'dda', 'ddd']) - - -def test_removing_nodes(): - x = [1, 2, 3, 4, 5, 6, 7, 8] - wp = pywt.WaveletPacket(data=x, wavelet='db1', mode='symmetric') - wp.get_level(2) - - dataleafs = [n.data for n in wp.get_leaf_nodes(False)] - expected = np.array([[5., 13.], [-2, -2], [-1, -1], [0, 0]]) - - for i in range(4): - assert_allclose(dataleafs[i], expected[i, :], atol=1e-12) - - node = wp['ad'] - del(wp['ad']) - dataleafs = [n.data for n in wp.get_leaf_nodes(False)] - expected = np.array([[5., 13.], [-1, -1], [0, 0]]) - - for i in range(3): - assert_allclose(dataleafs[i], expected[i, :], atol=1e-12) - - wp.reconstruct() - # The reconstruction is: - assert_allclose(wp.reconstruct(), - np.array([2., 3., 2., 3., 6., 7., 6., 7.]), rtol=1e-12) - - # Restore the data - wp['ad'].data = node.data - - dataleafs = [n.data for n in wp.get_leaf_nodes(False)] - expected = np.array([[5., 13.], [-2, -2], [-1, -1], [0, 0]]) - - for i in range(4): - assert_allclose(dataleafs[i], expected[i, :], atol=1e-12) - - assert_allclose(wp.reconstruct(), np.arange(1, 9), rtol=1e-12) - - -def test_wavelet_packet_dtypes(): - N = 32 - for dtype in [np.float32, np.float64, np.complex64, np.complex128]: - x = np.random.randn(N).astype(dtype) - if np.iscomplexobj(x): - x = x + 1j*np.random.randn(N).astype(x.real.dtype) - wp = pywt.WaveletPacket(data=x, wavelet='db1', mode='symmetric') - # no unnecessary copy made - assert_(wp.data is x) - - # assiging to a node should not change supported dtypes - wp['d'] = wp['d'].data - assert_equal(wp['d'].data.dtype, x.dtype) - - # full decomposition - wp.get_level(wp.maxlevel) - - # reconstruction from coefficients should preserve dtype - r = wp.reconstruct(False) - assert_equal(r.dtype, x.dtype) - assert_allclose(r, x, atol=1e-5, rtol=1e-5) - - # first element of the tuple is the input dtype - # second element of the tuple is the transform dtype - dtype_pairs = [(np.uint8, np.float64), - (np.intp, np.float64), ] - if hasattr(np, "complex256"): - dtype_pairs += [(np.complex256, np.complex128), ] - if hasattr(np, "half"): - dtype_pairs += [(np.half, np.float32), ] - for (dtype, transform_dtype) in dtype_pairs: - x = np.arange(N, dtype=dtype) - wp = pywt.WaveletPacket(x, wavelet='db1', mode='symmetric') - - # no unnecessary copy made of top-level data - assert_(wp.data is x) - - # full decomposition - wp.get_level(wp.maxlevel) - - # reconstructed data will have modified dtype - r = wp.reconstruct(False) - assert_equal(r.dtype, transform_dtype) - assert_allclose(r, x.astype(transform_dtype), atol=1e-5, rtol=1e-5) - - -if __name__ == '__main__': - run_module_suite() diff --git a/.eggs/PyWavelets-1.0.0-py3.7-linux-x86_64.egg/pywt/tests/test_wp2d.py b/.eggs/PyWavelets-1.0.0-py3.7-linux-x86_64.egg/pywt/tests/test_wp2d.py deleted file mode 100644 index ee6c1536..00000000 --- a/.eggs/PyWavelets-1.0.0-py3.7-linux-x86_64.egg/pywt/tests/test_wp2d.py +++ /dev/null @@ -1,172 +0,0 @@ -#!/usr/bin/env python - -from __future__ import division, print_function, absolute_import - -import numpy as np -from numpy.testing import (run_module_suite, assert_allclose, assert_, - assert_raises, assert_equal) - -import pywt - - -def test_traversing_tree_2d(): - x = np.array([[1, 2, 3, 4, 5, 6, 7, 8]] * 8, dtype=np.float64) - wp = pywt.WaveletPacket2D(data=x, wavelet='db1', mode='symmetric') - - assert_(np.all(wp.data == x)) - assert_(wp.path == '') - assert_(wp.level == 0) - assert_(wp.maxlevel == 3) - - assert_allclose(wp['a'].data, np.array([[3., 7., 11., 15.]] * 4), - rtol=1e-12) - assert_allclose(wp['h'].data, np.zeros((4, 4)), rtol=1e-12, atol=1e-14) - assert_allclose(wp['v'].data, -np.ones((4, 4)), rtol=1e-12, atol=1e-14) - assert_allclose(wp['d'].data, np.zeros((4, 4)), rtol=1e-12, atol=1e-14) - - assert_allclose(wp['aa'].data, np.array([[10., 26.]] * 2), rtol=1e-12) - - assert_(wp['a']['a'].data is wp['aa'].data) - assert_allclose(wp['aaa'].data, np.array([[36.]]), rtol=1e-12) - - assert_raises(IndexError, lambda: wp['aaaa']) - assert_raises(ValueError, lambda: wp['f']) - - -def test_accessing_node_atributes_2d(): - x = np.array([[1, 2, 3, 4, 5, 6, 7, 8]] * 8, dtype=np.float64) - wp = pywt.WaveletPacket2D(data=x, wavelet='db1', mode='symmetric') - - assert_allclose(wp['av'].data, np.zeros((2, 2)) - 4, rtol=1e-12) - assert_(wp['av'].path == 'av') - assert_(wp['av'].node_name == 'v') - assert_(wp['av'].parent.path == 'a') - - assert_allclose(wp['av'].parent.data, np.array([[3., 7., 11., 15.]] * 4), - rtol=1e-12) - assert_(wp['av'].level == 2) - assert_(wp['av'].maxlevel == 3) - assert_(wp['av'].mode == 'symmetric') - - -def test_collecting_nodes_2d(): - x = np.array([[1, 2, 3, 4, 5, 6, 7, 8]] * 8, dtype=np.float64) - wp = pywt.WaveletPacket2D(data=x, wavelet='db1', mode='symmetric') - - assert_(len(wp.get_level(0)) == 1) - assert_(wp.get_level(0)[0].path == '') - - # First level - assert_(len(wp.get_level(1)) == 4) - assert_([node.path for node in wp.get_level(1)] == ['a', 'h', 'v', 'd']) - - # Second level - assert_(len(wp.get_level(2)) == 16) - paths = [node.path for node in wp.get_level(2)] - expected_paths = ['aa', 'ah', 'av', 'ad', 'ha', 'hh', 'hv', 'hd', 'va', - 'vh', 'vv', 'vd', 'da', 'dh', 'dv', 'dd'] - assert_(paths == expected_paths) - - # Third level. - assert_(len(wp.get_level(3)) == 64) - paths = [node.path for node in wp.get_level(3)] - expected_paths = ['aaa', 'aah', 'aav', 'aad', 'aha', 'ahh', 'ahv', 'ahd', - 'ava', 'avh', 'avv', 'avd', 'ada', 'adh', 'adv', 'add', - 'haa', 'hah', 'hav', 'had', 'hha', 'hhh', 'hhv', 'hhd', - 'hva', 'hvh', 'hvv', 'hvd', 'hda', 'hdh', 'hdv', 'hdd', - 'vaa', 'vah', 'vav', 'vad', 'vha', 'vhh', 'vhv', 'vhd', - 'vva', 'vvh', 'vvv', 'vvd', 'vda', 'vdh', 'vdv', 'vdd', - 'daa', 'dah', 'dav', 'dad', 'dha', 'dhh', 'dhv', 'dhd', - 'dva', 'dvh', 'dvv', 'dvd', 'dda', 'ddh', 'ddv', 'ddd'] - - assert_(paths == expected_paths) - - -def test_data_reconstruction_2d(): - x = np.array([[1, 2, 3, 4, 5, 6, 7, 8]] * 8, dtype=np.float64) - wp = pywt.WaveletPacket2D(data=x, wavelet='db1', mode='symmetric') - - new_wp = pywt.WaveletPacket2D(data=None, wavelet='db1', mode='symmetric') - new_wp['vh'] = wp['vh'].data - new_wp['vv'] = wp['vh'].data - new_wp['vd'] = np.zeros((2, 2), dtype=np.float64) - new_wp['a'] = [[3.0, 7.0, 11.0, 15.0]] * 4 - new_wp['d'] = np.zeros((4, 4), dtype=np.float64) - new_wp['h'] = wp['h'] # all zeros - - assert_allclose(new_wp.reconstruct(update=False), - np.array([[1.5, 1.5, 3.5, 3.5, 5.5, 5.5, 7.5, 7.5]] * 8), - rtol=1e-12) - assert_allclose(wp['va'].data, np.zeros((2, 2)) - 2, rtol=1e-12) - - new_wp['va'] = wp['va'].data - assert_allclose(new_wp.reconstruct(update=False), x, rtol=1e-12) - - -def test_data_reconstruction_delete_nodes_2d(): - x = np.array([[1, 2, 3, 4, 5, 6, 7, 8]] * 8, dtype=np.float64) - wp = pywt.WaveletPacket2D(data=x, wavelet='db1', mode='symmetric') - - new_wp = pywt.WaveletPacket2D(data=None, wavelet='db1', mode='symmetric') - new_wp['vh'] = wp['vh'].data - new_wp['vv'] = wp['vh'].data - new_wp['vd'] = np.zeros((2, 2), dtype=np.float64) - new_wp['a'] = [[3.0, 7.0, 11.0, 15.0]] * 4 - new_wp['d'] = np.zeros((4, 4), dtype=np.float64) - new_wp['h'] = wp['h'] # all zeros - - assert_allclose(new_wp.reconstruct(update=False), - np.array([[1.5, 1.5, 3.5, 3.5, 5.5, 5.5, 7.5, 7.5]] * 8), - rtol=1e-12) - - new_wp['va'] = wp['va'].data - assert_allclose(new_wp.reconstruct(update=False), x, rtol=1e-12) - - del(new_wp['va']) - new_wp['va'] = wp['va'].data - assert_(new_wp.data is None) - - assert_allclose(new_wp.reconstruct(update=True), x, rtol=1e-12) - assert_allclose(new_wp.data, x, rtol=1e-12) - - # TODO: decompose=True - - -def test_lazy_evaluation_2D(): - # Note: internal implementation detail not to be relied on. Testing for - # now for backwards compatibility, but this test may be broken in needed. - x = np.array([[1, 2, 3, 4, 5, 6, 7, 8]] * 8) - wp = pywt.WaveletPacket2D(data=x, wavelet='db1', mode='symmetric') - - assert_(wp.a is None) - assert_allclose(wp['a'].data, np.array([[3., 7., 11., 15.]] * 4), - rtol=1e-12) - assert_allclose(wp.a.data, np.array([[3., 7., 11., 15.]] * 4), rtol=1e-12) - assert_allclose(wp.d.data, np.zeros((4, 4)), rtol=1e-12, atol=1e-12) - - -def test_wavelet_packet_dtypes(): - shape = (16, 16) - for dtype in [np.float32, np.float64, np.complex64, np.complex128]: - x = np.random.randn(*shape).astype(dtype) - if np.iscomplexobj(x): - x = x + 1j*np.random.randn(*shape).astype(x.real.dtype) - wp = pywt.WaveletPacket2D(data=x, wavelet='db1', mode='symmetric') - # no unnecessary copy made - assert_(wp.data is x) - - # assiging to a node should not change supported dtypes - wp['d'] = wp['d'].data - assert_equal(wp['d'].data.dtype, x.dtype) - - # full decomposition - wp.get_level(wp.maxlevel) - - # reconstruction from coefficients should preserve dtype - r = wp.reconstruct(False) - assert_equal(r.dtype, x.dtype) - assert_allclose(r, x, atol=1e-5, rtol=1e-5) - - -if __name__ == '__main__': - run_module_suite() diff --git a/.eggs/PyWavelets-1.0.0-py3.7-linux-x86_64.egg/pywt/version.py b/.eggs/PyWavelets-1.0.0-py3.7-linux-x86_64.egg/pywt/version.py deleted file mode 100644 index c4d3b3c5..00000000 --- a/.eggs/PyWavelets-1.0.0-py3.7-linux-x86_64.egg/pywt/version.py +++ /dev/null @@ -1,10 +0,0 @@ - -# THIS FILE IS GENERATED FROM PYWAVELETS SETUP.PY -short_version = '1.0.0' -version = '1.0.0' -full_version = '1.0.0' -git_revision = 'b58b810df9d1ec4ebb8443ecbd551c5cd5a40a7b' -release = True - -if not release: - version = full_version diff --git a/.eggs/README.txt b/.eggs/README.txt deleted file mode 100644 index 5d016688..00000000 --- a/.eggs/README.txt +++ /dev/null @@ -1,6 +0,0 @@ -This directory contains eggs that were downloaded by setuptools to build, test, and run plug-ins. - -This directory caches those eggs to prevent repeated downloads. - -However, it is safe to delete this directory. - diff --git a/.eggs/docopt-0.6.2-py3.7.egg b/.eggs/docopt-0.6.2-py3.7.egg deleted file mode 100644 index d5166b21..00000000 Binary files a/.eggs/docopt-0.6.2-py3.7.egg and /dev/null differ diff --git a/.gitignore b/.gitignore index 25cabf9b..3b455d67 100755 --- a/.gitignore +++ b/.gitignore @@ -1,7 +1,127 @@ -*.pyc /data -.env /Elastix/*.txt /Elastix/*.log + +activate +*.swp +*.swo .idea +*.pyc +*.egg-info + +# Byte-compiled / optimized / DLL files +__pycache__/ +*.py[cod] +*$py.class + +# C extensions +*.so + +# Distribution / packaging +.Python +build/ +develop-eggs/ +dist/ +downloads/ +eggs/ +.eggs/ +lib/ +lib64/ +parts/ +sdist/ +var/ +wheels/ +share/python-wheels/ +*.egg-info/ +.installed.cfg +*.egg +MANIFEST + +# PyInstaller +# Usually these files are written by a python script from a template +# before PyInstaller builds the exe, so as to inject date/other infos into it. +*.manifest +*.spec + +# Installer logs +pip-log.txt +pip-delete-this-directory.txt + +# Unit test / coverage reports +htmlcov/ +.tox/ +.nox/ +.coverage +.coverage.* +.cache +nosetests.xml +coverage.xml +*.cover +.hypothesis/ +.pytest_cache/ + +# Translations +*.mo +*.pot + +# Django stuff: +*.log +local_settings.py +db.sqlite3 + +# Flask stuff: +instance/ +.webassets-cache + +# Scrapy stuff: +.scrapy + +# Sphinx documentation +doc/_build/ +WORC/doc/_build/ + +# PyBuilder +target/ + +# Jupyter Notebook +.ipynb_checkpoints + +# IPython +profile_default/ +ipython_config.py + +# pyenv +.python-version + +# celery beat schedule file +celerybeat-schedule + +# SageMath parsed files +*.sage.py + +# Environments +.env +.venv +env/ +venv/ +ENV/ +env.bak/ +venv.bak/ + +# Spyder project settings +.spyderproject +.spyproject + +# Rope project settings +.ropeproject + +# mkdocs documentation +/site + +# mypy +.mypy_cache/ +.dmypy.json +dmypy.json +# Pyre type checker +.pyre/ diff --git a/.travis.yml b/.travis.yml index 892da9ee..b9281f0c 100644 --- a/.travis.yml +++ b/.travis.yml @@ -1,18 +1,23 @@ +dist: bionic language: python - python: -- '3.7' + - "3.7" before_install: - sudo apt-get -qq update -- sudo apt-get -qq -y install libblas-dev liblapack-dev libatlas-base-dev gfortran +- sudo apt-get -qq -y install git install: - pip install -r requirements.txt - python setup.py -q install +- pip install -e hg+https://bitbucket.org/bigr_erasmusmc/fastr@develop#egg=fastr +- git clone --single-branch --branch develop https://github.com/MStarmans91/WORCTutorial + +env: + - WORCDEBUG=true script: -- python ./tests/tests.py +- python WORCTutorial/WORCTutorialSimple.py notifications: slack: diff --git a/CHANGELOG b/CHANGELOG index 6a530de3..e6a66b42 100644 --- a/CHANGELOG +++ b/CHANGELOG @@ -6,6 +6,72 @@ All notable changes to this project will be documented in this file. The format is based on `Keep a Changelog `_ and this project adheres to `Semantic Versioning `_ +3.1.0 - 2019-10-16 +------------------ + +Added +~~~~~~~ +- Thresholding option in plot_SVM. +- NPV (Negative Preditive Value) to classification metrics. +- Facade for easier interaction with WORC. +- Thresholding option in plot_SVM. +- Function to create fixed splits for cross validation. +- n_splits parameter for train-test cross validation. +- Added generalization score. +- Parameter to choose how many of the optimal settings to save (maxlen). +- Option to combine multiple onevsrest models in plot_SVM. +- StatsticalTestThreshold feature selection for multilabel problems. +- Support for test sets in which only one class is present in various + plotting functions and the metrics. +- Installation: create fastr home if it does not exist yet. +- Boostrapping as performance evaluation in plot_SVM. +- Confidence intervals for boostrapping based on percentile. +- Catch for if patient is in the test set, but not the overall label set. +- Downloader for downloading example datasets. +- ReadTheDocs.yml for configuration of documentation. +- Unit test included in Travis. +- Various detectors. + +Changed +~~~~~~~ +- Plot_SVR is removed: it's now embedded in plot_SVM. +- Moved statistical feature selection to last step in fit and score. +- Also the minimum train and validation score are now saved. +- Put scaler at top of fitandscore function. +- Make link in file conversion if output is same format as input. +- Sort keys in performance output JSON. +- VarianceThreshold features selection on by default. +- Removed grid_scores from SearchCV as support is dropped in sklearn > 0.20 +- Renamed IntermediateFacade to SimpleWORC +- Use inspect to find packagedir + +Fixed +~~~~~ +- Metric computation can now handle it when both the truth and the predicted + labels are from a single class. +- Plotting module now correctly initialized. +- Plot_SVM now also works properly for regression. +- Masks for ROI normalization now properly added. +- Preprocessing: mask needed to be cast to binary. +- Failed workflows now return nan instead of zero for performance. +- Several bugs in multilabel performance evaluation +- Ring in segmentix was in sagital instead of axial direction. +- Added replacenan in features before applying SMOTE. +- Metadata test was not passed to calcfeatures: bugfix. +- Bugfix: overide labels in facade when predict_labels is called. +- Several bugfixes in the overrides in the facade configbuilder. +- Various print commands converted to Python3: .format prints were still + left and sometimes buggy. +- StatisticalTestFeatures and PlotRankedScores tools only accepted cardinality + of 1. +- Bugfixes in many plotting functions: opening files with 'w' instead of 'wb' + due to python3 conversion, Compatibility issues with plot_SVM due to + conversion. +- Except error when Grahpviz is not installed. +- Symlinking in worccastcovert not supported by Windows, reverted to copying. +- Bugfix in create_ensemble in SearchCV when using ensemble = 1. + + 3.0.0 - 2019-05-08 ------------------ diff --git a/CONTRIBUTORS b/CONTRIBUTORS index 000be4c8..8483ebf6 100644 --- a/CONTRIBUTORS +++ b/CONTRIBUTORS @@ -1,2 +1,3 @@ Martijn Starmans -Stefan Klein \ No newline at end of file +Thomas Phil +Stefan Klein diff --git a/README.md b/README.md index ff18db77..993d85b3 100644 --- a/README.md +++ b/README.md @@ -1,6 +1,6 @@ [![Build Status](https://travis-ci.com/MStarmans91/WORC.svg?token=qyvaeq7Cpwu7hJGB98Gp&branch=master)](https://travis-ci.com/MStarmans91/WORC) -# WORC v3.0.0 +# WORC v3.1.0 ## Workflow for Optimal Radiomics Classification @@ -26,7 +26,8 @@ The official documentation can be found at [https://worc.readthedocs.io](https:/ ## Installation WORC currently only supports Unix with Python 3.6+ (tested on 3.7.2 and 3.7.3) systems and -has been tested on Ubuntu 16.04 and 18.04 and Windows 10. +has been tested on Ubuntu 16.04 and 18.04 and Windows 10. For detailed installation +instructions, please check [the ReadTheDocs installation guidelines](https://worc.readthedocs.io/en/latest/static/quick_start.html#installation). The package can be installed through pip: @@ -40,40 +41,28 @@ Make sure you install the requirements first: pip install -r requirements.txt -### Fastr Configuration -The installation will create a FASTR configuration file in the $HOME/.fastr/config.d folder called WORC_config.py. -This file is used for configuring fastr, the pipeline execution toolbox we use. More information can be found at -[the FASTR website](http://fastr.readthedocs.io/en/stable/static/file_description.html#config-file). -In this file, so called mounts are defined, which are used to locate the WORC tools and your inputs and outputs. -Please inspect the mounts and change them if neccesary. +NOTE: The version of PyRadiomics which WORC currently uses requires numpy to be installed beforehand. Make sure you do so, e.g. -``` -echo "machine images.xnat.org -> login admin -> password admin" > ~/.netrc -chmod 600 ~/.netrc -``` + pip install numpy ## 3rd-party packages used in WORC: - - [FASTR (Workflow design and building)](http://fastr.readthedocs.io) + - [fastr (Workflow design and building)](http://fastr.readthedocs.io) - xnat (Collecting data from XNAT) - SimpleITK (Image loading and preprocessing) - [Pyradiomics](https://github.com/radiomics/pyradiomics) - [PREDICT](https://github.com/Svdvoort/PREDICTFastr) -See for other requirements the [requirements file](requirements.txt). +See for other python packages the [requirements file](requirements.txt). ## Start We suggest you start with the [WORC Tutorial](https://github.com/MStarmans91/WORCTutorial). Besides a Jupyter notebook with instructions, we provide there also an example script for you to get started with. -Make sure you input your own data as the sources. Also, check out the unit tests of several tools in the -WORC/resources/fastr_tests directory. The example is explained in more detail in the [documentation](https://worc.readthedocs.io). ## WIP - We are working on improving the documentation. -- We are working on organizing clinically relevant datasets for examples and unit tests. - We are writing the paper on WORC. +- We are expanding the example experiments of WORC with open source datasets. ## License This package is covered by the open source [APACHE 2.0 License](APACHE-LICENSE-2.0). @@ -83,7 +72,8 @@ When using WORC, please cite this repository. ## Contact We are happy to help you with any questions. Please sent us a mail or place an issue on the Github. -We welcome contributions to WORC. For the moment, converting your toolbox into a FASTR tool is satisfactory. +We welcome contributions to WORC. For the moment, converting your toolbox into a FASTR tool is satisfactory: +see also [the fastr tool development documentation](https://fastr.readthedocs.io/en/stable/static/user_manual.html#create-your-own-tool). ## Optional Besides the default installation, there are several optional packages you could install to support WORC. @@ -94,6 +84,9 @@ please make sure you install graphviz. On Ubuntu, simply run apt install graphiv +On Windows, follow the installation instructions provided on the graphviz website. +Make sure you add the executable to the PATH when prompted. + ### Elastix Image registration is included in WORC through [elastix and transformix](http://elastix.isi.uu.nl/). In order to use elastix, please download the binaries and place them in your @@ -108,5 +101,5 @@ for installation instructions. ### XNAT We use the XNATpy package to connect the toolbox to the XNAT online database platforms. You will only -need this when you want to download or upload data from or to XNAT. We advise you to specify -your account settings in a .netrc file when using this feature, such that you do not need to input them on every request: +need this when you use the example dataset we provided, or if you want to download or upload data from or to XNAT. We advise you to specify +your account settings in a .netrc file when using this feature for your own datasets, such that you do not need to input them on every request. diff --git a/README.rst b/README.rst index 7ca0028f..d2848f4f 100644 --- a/README.rst +++ b/README.rst @@ -1,6 +1,6 @@ |Build Status| -WORC v3.0.0 +WORC v3.1.0 =========== Workflow for Optimal Radiomics Classification @@ -39,7 +39,9 @@ Installation WORC currently only supports Unix with Python 3.6+ (tested on 3.7.2 and 3.7.3) systems and has been tested on Ubuntu 16.04 and 18.04 and Windows -10. +10. For detailed installation instructions, please check `the +ReadTheDocs installation +guidelines `__. The package can be installed through pip: @@ -59,36 +61,25 @@ Make sure you install the requirements first: pip install -r requirements.txt -Fastr Configuration -~~~~~~~~~~~~~~~~~~~ - -The installation will create a FASTR configuration file in the -$HOME/.fastr/config.d folder called WORC\_config.py. This file is used -for configuring fastr, the pipeline execution toolbox we use. More -information can be found at `the FASTR -website `__. -In this file, so called mounts are defined, which are used to locate the -WORC tools and your inputs and outputs. Please inspect the mounts and -change them if neccesary. +NOTE: The version of PyRadiomics which WORC currently uses requires +numpy to be installed beforehand. Make sure you do so, e.g. :: - echo "machine images.xnat.org - > login admin - > password admin" > ~/.netrc - chmod 600 ~/.netrc + pip install numpy 3rd-party packages used in WORC: -------------------------------- -- `FASTR (Workflow design and +- `fastr (Workflow design and building) `__ - xnat (Collecting data from XNAT) - SimpleITK (Image loading and preprocessing) - `Pyradiomics `__ - `PREDICT `__ -See for other requirements the `requirements file `__. +See for other python packages the `requirements +file `__. Start ----- @@ -96,18 +87,15 @@ Start We suggest you start with the `WORC Tutorial `__. Besides a Jupyter notebook with instructions, we provide there also an example -script for you to get started with. Make sure you input your own data as -the sources. Also, check out the unit tests of several tools in the -WORC/resources/fastr\_tests directory. The example is explained in more -detail in the `documentation `__. +script for you to get started with. WIP --- - We are working on improving the documentation. -- We are working on organizing clinically relevant datasets for - examples and unit tests. - We are writing the paper on WORC. +- We are expanding the example experiments of WORC with open source + datasets. License ------- @@ -124,7 +112,9 @@ We are happy to help you with any questions. Please sent us a mail or place an issue on the Github. We welcome contributions to WORC. For the moment, converting your -toolbox into a FASTR tool is satisfactory. +toolbox into a FASTR tool is satisfactory: see also `the fastr tool +development +documentation `__. Optional -------- @@ -143,6 +133,10 @@ sure you install graphviz. On Ubuntu, simply run apt install graphiv +On Windows, follow the installation instructions provided on the +graphviz website. Make sure you add the executable to the PATH when +prompted. + Elastix ~~~~~~~ @@ -164,10 +158,11 @@ XNAT ~~~~ We use the XNATpy package to connect the toolbox to the XNAT online -database platforms. You will only need this when you want to download or -upload data from or to XNAT. We advise you to specify your account -settings in a .netrc file when using this feature, such that you do not -need to input them on every request: +database platforms. You will only need this when you use the example +dataset we provided, or if you want to download or upload data from or +to XNAT. We advise you to specify your account settings in a .netrc file +when using this feature for your own datasets, such that you do not need +to input them on every request. .. |Build Status| image:: https://travis-ci.com/MStarmans91/WORC.svg?token=qyvaeq7Cpwu7hJGB98Gp&branch=master :target: https://travis-ci.com/MStarmans91/WORC diff --git a/WORC.egg-info/PKG-INFO b/WORC.egg-info/PKG-INFO deleted file mode 100644 index 02cfb02d..00000000 --- a/WORC.egg-info/PKG-INFO +++ /dev/null @@ -1,201 +0,0 @@ -Metadata-Version: 1.2 -Name: WORC -Version: 3.0.0 -Summary: Workflow for Optimal Radiomics Classification. -Home-page: https://github.com/MStarmans91/WORC -Author: M. Starmans -Author-email: m.starmans@erasmusmc.nl -License: Apache License, Version 2.0 -Description: |Build Status| - - WORC v3.0.0 - =========== - - Workflow for Optimal Radiomics Classification - --------------------------------------------- - - WORC is an open-source python package for the easy execution of full - radiomics pipelines. - - We aim to establish a general radiomics platform supporting easy - integration of other tools. With our modular build and support of - different software languages (python, MATLAB, ruby, java etc.), we want - to facilitate and stimulate collaboration, standardisation and - comparison of different radiomics approaches. By combining this in a - single framework, we hope to find a universal radiomics strategy that - can address various problems. - - Disclaimer - ---------- - - This package is still under development. We try to thoroughly test and - evaluate every new build and function, but bugs can off course still - occur. Please contact us through the channels below if you find any and - we will try to fix them as soon as possible, or create an issue on this - Github. - - Tutorial and Documentation - -------------------------- - - The WORC tutorial is hosted in a `separate - repository `__. - - The official documentation can be found at https://worc.readthedocs.io. - - Installation - ------------ - - WORC currently only supports Unix with Python 3.6+ (tested on 3.7.2 and - 3.7.3) systems and has been tested on Ubuntu 16.04 and 18.04 and Windows - 10. - - The package can be installed through pip: - - :: - - pip install WORC - - Alternatively, you can directly install WORC from this repository: - - :: - - python setup.py install - - Make sure you install the requirements first: - - :: - - pip install -r requirements.txt - - Fastr Configuration - ~~~~~~~~~~~~~~~~~~~ - - The installation will create a FASTR configuration file in the - $HOME/.fastr/config.d folder called WORC\_config.py. This file is used - for configuring fastr, the pipeline execution toolbox we use. More - information can be found at `the FASTR - website `__. - In this file, so called mounts are defined, which are used to locate the - WORC tools and your inputs and outputs. Please inspect the mounts and - change them if neccesary. - - :: - - echo "machine images.xnat.org - > login admin - > password admin" > ~/.netrc - chmod 600 ~/.netrc - - 3rd-party packages used in WORC: - -------------------------------- - - - `FASTR (Workflow design and - building) `__ - - xnat (Collecting data from XNAT) - - SimpleITK (Image loading and preprocessing) - - `Pyradiomics `__ - - `PREDICT `__ - - See for other requirements the `requirements file `__. - - Start - ----- - - We suggest you start with the `WORC - Tutorial `__. Besides a - Jupyter notebook with instructions, we provide there also an example - script for you to get started with. Make sure you input your own data as - the sources. Also, check out the unit tests of several tools in the - WORC/resources/fastr\_tests directory. The example is explained in more - detail in the `documentation `__. - - WIP - --- - - - We are working on improving the documentation. - - We are working on organizing clinically relevant datasets for - examples and unit tests. - - We are writing the paper on WORC. - - License - ------- - - This package is covered by the open source `APACHE 2.0 - License `__. - - When using WORC, please cite this repository. - - Contact - ------- - - We are happy to help you with any questions. Please sent us a mail or - place an issue on the Github. - - We welcome contributions to WORC. For the moment, converting your - toolbox into a FASTR tool is satisfactory. - - Optional - -------- - - Besides the default installation, there are several optional packages - you could install to support WORC. - - Graphviz - ~~~~~~~~ - - WORC can draw the network and save it as a SVG image using - `graphviz `__. In order to do so, please make - sure you install graphviz. On Ubuntu, simply run - - :: - - apt install graphiv - - Elastix - ~~~~~~~ - - Image registration is included in WORC through `elastix and - transformix `__. In order to use elastix, - please download the binaries and place them in your - fastr.config.mounts['apps'] path. Check the elastix tool description for - the correct subdirectory structure. For example, on Linux, the binaries - and libraries should be in "../apps/elastix/4.8/install/" and - "../apps/elastix/4.8/install/lib" respectively. - - Note: optionally, you can tell WORC to copy the metadata from the image - file to the segmentation file before applying the deformation field. - This requires ITK and ITKTools: see `the ITKTools - github `__ for installation - instructions. - - XNAT - ~~~~ - - We use the XNATpy package to connect the toolbox to the XNAT online - database platforms. You will only need this when you want to download or - upload data from or to XNAT. We advise you to specify your account - settings in a .netrc file when using this feature, such that you do not - need to input them on every request: - - .. |Build Status| image:: https://travis-ci.com/MStarmans91/WORC.svg?token=qyvaeq7Cpwu7hJGB98Gp&branch=master - :target: https://travis-ci.com/MStarmans91/WORC - -Keywords: bioinformatics radiomics features -Platform: UNKNOWN -Classifier: Development Status :: 5 - Production/Stable -Classifier: Intended Audience :: Developers -Classifier: Intended Audience :: Science/Research -Classifier: Intended Audience :: Healthcare Industry -Classifier: Intended Audience :: Information Technology -Classifier: Intended Audience :: Education -Classifier: License :: OSI Approved :: Apache Software License -Classifier: Natural Language :: English -Classifier: Operating System :: OS Independent -Classifier: Programming Language :: Python :: 3.6 -Classifier: Programming Language :: Python :: 3.7 -Classifier: Programming Language :: Python :: 3 :: Only -Classifier: Topic :: Scientific/Engineering :: Information Analysis -Classifier: Topic :: System :: Distributed Computing -Classifier: Topic :: System :: Logging -Classifier: Topic :: Utilities -Requires-Python: >=3.6 diff --git a/WORC.egg-info/SOURCES.txt b/WORC.egg-info/SOURCES.txt deleted file mode 100644 index 939a5c10..00000000 --- a/WORC.egg-info/SOURCES.txt +++ /dev/null @@ -1,426 +0,0 @@ -APACHE-LICENSE-2.0 -CHANGELOG -LICENSE -MANIFEST.in -README.rst -requirements-setup.txt -requirements.txt -setup.cfg -setup.py -test_requirements.txt -version -WORC/WORC.py -WORC/__init__.py -WORC/addexceptions.py -WORC/index.rst -WORC.egg-info/PKG-INFO -WORC.egg-info/SOURCES.txt -WORC.egg-info/dependency_links.txt -WORC.egg-info/entry_points.txt -WORC.egg-info/requires.txt -WORC.egg-info/top_level.txt -WORC/IOparser/__init__.py -WORC/IOparser/config_WORC.py -WORC/IOparser/config_io_classifier.py -WORC/IOparser/config_preprocessing.py -WORC/IOparser/config_segmentix.py -WORC/IOparser/file_io.py -WORC/classification/AdvancedSampler.py -WORC/classification/RankedSVM.py -WORC/classification/SearchCV.py -WORC/classification/__init__.py -WORC/classification/construct_classifier.py -WORC/classification/crossval.py -WORC/classification/estimators.py -WORC/classification/fitandscore.py -WORC/classification/metrics.py -WORC/classification/parameter_optimization.py -WORC/classification/trainclassifier.py -WORC/doc/Makefile -WORC/doc/README -WORC/doc/__placeholder__ -WORC/doc/conf.py -WORC/doc/doc_clean.py -WORC/doc/doc_generate.py -WORC/doc/generate_config.py -WORC/doc/generate_modules.py -WORC/doc/index.rst -WORC/doc/index.template -WORC/doc/make.bat -WORC/doc/_build/doctrees/environment.pickle -WORC/doc/_build/doctrees/index.doctree -WORC/doc/_build/doctrees/autogen/WORC.IOparser.doctree -WORC/doc/_build/doctrees/autogen/WORC.classification.doctree -WORC/doc/_build/doctrees/autogen/WORC.doctree -WORC/doc/_build/doctrees/autogen/WORC.featureprocessing.doctree -WORC/doc/_build/doctrees/autogen/WORC.plotting.doctree -WORC/doc/_build/doctrees/autogen/WORC.processing.doctree -WORC/doc/_build/doctrees/autogen/WORC.resources.fastr_tests.doctree -WORC/doc/_build/doctrees/autogen/WORC.tools.doctree -WORC/doc/_build/doctrees/static/changelog.doctree -WORC/doc/_build/doctrees/static/configuration.doctree -WORC/doc/_build/doctrees/static/development.doctree -WORC/doc/_build/doctrees/static/file_description.doctree -WORC/doc/_build/doctrees/static/introduction.doctree -WORC/doc/_build/doctrees/static/quick_start.doctree -WORC/doc/_build/doctrees/static/reference.doctree -WORC/doc/_build/doctrees/static/tools.doctree -WORC/doc/_build/doctrees/static/user_manual.doctree -WORC/doc/_build/doctrees/user_reference/user_reference.doctree -WORC/doc/_build/html/.buildinfo -WORC/doc/_build/html/genindex.html -WORC/doc/_build/html/index.html -WORC/doc/_build/html/objects.inv -WORC/doc/_build/html/py-modindex.html -WORC/doc/_build/html/search.html -WORC/doc/_build/html/searchindex.js -WORC/doc/_build/html/_images/CASH.png -WORC/doc/_build/html/_images/RadiomicsSteps.png -WORC/doc/_build/html/_images/WORC_small.png -WORC/doc/_build/html/_images/datatype_diagram.svg -WORC/doc/_build/html/_images/flow_broadcast.svg -WORC/doc/_build/html/_images/flow_collapse.svg -WORC/doc/_build/html/_images/flow_cross_three_sample.svg -WORC/doc/_build/html/_images/flow_expand.svg -WORC/doc/_build/html/_images/flow_expand_collapse.svg -WORC/doc/_build/html/_images/flow_simple_one_sample.svg -WORC/doc/_build/html/_images/flow_simple_one_sample_two_cardinality.svg -WORC/doc/_build/html/_images/flow_simple_three_sample.svg -WORC/doc/_build/html/_images/flow_simple_three_sample_two_cardinality.svg -WORC/doc/_build/html/_images/network1.svg -WORC/doc/_build/html/_images/network2.svg -WORC/doc/_build/html/_images/network_multi_atlas.svg -WORC/doc/_build/html/_images/provo.svg -WORC/doc/_build/html/_images/tooldefresolveflowchart.png -WORC/doc/_build/html/_modules/index.html -WORC/doc/_build/html/_modules/WORC/WORC.html -WORC/doc/_build/html/_modules/WORC/WORCpy27.html -WORC/doc/_build/html/_modules/WORC/addexceptions.html -WORC/doc/_build/html/_modules/WORC/IOparser/config_WORC.html -WORC/doc/_build/html/_modules/WORC/IOparser/config_io_classifier.html -WORC/doc/_build/html/_modules/WORC/IOparser/config_preprocessing.html -WORC/doc/_build/html/_modules/WORC/IOparser/config_segmentix.html -WORC/doc/_build/html/_modules/WORC/IOparser/file_io.html -WORC/doc/_build/html/_modules/WORC/classification/AdvancedSampler.html -WORC/doc/_build/html/_modules/WORC/classification/RankedSVM.html -WORC/doc/_build/html/_modules/WORC/classification/SearchCV.html -WORC/doc/_build/html/_modules/WORC/classification/construct_classifier.html -WORC/doc/_build/html/_modules/WORC/classification/crossval.html -WORC/doc/_build/html/_modules/WORC/classification/estimators.html -WORC/doc/_build/html/_modules/WORC/classification/fitandscore.html -WORC/doc/_build/html/_modules/WORC/classification/metrics.html -WORC/doc/_build/html/_modules/WORC/classification/parameter_optimization.html -WORC/doc/_build/html/_modules/WORC/classification/trainclassifier.html -WORC/doc/_build/html/_modules/WORC/featureprocessing/Imputer.html -WORC/doc/_build/html/_modules/WORC/featureprocessing/Relief.html -WORC/doc/_build/html/_modules/WORC/featureprocessing/SelectGroups.html -WORC/doc/_build/html/_modules/WORC/featureprocessing/SelectIndividuals.html -WORC/doc/_build/html/_modules/WORC/featureprocessing/StatisticalTestThreshold.html -WORC/doc/_build/html/_modules/WORC/featureprocessing/VarianceThreshold.html -WORC/doc/_build/html/_modules/WORC/plotting/compute_CI.html -WORC/doc/_build/html/_modules/WORC/plotting/linstretch.html -WORC/doc/_build/html/_modules/WORC/plotting/plot_ROC.html -WORC/doc/_build/html/_modules/WORC/plotting/plot_SVM.html -WORC/doc/_build/html/_modules/WORC/plotting/plot_SVR.html -WORC/doc/_build/html/_modules/WORC/plotting/plot_barchart.html -WORC/doc/_build/html/_modules/WORC/plotting/plot_boxplot.html -WORC/doc/_build/html/_modules/WORC/plotting/plot_images.html -WORC/doc/_build/html/_modules/WORC/plotting/plot_ranked_scores.html -WORC/doc/_build/html/_modules/WORC/processing/ExtractNLargestBlobsn.html -WORC/doc/_build/html/_modules/WORC/processing/classes.html -WORC/doc/_build/html/_modules/WORC/processing/label_processing.html -WORC/doc/_build/html/_modules/WORC/resources/fastr_tests/CalcFeatures_test.html -WORC/doc/_build/html/_modules/WORC/resources/fastr_tests/elastix_test.html -WORC/doc/_build/html/_modules/WORC/resources/fastr_tests/segmentix_test.html -WORC/doc/_build/html/_modules/WORC/tools/Elastix.html -WORC/doc/_build/html/_modules/WORC/tools/Evaluate.html -WORC/doc/_build/html/_modules/WORC/tools/Slicer.html -WORC/doc/_build/html/_modules/WORC/tools/Transformix.html -WORC/doc/_build/html/_modules/fastr/api.html -WORC/doc/_build/html/_sources/index.rst.txt -WORC/doc/_build/html/_sources/autogen/WORC.IOparser.rst.txt -WORC/doc/_build/html/_sources/autogen/WORC.classification.rst.txt -WORC/doc/_build/html/_sources/autogen/WORC.featureprocessing.rst.txt -WORC/doc/_build/html/_sources/autogen/WORC.plotting.rst.txt -WORC/doc/_build/html/_sources/autogen/WORC.processing.rst.txt -WORC/doc/_build/html/_sources/autogen/WORC.resources.fastr_tests.rst.txt -WORC/doc/_build/html/_sources/autogen/WORC.rst.txt -WORC/doc/_build/html/_sources/autogen/WORC.tools.rst.txt -WORC/doc/_build/html/_sources/static/changelog.rst.txt -WORC/doc/_build/html/_sources/static/configuration.rst.txt -WORC/doc/_build/html/_sources/static/development.rst.txt -WORC/doc/_build/html/_sources/static/file_description.rst.txt -WORC/doc/_build/html/_sources/static/introduction.rst.txt -WORC/doc/_build/html/_sources/static/quick_start.rst.txt -WORC/doc/_build/html/_sources/static/reference.rst.txt -WORC/doc/_build/html/_sources/static/tools.rst.txt -WORC/doc/_build/html/_sources/static/user_manual.rst.txt -WORC/doc/_build/html/_sources/user_reference/user_reference.rst.txt -WORC/doc/_build/html/_static/basic.css -WORC/doc/_build/html/_static/doctools.js -WORC/doc/_build/html/_static/documentation_options.js -WORC/doc/_build/html/_static/file.png -WORC/doc/_build/html/_static/graphviz.css -WORC/doc/_build/html/_static/jquery-3.2.1.js -WORC/doc/_build/html/_static/jquery.js -WORC/doc/_build/html/_static/language_data.js -WORC/doc/_build/html/_static/minus.png -WORC/doc/_build/html/_static/plus.png -WORC/doc/_build/html/_static/pygments.css -WORC/doc/_build/html/_static/searchtools.js -WORC/doc/_build/html/_static/underscore-1.3.1.js -WORC/doc/_build/html/_static/underscore.js -WORC/doc/_build/html/_static/css/badge_only.css -WORC/doc/_build/html/_static/css/theme.css -WORC/doc/_build/html/_static/fonts/Inconsolata-Bold.ttf -WORC/doc/_build/html/_static/fonts/Inconsolata-Regular.ttf -WORC/doc/_build/html/_static/fonts/Inconsolata.ttf -WORC/doc/_build/html/_static/fonts/Lato-Bold.ttf -WORC/doc/_build/html/_static/fonts/Lato-Regular.ttf -WORC/doc/_build/html/_static/fonts/RobotoSlab-Bold.ttf -WORC/doc/_build/html/_static/fonts/RobotoSlab-Regular.ttf -WORC/doc/_build/html/_static/fonts/fontawesome-webfont.eot -WORC/doc/_build/html/_static/fonts/fontawesome-webfont.svg -WORC/doc/_build/html/_static/fonts/fontawesome-webfont.ttf -WORC/doc/_build/html/_static/fonts/fontawesome-webfont.woff -WORC/doc/_build/html/_static/fonts/fontawesome-webfont.woff2 -WORC/doc/_build/html/_static/fonts/Lato/lato-bold.eot -WORC/doc/_build/html/_static/fonts/Lato/lato-bold.ttf -WORC/doc/_build/html/_static/fonts/Lato/lato-bold.woff -WORC/doc/_build/html/_static/fonts/Lato/lato-bold.woff2 -WORC/doc/_build/html/_static/fonts/Lato/lato-bolditalic.eot -WORC/doc/_build/html/_static/fonts/Lato/lato-bolditalic.ttf -WORC/doc/_build/html/_static/fonts/Lato/lato-bolditalic.woff -WORC/doc/_build/html/_static/fonts/Lato/lato-bolditalic.woff2 -WORC/doc/_build/html/_static/fonts/Lato/lato-italic.eot -WORC/doc/_build/html/_static/fonts/Lato/lato-italic.ttf -WORC/doc/_build/html/_static/fonts/Lato/lato-italic.woff -WORC/doc/_build/html/_static/fonts/Lato/lato-italic.woff2 -WORC/doc/_build/html/_static/fonts/Lato/lato-regular.eot -WORC/doc/_build/html/_static/fonts/Lato/lato-regular.ttf -WORC/doc/_build/html/_static/fonts/Lato/lato-regular.woff -WORC/doc/_build/html/_static/fonts/Lato/lato-regular.woff2 -WORC/doc/_build/html/_static/fonts/RobotoSlab/roboto-slab-v7-bold.eot -WORC/doc/_build/html/_static/fonts/RobotoSlab/roboto-slab-v7-bold.ttf -WORC/doc/_build/html/_static/fonts/RobotoSlab/roboto-slab-v7-bold.woff -WORC/doc/_build/html/_static/fonts/RobotoSlab/roboto-slab-v7-bold.woff2 -WORC/doc/_build/html/_static/fonts/RobotoSlab/roboto-slab-v7-regular.eot -WORC/doc/_build/html/_static/fonts/RobotoSlab/roboto-slab-v7-regular.ttf -WORC/doc/_build/html/_static/fonts/RobotoSlab/roboto-slab-v7-regular.woff -WORC/doc/_build/html/_static/fonts/RobotoSlab/roboto-slab-v7-regular.woff2 -WORC/doc/_build/html/_static/js/modernizr.min.js -WORC/doc/_build/html/_static/js/theme.js -WORC/doc/_build/html/autogen/WORC.IOparser.html -WORC/doc/_build/html/autogen/WORC.classification.html -WORC/doc/_build/html/autogen/WORC.featureprocessing.html -WORC/doc/_build/html/autogen/WORC.html -WORC/doc/_build/html/autogen/WORC.plotting.html -WORC/doc/_build/html/autogen/WORC.processing.html -WORC/doc/_build/html/autogen/WORC.resources.fastr_tests.html -WORC/doc/_build/html/autogen/WORC.tools.html -WORC/doc/_build/html/static/changelog.html -WORC/doc/_build/html/static/configuration.html -WORC/doc/_build/html/static/development.html -WORC/doc/_build/html/static/file_description.html -WORC/doc/_build/html/static/introduction.html -WORC/doc/_build/html/static/quick_start.html -WORC/doc/_build/html/static/reference.html -WORC/doc/_build/html/static/tools.html -WORC/doc/_build/html/static/user_manual.html -WORC/doc/_build/html/user_reference/user_reference.html -WORC/doc/autogen/WORC.IOparser.rst -WORC/doc/autogen/WORC.classification.rst -WORC/doc/autogen/WORC.featureprocessing.rst -WORC/doc/autogen/WORC.plotting.rst -WORC/doc/autogen/WORC.processing.rst -WORC/doc/autogen/WORC.resources.fastr_tests.rst -WORC/doc/autogen/WORC.rst -WORC/doc/autogen/WORC.tools.rst -WORC/doc/autogen/__placeholder__ -WORC/doc/static/changelog.rst -WORC/doc/static/configuration.rst -WORC/doc/static/file_description.rst -WORC/doc/static/introduction.rst -WORC/doc/static/quick_start.rst -WORC/doc/static/user_manual.rst -WORC/doc/static/images/CASH.pdf -WORC/doc/static/images/CASH.png -WORC/doc/static/images/RadiomicsSteps.pdf -WORC/doc/static/images/RadiomicsSteps.png -WORC/doc/static/images/WORC_small.png -WORC/doc/static/images/datatype_diagram.pdf -WORC/doc/static/images/datatype_diagram.svg -WORC/doc/static/images/fastr_core.png -WORC/doc/static/images/network1.pdf -WORC/doc/static/images/network1.svg -WORC/doc/static/images/network2.pdf -WORC/doc/static/images/network2.svg -WORC/doc/static/images/network_multi_atlas.pdf -WORC/doc/static/images/network_multi_atlas.svg -WORC/doc/static/images/provo.svg -WORC/doc/static/images/flow/flow_broadcast.pdf -WORC/doc/static/images/flow/flow_broadcast.svg -WORC/doc/static/images/flow/flow_collapse.pdf -WORC/doc/static/images/flow/flow_collapse.svg -WORC/doc/static/images/flow/flow_cross_three_sample.pdf -WORC/doc/static/images/flow/flow_cross_three_sample.svg -WORC/doc/static/images/flow/flow_cross_three_sample_two_cardinality.pdf -WORC/doc/static/images/flow/flow_cross_three_sample_two_cardinality.svg -WORC/doc/static/images/flow/flow_expand.pdf -WORC/doc/static/images/flow/flow_expand.svg -WORC/doc/static/images/flow/flow_expand_collapse.pdf -WORC/doc/static/images/flow/flow_expand_collapse.svg -WORC/doc/static/images/flow/flow_simple_one_sample.pdf -WORC/doc/static/images/flow/flow_simple_one_sample.svg -WORC/doc/static/images/flow/flow_simple_one_sample_two_cardinality.pdf -WORC/doc/static/images/flow/flow_simple_one_sample_two_cardinality.svg -WORC/doc/static/images/flow/flow_simple_three_sample.pdf -WORC/doc/static/images/flow/flow_simple_three_sample.svg -WORC/doc/static/images/flow/flow_simple_three_sample_two_cardinality.pdf -WORC/doc/static/images/flow/flow_simple_three_sample_two_cardinality.svg -WORC/doc/static/images/sources/fastr_daemon_structure.xmind -WORC/doc/static/images/sources/fastr_server_strucure.xmind -WORC/doc/static/images/tools/tooldefresolveflowchart.png -WORC/exampledata/dummies/dummy.nii.gz -WORC/exampledata/elastix/parAslice.txt -WORC/exampledata/elastix/parBslice.txt -WORC/exampledata/elastix/img0/slice047.mhd -WORC/exampledata/elastix/img0/slice047.raw -WORC/exampledata/elastix/img1/slice086.mhd -WORC/exampledata/elastix/img1/slice086.raw -WORC/exampledata/elastix/img1/slice091.mhd -WORC/exampledata/elastix/img1/slice091.raw -WORC/fastrconfig/WORC_config.py -WORC/featureprocessing/Imputer.py -WORC/featureprocessing/Relief.py -WORC/featureprocessing/SelectGroups.py -WORC/featureprocessing/SelectIndividuals.py -WORC/featureprocessing/StatisticalTestFeatures.py -WORC/featureprocessing/StatisticalTestThreshold.py -WORC/featureprocessing/VarianceThreshold.py -WORC/featureprocessing/__init__.py -WORC/plotting/__init__.py -WORC/plotting/compute_CI.py -WORC/plotting/linstretch.py -WORC/plotting/plot_ROC.py -WORC/plotting/plot_SVM.py -WORC/plotting/plot_SVR.py -WORC/plotting/plot_barchart.py -WORC/plotting/plot_boxplot.py -WORC/plotting/plot_images.py -WORC/plotting/plot_ranked_scores.py -WORC/plotting/plotminmaxresponse.py -WORC/plotting/scatterplot.py -WORC/processing/ExtractNLargestBlobsn.py -WORC/processing/RTStructReader.py -WORC/processing/__init__.py -WORC/processing/classes.py -WORC/processing/label_processing.py -WORC/resources/fastr_tests/CalcFeatures_test.py -WORC/resources/fastr_tests/__init__.py -WORC/resources/fastr_tests/elastix_test.py -WORC/resources/fastr_tests/segmentix_test.py -WORC/resources/fastr_tools/elastix4.8/elastix.xml -WORC/resources/fastr_tools/elastix4.8/transformix.xml -WORC/resources/fastr_tools/elastix4.8/testdata/input/parAslice.txt -WORC/resources/fastr_tools/elastix4.8/testdata/input/parBslice.txt -WORC/resources/fastr_tools/elastix4.8/testdata/input/slice047.mhd -WORC/resources/fastr_tools/elastix4.8/testdata/input/slice047.raw -WORC/resources/fastr_tools/elastix4.8/testdata/input/slice091.mhd -WORC/resources/fastr_tools/elastix4.8/testdata/input/slice091.raw -WORC/resources/fastr_tools/elastix4.8/testdata/output/TransformParameters.0.txt -WORC/resources/fastr_tools/elastix4.8/testdata/output/TransformParameters.1.txt -WORC/resources/fastr_tools/elastixtools/createdeftransform.xml -WORC/resources/fastr_tools/elastixtools/createmeantransform.xml -WORC/resources/fastr_tools/elastixtools/elastixparameterfile.xml -WORC/resources/fastr_tools/elastixtools/elastixtransformfile.xml -WORC/resources/fastr_tools/elastixtools/transformixpoint2json.xml -WORC/resources/fastr_tools/elastixtools/bin/create_def_transform.py -WORC/resources/fastr_tools/elastixtools/bin/create_mean_transform.py -WORC/resources/fastr_tools/elastixtools/bin/elastixparameterfile.py -WORC/resources/fastr_tools/elastixtools/bin/transformixpoint2json.py -WORC/resources/fastr_tools/itktools/0.3.0/pxbinaryimageoperator.xml -WORC/resources/fastr_tools/itktools/0.3.0/pxcastconvert.xml -WORC/resources/fastr_tools/itktools/0.3.0/pxcastconvertdicom.xml -WORC/resources/fastr_tools/itktools/0.3.0/pxcombinesegmentations.xml -WORC/resources/fastr_tools/itktools/0.3.0/pxcomputeboundingbox.xml -WORC/resources/fastr_tools/itktools/0.3.0/pxgaussianimagefilter.xml -WORC/resources/fastr_tools/itktools/0.3.0/pxgetimageinformation.xml -WORC/resources/fastr_tools/itktools/0.3.0/pxintensityreplace.xml -WORC/resources/fastr_tools/itktools/0.3.0/pxmeanstdimage.xml -WORC/resources/fastr_tools/itktools/0.3.0/pxmorphology.xml -WORC/resources/fastr_tools/itktools/0.3.0/pxthresholdimage.xml -WORC/resources/fastr_tools/itktools/0.3.0/pxunaryimageoperator.xml -WORC/resources/fastr_tools/itktools/0.3.2/copymetadata.xml -WORC/resources/fastr_tools/itktools/0.3.2/pxcastconvert.xml -WORC/resources/fastr_tools/itktools/0.3.2/pxcastconvertdicom.xml -WORC/resources/fastr_tools/itktools/0.3.2/pxgaussianimagefilter.xml -WORC/resources/fastr_tools/itktools/0.3.2/bin/copymetadata.py -WORC/resources/fastr_tools/predict/CalcFeatures.xml -WORC/resources/fastr_tools/predict/bin/CalcFeatures_tool.py -WORC/resources/fastr_tools/pyradiomics/CF_pyradiomics.xml -WORC/resources/fastr_tools/pyradiomics/bin/CF_pyradiomics.py -WORC/resources/fastr_tools/pyradiomics/bin/CF_pyradiomics_tool.py -WORC/resources/fastr_tools/segmentix/Segmentix.xml -WORC/resources/fastr_tools/segmentix/bin/segmentix.py -WORC/resources/fastr_tools/segmentix/bin/segmentix_tool.py -WORC/resources/fastr_tools/worc/PlotBarchart.xml -WORC/resources/fastr_tools/worc/PlotROC.xml -WORC/resources/fastr_tools/worc/PlotRankedScores.xml -WORC/resources/fastr_tools/worc/PlotSVM.xml -WORC/resources/fastr_tools/worc/PreProcess.xml -WORC/resources/fastr_tools/worc/RTStructReader.xml -WORC/resources/fastr_tools/worc/Slicer.xml -WORC/resources/fastr_tools/worc/StatisticalTestFeatures.xml -WORC/resources/fastr_tools/worc/TrainClassifier.xml -WORC/resources/fastr_tools/worc/combineresults.xml -WORC/resources/fastr_tools/worc/fitandscore.xml -WORC/resources/fastr_tools/worc/worccastconvert.xml -WORC/resources/fastr_tools/worc/bin/PlotBarchart.py -WORC/resources/fastr_tools/worc/bin/PlotROC.py -WORC/resources/fastr_tools/worc/bin/PlotRankedScores.py -WORC/resources/fastr_tools/worc/bin/PlotSVM.py -WORC/resources/fastr_tools/worc/bin/RTStructReader_Tool.py -WORC/resources/fastr_tools/worc/bin/StatisticalTestFeatures_tool.py -WORC/resources/fastr_tools/worc/bin/TrainClassifier.py -WORC/resources/fastr_tools/worc/bin/combineresults.py -WORC/resources/fastr_tools/worc/bin/fitandscore_tool.py -WORC/resources/fastr_tools/worc/bin/preprocessing.py -WORC/resources/fastr_tools/worc/bin/slicer.py -WORC/resources/fastr_tools/worc/bin/worccastconvert.py -WORC/resources/fastr_types/BValueFile.py -WORC/resources/fastr_types/BVectorFile.py -WORC/resources/fastr_types/CSVFile.py -WORC/resources/fastr_types/ConfigFile.py -WORC/resources/fastr_types/DataFile.py -WORC/resources/fastr_types/DicomImageDirectory.py -WORC/resources/fastr_types/DicomImageFile.py -WORC/resources/fastr_types/DummyFile.py -WORC/resources/fastr_types/ElastixInput.py -WORC/resources/fastr_types/ElastixLogFile.py -WORC/resources/fastr_types/ElastixParameterFile.py -WORC/resources/fastr_types/ElastixTransformFile.py -WORC/resources/fastr_types/HDF5.py -WORC/resources/fastr_types/MIGRASParameterFile.py -WORC/resources/fastr_types/MatlabFile.py -WORC/resources/fastr_types/MetaData.py -WORC/resources/fastr_types/PNGFile.py -WORC/resources/fastr_types/PREDICTParameterFile.py -WORC/resources/fastr_types/ParameterFile.py -WORC/resources/fastr_types/PatientInfoFile.py -WORC/resources/fastr_types/RDF.py -WORC/resources/fastr_types/RTStructFile.py -WORC/resources/fastr_types/Shelve.py -WORC/resources/fastr_types/TexFile.py -WORC/resources/fastr_types/TextFile.py -WORC/resources/fastr_types/TransformixLogFile.py -WORC/resources/fastr_types/TransformixOutputPointFile.py -WORC/resources/fastr_types/TransformixParam.py -WORC/resources/fastr_types/TransformixPointFile.py -WORC/resources/fastr_types/XlsxFile.py -WORC/resources/fastr_types/ZipFile.py -WORC/tools/Elastix.py -WORC/tools/Evaluate.py -WORC/tools/Slicer.py -WORC/tools/Transformix.py -WORC/tools/__init__.py \ No newline at end of file diff --git a/WORC.egg-info/dependency_links.txt b/WORC.egg-info/dependency_links.txt deleted file mode 100644 index 8b137891..00000000 --- a/WORC.egg-info/dependency_links.txt +++ /dev/null @@ -1 +0,0 @@ - diff --git a/WORC.egg-info/entry_points.txt b/WORC.egg-info/entry_points.txt deleted file mode 100644 index 7f4961e2..00000000 --- a/WORC.egg-info/entry_points.txt +++ /dev/null @@ -1,3 +0,0 @@ -[console_scripts] -WORC = WORC.WORC:main - diff --git a/WORC.egg-info/requires.txt b/WORC.egg-info/requires.txt deleted file mode 100644 index 51cf6dec..00000000 --- a/WORC.egg-info/requires.txt +++ /dev/null @@ -1,26 +0,0 @@ -fastr>=3.1.1 -xnat>=0.2.2 -configparser>=3.5.0 -natsort>=5.0.1 -drmaa>=0.7.6 -nose>=1.3.7 -nose-parameterized>=0.5.0 -numpy>=1.16.3 -tqdm>=4.7.1 -six>=1.10.0 -sphinx>=1.4 -pyOpenSSL>=16.2.0 -boto3>=1.7.74 -pandas>=0.24.2 -xlrd>=1.2.0 -tables>=3.5.1 -pydicom>=1.2.2 -ghalton>=0.6.1 -imbalanced-learn>=0.4.3 -scikit-learn>=0.20.3 -scipy>=1.2.1 -SimpleITK>=1.2.0 -missingpy>=0.2.0 -matplotlib2tikz>=0.7.4 -lifelines>=0.21.1 -PREDICT>=3.0.0 diff --git a/WORC.egg-info/top_level.txt b/WORC.egg-info/top_level.txt deleted file mode 100644 index 561ce3c9..00000000 --- a/WORC.egg-info/top_level.txt +++ /dev/null @@ -1 +0,0 @@ -WORC diff --git a/WORC/IOparser/__init__.pyc b/WORC/IOparser/__init__.pyc deleted file mode 100644 index 0796feb9..00000000 Binary files a/WORC/IOparser/__init__.pyc and /dev/null differ diff --git a/WORC/IOparser/config_WORC.pyc b/WORC/IOparser/config_WORC.pyc deleted file mode 100644 index 4ad6a215..00000000 Binary files a/WORC/IOparser/config_WORC.pyc and /dev/null differ diff --git a/WORC/IOparser/config_general.pyc b/WORC/IOparser/config_general.pyc deleted file mode 100644 index 4db6c25e..00000000 Binary files a/WORC/IOparser/config_general.pyc and /dev/null differ diff --git a/WORC/IOparser/config_io_classifier.py b/WORC/IOparser/config_io_classifier.py index 60f811ce..c2043af7 100644 --- a/WORC/IOparser/config_io_classifier.py +++ b/WORC/IOparser/config_io_classifier.py @@ -32,14 +32,13 @@ def load_config(config_file_path): settings = configparser.ConfigParser() settings.read(config_file_path) - print(settings.keys()) settings_dict = {'General': dict(), 'CrossValidation': dict(), 'Labels': dict(), 'HyperOptimization': dict(), 'Classification': dict(), 'SelectFeatGroup': dict(), 'Featsel': dict(), 'FeatureScaling': dict(), 'SampleProcessing': dict(), 'Imputation': dict(), - 'Ensemble': dict()} + 'Ensemble': dict(), 'Bootstrap': dict()} settings_dict['General']['cross_validation'] =\ settings['General'].getboolean('cross_validation') @@ -241,14 +240,21 @@ def load_config(config_file_path): settings['HyperOptimization'].getfloat('test_size') settings_dict['HyperOptimization']['N_iter'] =\ settings['HyperOptimization'].getint('N_iterations') + settings_dict['HyperOptimization']['n_splits'] =\ + settings['HyperOptimization'].getint('n_splits') settings_dict['HyperOptimization']['n_jobspercore'] =\ int(settings['HyperOptimization']['n_jobspercore']) + settings_dict['HyperOptimization']['maxlen'] = \ + settings['HyperOptimization'].getint('maxlen') + settings_dict['HyperOptimization']['ranking_score'] = \ + str(settings['HyperOptimization']['ranking_score']) settings_dict['FeatureScaling']['scale_features'] =\ settings['FeatureScaling'].getboolean('scale_features') settings_dict['FeatureScaling']['scaling_method'] =\ str(settings['FeatureScaling']['scaling_method']) + # Settings for sample processing, i.e. oversampling, undersampling etc settings_dict['SampleProcessing']['SMOTE'] =\ [str(item).strip() for item in settings['SampleProcessing']['SMOTE'].split(',')] @@ -265,7 +271,15 @@ def load_config(config_file_path): [str(item).strip() for item in settings['SampleProcessing']['Oversampling'].split(',')] + # Settings for ensembling settings_dict['Ensemble']['Use'] =\ settings['Ensemble'].getboolean('Use') + # Settings for bootstrapping + settings_dict['Bootstrap']['Use'] =\ + settings['Bootstrap'].getboolean('Use') + + settings_dict['Bootstrap']['N_iterations'] =\ + settings['Bootstrap'].getint('N_iterations') + return settings_dict diff --git a/WORC/IOparser/config_segmentix.pyc b/WORC/IOparser/config_segmentix.pyc deleted file mode 100644 index e9487ec1..00000000 Binary files a/WORC/IOparser/config_segmentix.pyc and /dev/null differ diff --git a/WORC/IOparser/file_io.py b/WORC/IOparser/file_io.py index 8a369abc..d1b2eac5 100644 --- a/WORC/IOparser/file_io.py +++ b/WORC/IOparser/file_io.py @@ -95,7 +95,7 @@ def load_data(featurefiles, patientinfo=None, label_names=None, modnames=[]): pfiles, image_features) except ValueError as e: - message = e.message + '. Please take a look at your labels' +\ + message = str(e) + '. Please take a look at your labels' +\ ' file and make sure it is formatted correctly. ' +\ 'See also https://github.com/MStarmans91/WORC/wiki/The-WORC-configuration#genetics.' raise WORCexceptions.WORCValueError(message) diff --git a/WORC/WORC.py b/WORC/WORC.py index 0956bb2d..b9204775 100644 --- a/WORC/WORC.py +++ b/WORC/WORC.py @@ -20,10 +20,12 @@ from fastr.api import ResourceLimit import os from random import randint +import graphviz import WORC.addexceptions as WORCexceptions import WORC.IOparser.config_WORC as config_io from WORC.tools.Elastix import Elastix from WORC.tools.Evaluate import Evaluate +from WORC.tools.Slicer import Slicer class WORC(object): @@ -100,7 +102,7 @@ class WORC(object): """ - def __init__(self, name='WORC'): + def __init__(self, name='test'): """Initialize WORC object. Set the initial variables all to None, except for some defaults. @@ -108,7 +110,7 @@ def __init__(self, name='WORC'): name: name of the nework (string, optional) """ - self.name = name + self.name = 'WORC_' + name # Initialize several objects self.configs = list() @@ -119,6 +121,7 @@ def __init__(self, name='WORC'): self.semantics_train = list() self.labels_train = list() self.masks_train = list() + self.masks_normalize_train = list() self.features_train = list() self.metadata_train = list() @@ -127,20 +130,23 @@ def __init__(self, name='WORC'): self.semantics_test = list() self.labels_test = list() self.masks_test = list() + self.masks_normalize_test = list() self.features_test = list() self.metadata_test = list() self.Elastix_Para = list() + self.label_names = 'Label1, Label2' # Set some defaults, name - self.fastr_plugin = 'ProcessPoolExecution' + self.fastr_plugin = 'LinearExecution' if name == '': name = [randint(0, 9) for p in range(0, 5)] - self.fastr_tmpdir = os.path.join(fastr.config.mounts['tmp'], 'WORC_' + str(name)) + self.fastr_tmpdir = os.path.join(fastr.config.mounts['tmp'], self.name) self.additions = dict() self.CopyMetadata = True self.segmode = [] + self._add_evaluation = False def defaultconfig(self): """Generate a configparser object holding all default configuration values. @@ -231,14 +237,14 @@ def defaultconfig(self): # Feature selection config['Featsel'] = dict() - config['Featsel']['Variance'] = 'True, False' + config['Featsel']['Variance'] = 'True' config['Featsel']['GroupwiseSearch'] = 'True' config['Featsel']['SelectFromModel'] = 'False' config['Featsel']['UsePCA'] = 'False' config['Featsel']['PCAType'] = '95variance' config['Featsel']['StatisticalTestUse'] = 'False' config['Featsel']['StatisticalTestMetric'] = 'ttest, Welch, Wilcoxon, MannWhitneyU' - config['Featsel']['StatisticalTestThreshold'] = '0.02, 0.2' + config['Featsel']['StatisticalTestThreshold'] = '-2, 1.5' config['Featsel']['ReliefUse'] = 'False' config['Featsel']['ReliefNN'] = '2, 4' config['Featsel']['ReliefSampleSize'] = '1, 1' @@ -250,7 +256,7 @@ def defaultconfig(self): config['SelectFeatGroup']['shape_features'] = 'True, False' config['SelectFeatGroup']['histogram_features'] = 'True, False' config['SelectFeatGroup']['orientation_features'] = 'True, False' - config['SelectFeatGroup']['texture_Gabor_features'] = 'True, False' + config['SelectFeatGroup']['texture_Gabor_features'] = 'False' config['SelectFeatGroup']['texture_GLCM_features'] = 'True, False' config['SelectFeatGroup']['texture_GLCMMS_features'] = 'True, False' config['SelectFeatGroup']['texture_GLRLM_features'] = 'True, False' @@ -313,8 +319,11 @@ def defaultconfig(self): config['HyperOptimization'] = dict() config['HyperOptimization']['scoring_method'] = 'f1_weighted' config['HyperOptimization']['test_size'] = '0.15' + config['HyperOptimization']['n_splits'] = '5' config['HyperOptimization']['N_iterations'] = '10000' config['HyperOptimization']['n_jobspercore'] = '2000' # only relevant when using fastr in classification + config['HyperOptimization']['maxlen'] = '100' + config['HyperOptimization']['ranking_score'] = 'test_score' # Feature scaling options config['FeatureScaling'] = dict() @@ -330,7 +339,12 @@ def defaultconfig(self): # Ensemble options config['Ensemble'] = dict() - config['Ensemble']['Use'] = 'False' # Still WIP + config['Ensemble']['Use'] = '1' + + # Bootstrap options + config['Bootstrap'] = dict() + config['Bootstrap']['Use'] = 'False' + config['Bootstrap']['N_iterations'] = '1000' return config @@ -368,7 +382,7 @@ def build_training(self): self.configs = [self.defaultconfig()] * len(self.images_train) else: self.configs = [self.defaultconfig()] * len(self.features_train) - self.network = fastr.create_network('WORC_' + self.name) + self.network = fastr.create_network(self.name) # BUG: We currently use the first configuration as general config image_types = list() @@ -408,6 +422,12 @@ def build_training(self): self.sink_classification.input = self.classify.outputs['classification'] self.sink_performance.input = self.classify.outputs['performance'] + if self.masks_normalize_train: + self.sources_masks_normalize_train = dict() + + if self.masks_normalize_test: + self.sources_masks_normalize_test = dict() + if not self.features_train: # Create nodes to compute features self.sources_parameters = dict() @@ -574,12 +594,24 @@ def build_training(self): if self.metadata_test and len(self.metadata_test) >= nmod + 1: self.preprocessing_test[label].inputs['metadata'] = self.sources_metadata_test[label].output + # If there are masks to use in normalization, add them here + if self.masks_normalize_train: + self.sources_masks_normalize_train[label] = self.network.create_source('ITKImageFile', id='masks_normalize_train_' + label, node_group='train') + self.preprocessing_train[label].inputs['mask'] = self.sources_masks_normalize_train[label].output + + if self.masks_normalize_test: + self.sources_masks_normalize_test[label] = self.network.create_source('ITKImageFile', id='masks_normalize_test_' + label, node_group='test') + self.preprocessing_test[label].inputs['mask'] = self.sources_masks_normalize_test[label].output + # ----------------------------------------------------- # Create a feature calculator node calcfeat_node = str(self.configs[nmod]['General']['FeatureCalculator']) - self.calcfeatures_train[label] = self.network.create_node(calcfeat_node, tool_version='1.0', id='calcfeatures_train_' + label, resources=ResourceLimit(memory='14G')) + node_ID = '_'.join([self.configs[nmod]['General']['FeatureCalculator'].replace(':', '_').replace('.', '_').replace('/', '_'), + label]) + + self.calcfeatures_train[label] = self.network.create_node(calcfeat_node, tool_version='1.0', id='calcfeatures_train_' + node_ID, resources=ResourceLimit(memory='14G')) if self.images_test or self.features_test: - self.calcfeatures_test[label] = self.network.create_node(calcfeat_node, tool_version='1.0', id='calcfeatures_test_' + label, resources=ResourceLimit(memory='14G')) + self.calcfeatures_test[label] = self.network.create_node(calcfeat_node, tool_version='1.0', id='calcfeatures_test_' + node_ID, resources=ResourceLimit(memory='14G')) # Create required links self.calcfeatures_train[label].inputs['parameters'] = self.sources_parameters[label].output @@ -592,8 +624,8 @@ def build_training(self): if self.metadata_train and len(self.metadata_train) >= nmod + 1: self.calcfeatures_train[label].inputs['metadata'] = self.sources_metadata_train[label].output - if self.metadata_train and len(self.metadata_test) >= nmod + 1: - self.calcfeatures_train[label].inputs['metadata'] = self.sources_metadata_train[label].output + if self.metadata_test and len(self.metadata_test) >= nmod + 1: + self.calcfeatures_test[label].inputs['metadata'] = self.sources_metadata_test[label].output if self.semantics_train and len(self.semantics_train) >= nmod + 1: self.sources_semantics_train[label] = self.network.create_source('CSVFile', id='semantics_train_' + label) @@ -874,12 +906,12 @@ def set(self): config = configparser.ConfigParser() config.read(c) c = config - cfile = os.path.join(fastr.config.mounts['tmp'], 'WORC_' + self.name, ("config_{}_{}.ini").format(self.name, num)) + cfile = os.path.join(self.fastr_tmpdir, f"config_{self.name}_{num}.ini") if not os.path.exists(os.path.dirname(cfile)): os.makedirs(os.path.dirname(cfile)) with open(cfile, 'w') as configfile: c.write(configfile) - self.fastrconfigs.append(("vfs://tmp/{}/config_{}_{}.ini").format('WORC_' + self.name, self.name, num)) + self.fastrconfigs.append(cfile) # Generate gridsearch parameter files if required # TODO: We now use the first configuration for the classifier, but his needs to be separated from the rest per modality @@ -889,7 +921,7 @@ def set(self): self.source_data['patientclass_train'] = self.labels_train self.source_data['patientclass_test'] = self.labels_test - self.sink_data['classification'] = ("vfs://output/{}/svm_{{sample_id}}_{{cardinality}}{{ext}}").format(self.name) + self.sink_data['classification'] = ("vfs://output/{}/estimator_{{sample_id}}_{{cardinality}}{{ext}}").format(self.name) self.sink_data['performance'] = ("vfs://output/{}/performance_{{sample_id}}_{{cardinality}}{{ext}}").format(self.name) self.sink_data['config_classification_sink'] = ("vfs://output/{}/config_{{sample_id}}_{{cardinality}}{{ext}}").format(self.name) @@ -904,6 +936,9 @@ def set(self): if self.masks_train and len(self.masks_train) - 1 >= num: self.source_data['mask_train_' + label] = self.masks_train[num] + if self.masks_normalize_train and len(self.masks_normalize_train) - 1 >= num: + self.source_data['masks_normalize_train_' + label] = self.masks_normalize_train[num] + if self.metadata_train and len(self.metadata_train) - 1 >= num: self.source_data['metadata_train_' + label] = self.metadata_train[num] @@ -933,6 +968,9 @@ def set(self): if self.masks_test and len(self.masks_test) - 1 >= num: self.source_data['mask_test_' + label] = self.masks_test[num] + if self.masks_normalize_test and len(self.masks_normalize_test) - 1 >= num: + self.source_data['masks_normalize_test_' + label] = self.masks_normalize_test[num] + if self.metadata_test and len(self.metadata_test) - 1 >= num: self.source_data['metadata_test_' + label] = self.metadata_test[num] @@ -964,12 +1002,21 @@ def set(self): if self.images_test or self.features_test: self.sink_data['transformations_test_' + label] = ("vfs://output/{}/Elastix/transformation_{}_{{sample_id}}_{{cardinality}}{{ext}}").format(self.name, label) + if self._add_evaluation: + self.Evaluate.set() + def execute(self): """ Execute the network through the fastr.network.execute command. """ # Draw and execute nwtwork - self.network.draw(file_path=self.network.id + '.svg', draw_dimensions=True) + try: + self.network.draw(file_path=self.network.id + '.svg', draw_dimensions=True) + except graphviz.backend.ExecutableNotFound: + print('[WORC WARNING] Graphviz executable not found: not drawing network diagram. MAke sure the Graphviz executables are on your systems PATH.') self.network.execute(self.source_data, self.sink_data, execution_plugin=self.fastr_plugin, tmpdir=self.fastr_tmpdir) - # self.network.execute(self.source_data, self.sink_data) + + def add_evaluation(self, label_type): + self.Evaluate = Evaluate(label_type=label_type, parent=self) + self._add_evaluation = True class Tools(object): @@ -980,3 +1027,4 @@ class Tools(object): def __init__(self): self.Elastix = Elastix() self.Evaluate = Evaluate() + self.Slicer = Slicer() diff --git a/WORC/WORC.pyc b/WORC/WORC.pyc deleted file mode 100644 index 917b026d..00000000 Binary files a/WORC/WORC.pyc and /dev/null differ diff --git a/WORC/__init__.py b/WORC/__init__.py index 503b3f67..2645a0e5 100644 --- a/WORC/__init__.py +++ b/WORC/__init__.py @@ -1,2 +1,7 @@ from WORC.WORC import WORC -from WORC import classification, featureprocessing, processing +from WORC import classification +from WORC import featureprocessing +from WORC import processing +from WORC import plotting +from WORC import exampledata +from .facade import SimpleWORC diff --git a/WORC/__init__.pyc b/WORC/__init__.pyc deleted file mode 100644 index c18e85ad..00000000 Binary files a/WORC/__init__.pyc and /dev/null differ diff --git a/WORC/addexceptions.pyc b/WORC/addexceptions.pyc deleted file mode 100644 index 2cc69752..00000000 Binary files a/WORC/addexceptions.pyc and /dev/null differ diff --git a/WORC/classification/ObjectSampler.py b/WORC/classification/ObjectSampler.py new file mode 100644 index 00000000..56382154 --- /dev/null +++ b/WORC/classification/ObjectSampler.py @@ -0,0 +1,105 @@ +#!/usr/bin/env python + +# Copyright 2016-2019 Biomedical Imaging Group Rotterdam, Departments of +# Medical Informatics and Radiology, Erasmus MC, Rotterdam, The Netherlands +# +# 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. + +from imblearn import over_sampling, under_sampling, combine +import numpy as np +from sklearn.utils import check_random_state +import WORC.addexceptions as ae + + +class ObjectSampler(object): + """ + Samples objects for learning based on various under-, over- and combined sampling methods. + + The choice of included methods is largely based on: + + He, Haibo, and Edwardo A. Garcia. "Learning from imbalanced data." + IEEE Transactions on Knowledge & Data Engineering 9 (2008): 1263-1284. + + + """ + def __init__(self, method, + sampling_strategy='auto', + SMOTE_ratio=1, + SMOTE_neighbors=5, + n_jobs=1, + n_neighbors=3, + ): + + # Initialize a random state + self.random_seed = np.random.randint(5000) + self.random_state = check_random_state(random_seed) + + # Initialize all objects as Nones: overriden when required by functions + self.sampling_strategy = None + self.object = None + self.n_neighbors = None + self.n_jobs = None + + if method == 'RandomUnderSampling': + self.init_RandomUnderSampling(sampling_strategy) + elif method == 'NearMiss': + self.init_NearMiss(sampling_strategy, n_neighbors, n_jobs) + elif method == 'NeigbourhoodCleaningRule': + self.init_NeigbourhoodCleaningRule() + elif method == 'RandomOverSampling': + self.init_RandomOverSampling(sampling_strategy) + elif method == 'ADASYN': + self.init_ADASYN() + elif method == 'BorderlineSMOTE': + self.init_BorderlineSMOTE() + elif method == 'SMOTEENN': + self.init_SMOTEENN() + elif method == 'SMOTETomek': + self.init_SMOTETomek() + else: + raise ae.WORCKeyError(f'{method} is not a valid sampling method!') + + def init_RandomUnderSampling(self, sampling_strategy): + self.object = under_sampling.RandomUnderSampler(sampling_strategy=sampling_strategy, + random_state=self.random_state) + self.sampling_strategy = sampling_strategy + + def init_NearMiss(self, sampling_strategy, n_neighbors, n_jobs): + self.object = under_sampling.NearMiss(sampling_strategy=sampling_strategy, + random_state=self.random_state, + n_neighbors=n_neighbors, + n_jobs=n_jobs) + + self.sampling_strategy = sampling_strategy + self.n_neighbors = n_neighbors + self.n_jobs = n_jobs + + def init_RandomOverSampling(self, sampling_strategy): + self.object = over_sampling.RandomOverSampler(sampling_strategy=sampling_strategy, + random_state=self.random_state) + self.sampling_strategy = sampling_strategy + + def init_SMOTE(self): + sm = SMOTE(random_state=None, + ratio=para_estimator['SampleProcessing_SMOTE_ratio'], + m_neighbors=para_estimator['SampleProcessing_SMOTE_neighbors'], + kind='borderline1', + n_jobs=para_estimator['SampleProcessing_SMOTE_n_cores']) + + self.object = sm + + def fit(self, **kwargs): + self.object.fit(**kwargs) + + def fit(self, **kwargs): + self.object.fit(**kwargs) \ No newline at end of file diff --git a/WORC/classification/RankedSVM.py b/WORC/classification/RankedSVM.py index ba2e4d30..539cbf02 100644 --- a/WORC/classification/RankedSVM.py +++ b/WORC/classification/RankedSVM.py @@ -591,6 +591,7 @@ def RankSVM_train(train_data, train_target, cost=1, lambda_tol=1e-6, return Weights,Bias,SVs + def RankSVM_test_original(test_data, test_target, Weights, Bias, SVs, svm='Poly', gamma=0.05, coefficient=0.05, degree=3): diff --git a/WORC/classification/SearchCV.py b/WORC/classification/SearchCV.py index 91a71530..fa4f6a67 100644 --- a/WORC/classification/SearchCV.py +++ b/WORC/classification/SearchCV.py @@ -27,7 +27,7 @@ from sklearn.externals import six from sklearn.utils.fixes import MaskedArray -from sklearn.model_selection._search import _CVScoreTuple, ParameterSampler +from sklearn.model_selection._search import ParameterSampler from sklearn.model_selection._search import ParameterGrid, _check_param_grid from abc import ABCMeta, abstractmethod @@ -42,7 +42,7 @@ import fastr from fastr.api import ResourceLimit from joblib import Parallel, delayed -from WORC.classification.fitandscore import fit_and_score +from WORC.classification.fitandscore import fit_and_score, replacenan from WORC.classification.fitandscore import delete_nonestimator_parameters import WORC.addexceptions as WORCexceptions import pandas as pd @@ -97,6 +97,9 @@ class Ensemble(six.with_metaclass(ABCMeta, BaseEstimator, """Ensemble of BaseSearchCV Estimators.""" # @abstractmethod def __init__(self, estimators): + if not estimators: + message = 'You supplied an empty list of estimators: No ensemble creation possible.' + raise WORCexceptions.WORCValueError(message) self.estimators = estimators self.n_estimators = len(estimators) @@ -115,20 +118,36 @@ def predict(self, X): """ self.estimators[0]._check_is_fitted('predict') - # NOTE: Check if we are dealing with multilabel + # Check if we are dealing with multilabel + if len(self.estimators[0].predict(X).shape) == 1: + nlabels = 1 + else: + nlabels = self.estimators[0].predict(X).shape[1] + if type(self.estimators[0].best_estimator_) == OneVsRestClassifier: + multilabel = True + elif nlabels > 1: + multilabel = True + else: + multilabel = False + + if multilabel: # Multilabel - nlabels = self.estimators[0].predict(X).shape[1] outcome = np.zeros((self.n_estimators, len(X), nlabels)) for num, est in enumerate(self.estimators): if hasattr(est, 'predict_proba'): # BUG: SVM kernel can be wrong type if hasattr(est.best_estimator_, 'kernel'): est.best_estimator_.kernel = str(est.best_estimator_.kernel) - outcome[num, :, :] = est.predict_proba(X)[:, 1] + outcome[num, :, :] = est.predict_proba(X) else: outcome[num, :, :] = est.predict(X) + # Replace NAN if they are there + if np.isnan(outcome).any(): + print('[WARNING] Predictions contain NaN, removing those rows.') + outcome = outcome[~np.isnan(outcome).any(axis=1)] + outcome = np.squeeze(np.mean(outcome, axis=0)) # NOTE: Binarize specifically for multiclass @@ -149,6 +168,9 @@ def predict(self, X): else: outcome[num, :] = est.predict(X) + # Replace NAN if they are there + outcome = outcome[~np.isnan(outcome).any(axis=1)] + outcome = np.squeeze(np.mean(outcome, axis=0)) # Binarize @@ -175,19 +197,53 @@ def predict_proba(self, X): """ self.estimators[0]._check_is_fitted('predict_proba') - # For probabilities, we get both a class0 and a class1 score - outcome = np.zeros((len(X), 2)) - outcome_class1 = np.zeros((self.n_estimators, len(X))) - outcome_class2 = np.zeros((self.n_estimators, len(X))) - for num, est in enumerate(self.estimators): - # BUG: SVM kernel can be wrong type - if hasattr(est.best_estimator_, 'kernel'): - est.best_estimator_.kernel = str(est.best_estimator_.kernel) - outcome_class1[num, :] = est.predict_proba(X)[:, 0] - outcome_class2[num, :] = est.predict_proba(X)[:, 1] - - outcome[:, 0] = np.squeeze(np.mean(outcome_class1, axis=0)) - outcome[:, 1] = np.squeeze(np.mean(outcome_class2, axis=0)) + # Check if we are dealing with multilabel + if len(self.estimators[0].predict(X).shape) == 1: + nlabels = 1 + else: + nlabels = self.estimators[0].predict(X).shape[1] + + if type(self.estimators[0].best_estimator_) == OneVsRestClassifier: + multilabel = True + elif nlabels > 1: + multilabel = True + else: + multilabel = False + + if multilabel: + # Multilabel + outcome = np.zeros((self.n_estimators, len(X), nlabels)) + for num, est in enumerate(self.estimators): + if hasattr(est, 'predict_proba'): + # BUG: SVM kernel can be wrong type + if hasattr(est.best_estimator_, 'kernel'): + est.best_estimator_.kernel = str(est.best_estimator_.kernel) + outcome[num, :, :] = est.predict_proba(X) + else: + outcome[num, :, :] = est.predict(X) + + # Replace NAN if they are there + if np.isnan(outcome).any(): + print('[WARNING] Predictions contain NaN, removing those rows.') + outcome = outcome[~np.isnan(outcome).any(axis=1)] + + outcome = np.squeeze(np.mean(outcome, axis=0)) + else: + # Single label + # For probabilities, we get both a class0 and a class1 score + outcome = np.zeros((len(X), 2)) + outcome_class1 = np.zeros((self.n_estimators, len(X))) + outcome_class2 = np.zeros((self.n_estimators, len(X))) + for num, est in enumerate(self.estimators): + # BUG: SVM kernel can be wrong type + if hasattr(est.best_estimator_, 'kernel'): + est.best_estimator_.kernel = str(est.best_estimator_.kernel) + outcome_class1[num, :] = est.predict_proba(X)[:, 0] + outcome_class2[num, :] = est.predict_proba(X)[:, 1] + + outcome[:, 0] = np.squeeze(np.mean(outcome_class1, axis=0)) + outcome[:, 1] = np.squeeze(np.mean(outcome_class2, axis=0)) + return outcome def predict_log_proba(self, X): @@ -300,7 +356,8 @@ def __init__(self, param_distributions={}, n_iter=10, scoring=None, fit_params=None, n_jobs=1, iid=True, refit=True, cv=None, verbose=0, pre_dispatch='2*n_jobs', random_state=None, error_score='raise', return_train_score=True, - n_jobspercore=100, maxlen=100, fastr_plugin=None): + n_jobspercore=100, maxlen=100, fastr_plugin=None, + ranking_score='test_score'): # Added for fastr and joblib executions self.param_distributions = param_distributions @@ -322,6 +379,7 @@ def __init__(self, param_distributions={}, n_iter=10, scoring=None, self.error_score = error_score self.return_train_score = return_train_score self.maxlen = maxlen + self.ranking_score = ranking_score @property def _estimator_type(self): @@ -507,9 +565,15 @@ def inverse_transform(self, Xt): def preprocess(self, X, y=None): '''Apply the available preprocssing methods to the features''' + if self.best_scaler is not None: + X = self.best_scaler.transform(X) + if self.best_imputer is not None: X = self.best_imputer.transform(X) + # Replace nan if still left + X = replacenan(np.asarray(X)).tolist() + # Only oversample in training phase, i.e. if we have the labels if y is not None: if self.best_SMOTE is not None: @@ -527,9 +591,6 @@ def preprocess(self, X, y=None): if self.best_statisticalsel is not None: X = self.best_statisticalsel.transform(X) - if self.best_scaler is not None: - X = self.best_scaler.transform(X) - if self.best_reliefsel is not None: X = self.best_reliefsel.transform(X) @@ -551,29 +612,6 @@ def best_score_(self): check_is_fitted(self, 'cv_results_') return self.cv_results_['mean_test_score'][self.best_index_] - @property - def grid_scores_(self): - warnings.warn( - "The grid_scores_ attribute was deprecated in version 0.18" - " in favor of the more elaborate cv_results_ attribute." - " The grid_scores_ attribute will not be available from 0.20", - DeprecationWarning) - - check_is_fitted(self, 'cv_results_') - grid_scores = list() - - for i, (params, mean, std) in enumerate(zip( - self.cv_results_['params'], - self.cv_results_['mean_test_score'], - self.cv_results_['std_test_score'])): - scores = np.array(list(self.cv_results_['split%d_test_score' - % s][i] - for s in range(self.n_splits_)), - dtype=np.float64) - grid_scores.append(_CVScoreTuple(params, mean, scores)) - - return grid_scores - def process_fit(self, n_splits, parameters_est, parameters_all, test_sample_counts, test_scores, train_scores, fit_time, score_time, cv_iter, @@ -609,18 +647,22 @@ def _store(key_name, array, weights=None, splits=False, rank=False): try: array_means = np.average(array, axis=1, weights=weights) except ZeroDivisionError as e: - e = ('[PREDICT Warning] {}. Setting {} to unweighted.').format(e, key_name) + e = f'[WORC Warning] {e}. Setting {key_name} to unweighted.' print(e) array_means = np.average(array, axis=1) results['mean_%s' % key_name] = array_means + + array_mins = np.min(array, axis=1) + results['min_%s' % key_name] = array_mins + # Weighted std is not directly available in numpy try: array_stds = np.sqrt(np.average((array - array_means[:, np.newaxis]) ** 2, axis=1, weights=weights)) except ZeroDivisionError as e: - e = ('[PREDICT Warning] {}. Setting {} to unweighted.').format(e, key_name) + e = f'[WORC Warning] {e}. Setting {key_name} to unweighted.' print(e) array_stds = np.sqrt(np.average((array - array_means[:, np.newaxis]) ** 2, @@ -639,8 +681,15 @@ def _store(key_name, array, weights=None, splits=False, rank=False): _store('fit_time', fit_time) _store('score_time', score_time) + # Compute the "Generalization" score + difference_score = abs(results['mean_train_score'] - results['mean_test_score']) + generalization_score = results['mean_test_score'] - difference_score + results['generalization_score'] = generalization_score + results['rank_generalization_score'] = np.asarray( + rankdata(-results['generalization_score'], method='min'), dtype=np.int32) + # Rank the indices of scores from all parameter settings - ranked_test_scores = results["rank_test_score"] + ranked_test_scores = results["rank_" + self.ranking_score] indices = range(0, len(ranked_test_scores)) sortedindices = [x for _, x in sorted(zip(ranked_test_scores, indices))] @@ -656,7 +705,7 @@ def _store(key_name, array, weights=None, splits=False, rank=False): n_candidates = len(candidate_params_est) # Store the atributes of the best performing estimator - best_index = np.flatnonzero(results["rank_test_score"] == 1)[0] + best_index = np.flatnonzero(results["rank_" + self.ranking_score] == 1)[0] best_parameters_est = candidate_params_est[best_index] best_parameters_all = candidate_params_all[best_index] @@ -780,7 +829,6 @@ def refit_and_score(self, X, y, parameters_all, parameters_est, def create_ensemble(self, X_train, Y_train, verbose=None, initialize=True, scoring=None, method=50): - # NOTE: Function is still WIP, do not actually use this. ''' Create an (optimal) ensemble of a combination of hyperparameter settings @@ -821,7 +869,7 @@ def compute_performance(scoring, Y_valid_truth, Y_valid_score): elif scoring == 'sar': perf = sar_score(Y_valid_truth, Y_valid_score) else: - raise KeyError('[PREDICT Warning] No valid score method given in ensembling: ' + str(scoring)) + raise KeyError('[WORC Warning] No valid score method given in ensembling: ' + str(scoring)) return perf @@ -847,7 +895,11 @@ def compute_performance(scoring, Y_valid_truth, Y_valid_score): # Simply take the top50 best hyperparameters if verbose: print(f'Creating ensemble using top {str(method)} individual classifiers.') - ensemble = range(0, method) + if method == 1: + # Next functions expect list + ensemble = [0] + else: + ensemble = range(0, method) elif method == 'FitNumber': # Use optimum number of models @@ -1173,7 +1225,7 @@ def compute_performance(scoring, Y_valid_truth, Y_valid_score): print(f"Single estimator best {scoring}: {single_estimator_performance}.") print(f'Ensemble consists of {len(ensemble)} estimators {ensemble}.') else: - print('[PREDICT WARNING] No valid ensemble method given: {}. Not ensembling').format(str(method)) + print(f'[WORC WARNING] No valid ensemble method given: {method}. Not ensembling') return self # Create the ensemble -------------------------------------------------- @@ -1200,9 +1252,8 @@ def compute_performance(scoring, Y_valid_truth, Y_valid_score): estimators.append(base_estimator) self.ensemble = Ensemble(estimators) - + self.best_estimator_ = self.ensemble print("\n") - return self class BaseSearchCVfastr(BaseSearchCV): @@ -1251,8 +1302,8 @@ def _fit(self, X, y, groups, parameter_iterable): message = 'One or more of the values in your parameter sampler ' +\ 'is either not iterable, or the distribution cannot ' +\ 'generate valid samples. Please check your ' +\ - (' parameters. At least {} gives an error.').format(k) - raise PREDICTexceptions.PREDICTValueError(message) + f' parameters. At least {k} gives an error.' + raise WORCexceptions.WORCValueError(message) # Split the parameters files in equal parts keys = list(parameters_temp.keys()) @@ -1263,7 +1314,7 @@ def _fit(self, X, y, groups, parameter_iterable): for number in k: temp_dict[number] = parameters_temp[number] - fname = ('settings_{}.json').format(str(num)) + fname = f'settings_{num}.json' sourcename = os.path.join(tempfolder, 'parameters', fname) if not os.path.exists(os.path.dirname(sourcename)): os.makedirs(os.path.dirname(sourcename)) @@ -1271,10 +1322,7 @@ def _fit(self, X, y, groups, parameter_iterable): json.dump(temp_dict, fp, indent=4) parameter_files[str(num)] =\ - ('vfs://tmp/{}/{}/{}/{}').format('GS', - name, - 'parameters', - fname) + f'vfs://tmp/GS/{name}/parameters/{fname}' # Create test-train splits traintest_files = dict() @@ -1287,16 +1335,13 @@ def _fit(self, X, y, groups, parameter_iterable): index=source_labels, name='Train-test data') - fname = ('traintest_{}.hdf5').format(str(num)) + fname = f'traintest_{num}.hdf5' sourcename = os.path.join(tempfolder, 'traintest', fname) if not os.path.exists(os.path.dirname(sourcename)): os.makedirs(os.path.dirname(sourcename)) - traintest_files[str(num)] = ('vfs://tmp/{}/{}/{}/{}').format('GS', - name, - 'traintest', - fname) + traintest_files[str(num)] = f'vfs://tmp/GS/{name}/traintest/{fname}' - sourcelabel = ("Source Data Iteration {}").format(str(num)) + sourcelabel = f"Source Data Iteration {num}" source_data.to_hdf(sourcename, sourcelabel) num += 1 @@ -1309,7 +1354,7 @@ def _fit(self, X, y, groups, parameter_iterable): 'error_score'] estimator_data = pd.Series([X, y, self.scoring, - self.verbose, + False, self.fit_params, self.return_train_score, True, True, True, self.error_score], @@ -1319,10 +1364,10 @@ def _fit(self, X, y, groups, parameter_iterable): estimatorname = os.path.join(tempfolder, fname) estimator_data.to_hdf(estimatorname, 'Estimator Data') - estimatordata = ("vfs://tmp/{}/{}/{}").format('GS', name, fname) + estimatordata = f"vfs://tmp/GS/{name}/{fname}" # Create the fastr network - network = fastr.create_network('PREDICT_GridSearch_' + name) + network = fastr.create_network('WORC_GridSearch_' + name) estimator_data = network.create_source('HDF5', id='estimator_source') traintest_data = network.create_source('HDF5', id='traintest') parameter_data = network.create_source('JsonFile', id='parameters') @@ -1341,7 +1386,7 @@ def _fit(self, X, y, groups, parameter_iterable): source_data = {'estimator_source': estimatordata, 'traintest': traintest_files, 'parameters': parameter_files} - sink_data = {'output': ("vfs://tmp/{}/{}/output_{{sample_id}}_{{cardinality}}{{ext}}").format('GS', name)} + sink_data = {'output': f"vfs://tmp/GS/{name}/output_{{sample_id}}_{{cardinality}}{{ext}}"} network.execute(source_data, sink_data, tmpdir=os.path.join(tempfolder, 'tmp'), @@ -1368,11 +1413,11 @@ def _fit(self, X, y, groups, parameter_iterable): except ValueError as e: print(e) message = ('Fitting classifiers has failed. The temporary ' + - 'results where not deleted and can be found in {}. ' + + f'results where not deleted and can be found in {tempfolder}. ' + 'Probably your fitting and scoring failed: check out ' + 'the tmp/fitandscore folder within the tempfolder for ' + - 'the fastr job temporary results.').format(tempfolder) - raise PREDICTexceptions.PREDICTValueError(message) + 'the fastr job temporary results.') + raise WORCexceptions.WORCValueError(message) # Remove the temporary folder used shutil.rmtree(tempfolder) @@ -1603,13 +1648,15 @@ def __init__(self, param_distributions={}, n_iter=10, scoring=None, fit_params=None, n_jobs=1, iid=True, refit=True, cv=None, verbose=0, pre_dispatch='2*n_jobs', random_state=None, error_score='raise', return_train_score=True, - n_jobspercore=100, fastr_plugin=None): + n_jobspercore=100, fastr_plugin=None, maxlen=100, + ranking_score='test_score'): super(RandomizedSearchCVfastr, self).__init__( param_distributions=param_distributions, scoring=scoring, fit_params=fit_params, n_iter=n_iter, random_state=random_state, n_jobs=n_jobs, iid=iid, refit=refit, cv=cv, verbose=verbose, pre_dispatch=pre_dispatch, error_score=error_score, return_train_score=return_train_score, - n_jobspercore=n_jobspercore, fastr_plugin=None) + n_jobspercore=n_jobspercore, fastr_plugin=fastr_plugin, + maxlen=maxlen, ranking_score=ranking_score) def fit(self, X, y=None, groups=None): """Run fit on the estimator with randomly drawn parameters. @@ -1651,9 +1698,9 @@ def _fit(self, X, y, groups, parameter_iterable): n_splits = cv.get_n_splits(X, y, groups) if self.verbose > 0 and isinstance(parameter_iterable, Sized): n_candidates = len(parameter_iterable) - print("Fitting {0} folds for each of {1} candidates, totalling" - " {2} fits".format(n_splits, n_candidates, - n_candidates * n_splits)) + print(f"Fitting {n_splits} folds for each of {n_candidates}" +\ + " candidates, totalling" +\ + " {n_candidates * n_splits} fits") pre_dispatch = self.pre_dispatch cv_iter = list(cv.split(X, y, groups)) @@ -1668,7 +1715,7 @@ def _fit(self, X, y, groups, parameter_iterable): return_n_test_samples=True, return_times=True, return_parameters=True, error_score=self.error_score, - verbose=self.verbose, + verbose=False, return_all=False) for parameters in parameter_iterable for train, test in cv_iter) @@ -2174,14 +2221,15 @@ def __init__(self, param_distributions={}, n_iter=10, scoring=None, fit_params=None, n_jobs=1, iid=True, refit=True, cv=None, verbose=0, pre_dispatch='2*n_jobs', random_state=None, error_score='raise', return_train_score=True, - n_jobspercore=100): + n_jobspercore=100, maxlen=100, ranking_score='test_score'): super(RandomizedSearchCVJoblib, self).__init__( param_distributions=param_distributions, n_iter=n_iter, scoring=scoring, fit_params=fit_params, n_jobs=n_jobs, iid=iid, refit=refit, cv=cv, verbose=verbose, pre_dispatch=pre_dispatch, error_score=error_score, return_train_score=return_train_score, - n_jobspercore=n_jobspercore, random_state=random_state) + n_jobspercore=n_jobspercore, random_state=random_state, + maxlen=maxlen, ranking_score=ranking_score) def fit(self, X, y=None, groups=None): """Run fit on the estimator with randomly drawn parameters. diff --git a/WORC/classification/__init__.py b/WORC/classification/__init__.py index e69de29b..fac3565f 100644 --- a/WORC/classification/__init__.py +++ b/WORC/classification/__init__.py @@ -0,0 +1,9 @@ +import WORC.classification.AdvancedSampler +import WORC.classification.construct_classifier +import WORC.classification.crossval +import WORC.classification.estimators +import WORC.classification.fitandscore +import WORC.classification.metrics +import WORC.classification.parameter_optimization +import WORC.classification.SearchCV +import WORC.classification.trainclassifier diff --git a/WORC/classification/createfixedsplits.py b/WORC/classification/createfixedsplits.py new file mode 100644 index 00000000..e0db0415 --- /dev/null +++ b/WORC/classification/createfixedsplits.py @@ -0,0 +1,127 @@ +#!/usr/bin/env python + +# Copyright 2016-2019 Biomedical Imaging Group Rotterdam, Departments of +# Medical Informatics and Radiology, Erasmus MC, Rotterdam, The Netherlands +# +# 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 numpy as np +from sklearn.model_selection import train_test_split +import WORC.addexceptions as ae +from WORC.processing.label_processing import load_labels +import pandas as pd + + +def createfixedsplits(label_file=None, label_type=None, patient_IDs=None, + test_size=0.2, N_iterations=1, regression=False, + stratify=None, modus='singlelabel', output=None): + ''' + Create fixed splits for a cross validation. + ''' + # Check whether input is valid + if patient_IDs is None: + if label_file is not None and label_type is not None: + # Read the label file + label_data = load_labels(label_file, label_type) + patient_IDs = label_data['patient_IDs'] + + # Create the stratification object + if modus == 'singlelabel': + stratify = label_data['label'] + elif modus == 'multilabel': + # Create a stratification object from the labels + # Label = 0 means no label equals one + # Other label numbers refer to the label name that is 1 + stratify = list() + labels = label_data['label'] + for pnum in range(0, len(labels[0])): + plabel = 0 + for lnum, slabel in enumerate(labels): + if slabel[pnum] == 1: + plabel = lnum + 1 + stratify.append(plabel) + + else: + raise ae.WORCKeyError('{} is not a valid modus!').format(modus) + else: + raise ae.WORCIOError('Either a label file and label type or patient_IDs need to be provided!') + + pd_dict = dict() + for i in range(N_iterations): + print(f'Splitting iteration {i + 1} / {N_iterations}') + # Create a random seed for the splitting + random_seed = np.random.randint(5000) + + # Define stratification + unique_patient_IDs, unique_indices =\ + np.unique(np.asarray(patient_IDs), return_index=True) + if regression: + unique_stratify = None + else: + unique_stratify = [stratify[i] for i in unique_indices] + + # Split, throw error when dataset is too small for split ratio's + try: + unique_PID_train, indices_PID_test\ + = train_test_split(unique_patient_IDs, + test_size=test_size, + random_state=random_seed, + stratify=unique_stratify) + except ValueError as e: + e = str(e) + ' Increase the size of your test set.' + raise ae.WORCValueError(e) + + # Check for all IDs if they are in test or training + indices_train = list() + indices_test = list() + patient_ID_train = list() + patient_ID_test = list() + for num, pid in enumerate(patient_IDs): + if pid in unique_PID_train: + indices_train.append(num) + + # Make sure we get a unique ID + if pid in patient_ID_train: + n = 1 + while str(pid + '_' + str(n)) in patient_ID_train: + n += 1 + pid = str(pid + '_' + str(n)) + patient_ID_train.append(pid) + else: + indices_test.append(num) + + # Make sure we get a unique ID + if pid in patient_ID_test: + n = 1 + while str(pid + '_' + str(n)) in patient_ID_test: + n += 1 + pid = str(pid + '_' + str(n)) + patient_ID_test.append(pid) + + # Add to train object + pd_dict[str(i) + '_train'] = patient_ID_train + + # Test object has to be same length as training object + extras = [""]*(len(patient_ID_train) - len(patient_ID_test)) + patient_ID_test.extend(extras) + pd_dict[str(i) + '_test'] = patient_ID_test + + # Convert into pandas dataframe for easy use and conversion + df = pd.DataFrame(pd_dict) + + # Write output if required + if output is not None: + print("Writing Output.") + df.to_csv(output) + + return df diff --git a/WORC/classification/crossval.py b/WORC/classification/crossval.py index b58d2812..3fa880b2 100644 --- a/WORC/classification/crossval.py +++ b/WORC/classification/crossval.py @@ -20,9 +20,9 @@ import logging import os from sklearn.model_selection import train_test_split -import xlrd from .parameter_optimization import random_search_parameters import WORC.addexceptions as ae +from WORC.classification.regressors import regressors def crossval(config, label_data, image_features, @@ -103,10 +103,6 @@ def crossval(config, label_data, image_features, if tempsave: import fastr - - # Define all possible regressors - regressors = ['SVR', 'RFR', 'SGDR', 'Lasso', 'ElasticNet'] - # Process input data patient_IDs = label_data['patient_IDs'] label_value = label_data['label'] @@ -132,10 +128,8 @@ def crossval(config, label_data, image_features, feature_labels = image_features[0][1] # Check if we need to use fixedsplits: - if fixedsplits is not None and '.xlsx' in fixedsplits: - # fixedsplits = '/home/mstarmans/Settings/RandomSufflingOfData.xlsx' - wb = xlrd.open_workbook(fixedsplits) - wb = wb.sheet_by_index(1) + if fixedsplits is not None and '.csv' in fixedsplits: + fixedsplits = pd.read_csv(fixedsplits, header=0) if modus == 'singlelabel': print('Performing Single class classification.') @@ -251,17 +245,15 @@ def crossval(config, label_data, image_features, else: # Use pre defined splits - indices = wb.col_values(i) - indices = [int(j) for j in indices[1:]] # First element is "Iteration x" - train = indices[0:121] - test = indices[121:] + train = fixedsplits[str(i) + '_train'].values + test = fixedsplits[str(i) + '_test'].values # Convert the numbers to the correct indices ind_train = list() for j in train: success = False for num, p in enumerate(patient_IDs): - if str(j).zfill(3) == p[0:3]: + if j == p: ind_train.append(num) success = True if not success: @@ -271,19 +263,27 @@ def crossval(config, label_data, image_features, for j in test: success = False for num, p in enumerate(patient_IDs): - if str(j).zfill(3) == p[0:3]: + if j == p: ind_test.append(num) success = True if not success: raise ae.WORCIOError("Patient " + str(j).zfill(3) + " is not included!") - X_train = np.asarray(image_features)[ind_train].tolist() - Y_train = np.asarray(i_class_temp)[ind_train].tolist() + X_train = [image_features[i] for i in ind_train] + X_test = [image_features[i] for i in ind_test] + patient_ID_train = patient_IDs[ind_train] - X_test = np.asarray(image_features)[ind_test].tolist() - Y_test = np.asarray(i_class_temp)[ind_test].tolist() patient_ID_test = patient_IDs[ind_test] + if modus == 'singlelabel': + Y_train = i_class_temp[ind_train] + Y_test = i_class_temp[ind_test] + elif modus == 'multilabel': + Y_train = i_class_temp[ind_train, :] + Y_test = i_class_temp[ind_test, :] + else: + raise ae.WORCKeyError('{} is not a valid modus!').format(modus) + # Find best hyperparameters and construct classifier config['HyperOptimization']['use_fastr'] = use_fastr config['HyperOptimization']['fastr_plugin'] = fastr_plugin @@ -295,8 +295,7 @@ def crossval(config, label_data, image_features, **config['HyperOptimization']) # Create an ensemble if required - if ensemble['Use']: - trained_classifier.create_ensemble(X_train, Y_train) + trained_classifier.create_ensemble(X_train, Y_train, method=ensemble['Use']) # We only want to save the feature values and one label array X_train = [x[0] for x in X_train] @@ -311,12 +310,12 @@ def crossval(config, label_data, image_features, if tempsave: panda_labels = ['trained_classifier', 'X_train', 'X_test', 'Y_train', 'Y_test', 'config', 'patient_ID_train', 'patient_ID_test', - 'random_seed'] + 'random_seed', 'feature_labels'] panda_data_temp =\ pd.Series([trained_classifier, X_train, X_test, Y_train, Y_test, config, patient_ID_train, - patient_ID_test, random_seed], + patient_ID_test, random_seed, feature_labels], index=panda_labels, name='Constructed crossvalidation') diff --git a/WORC/classification/estimators.py b/WORC/classification/estimators.py index 0c71d46e..73dad4b0 100644 --- a/WORC/classification/estimators.py +++ b/WORC/classification/estimators.py @@ -19,7 +19,7 @@ from sklearn.base import BaseEstimator, ClassifierMixin from sklearn.utils.validation import check_is_fitted from sklearn.utils.multiclass import unique_labels -import WORC.classification.RankedSVM as RSVM +from WORC.classification.RankedSVM import RankSVM_train, RankSVM_test class RankedSVM(BaseEstimator, ClassifierMixin): @@ -77,7 +77,7 @@ def fit(self, X, y): self.num_class = y.shape[0] Weights, Bias, SVs =\ - RSVM.RankSVM_train(train_data=X, + RankSVM_train(train_data=X, train_target=y, cost=self.cost, lambda_tol=self.lambda_tol, @@ -111,14 +111,14 @@ def predict(self, X, y=None): check_is_fitted(self, ['X_', 'y_']) _, Predicted_Labels =\ - RSVM.RankSVM_test(test_data=X, - num_class=self.num_class, - Weights=self.Weights, - Bias=self.Bias, - SVs=self.SVs, - svm=self.svm, gamma=self.gamma, - coefficient=self.coefficient, - degree=self.degree) + RankSVM_test(test_data=X, + num_class=self.num_class, + Weights=self.Weights, + Bias=self.Bias, + SVs=self.SVs, + svm=self.svm, gamma=self.gamma, + coefficient=self.coefficient, + degree=self.degree) return Predicted_Labels @@ -140,12 +140,12 @@ def predict_proba(self, X, y): check_is_fitted(self, ['X_', 'y_']) Probs, _ =\ - RSVM.RankSVM_test(test_data=X, - num_class=self.num_class, - Weights=self.Weights, - Bias=self.Bias, - svm=self.svm, gamma=self.gamma, - coefficient=self.coefficient, - degree=self.degree) + RankSVM_test(test_data=X, + num_class=self.num_class, + Weights=self.Weights, + Bias=self.Bias, + svm=self.svm, gamma=self.gamma, + coefficient=self.coefficient, + degree=self.degree) return Probs diff --git a/WORC/classification/fitandscore.py b/WORC/classification/fitandscore.py index ac756dbc..51c23881 100644 --- a/WORC/classification/fitandscore.py +++ b/WORC/classification/fitandscore.py @@ -24,6 +24,7 @@ import scipy from sklearn.decomposition import PCA from sklearn.multiclass import OneVsRestClassifier +from sklearn.ensemble import RandomForestClassifier from imblearn.over_sampling import SMOTE, RandomOverSampler from sklearn.utils import check_random_state import random @@ -37,6 +38,10 @@ from WORC.featureprocessing.StatisticalTestThreshold import StatisticalTestThreshold from WORC.featureprocessing.SelectGroups import SelectGroups +# Specific imports for error management +from sklearn.discriminant_analysis import LinearDiscriminantAnalysis as LDA +from numpy.linalg import LinAlgError + def fit_and_score(X, y, scoring, train, test, para, @@ -178,7 +183,18 @@ def fit_and_score(X, y, scoring, the fitted object. ''' + # Set some defaults for if a part fails and we return a dummy + test_sample_counts = len(test) + fit_time = np.inf + score_time = np.inf + train_score = np.nan + test_score = np.nan + # We copy the parameter object so we can alter it and keep the original + if verbose: + print("\n") + print('#######################################') + print('Starting fit and score of new workflow.') para_estimator = para.copy() estimator = cc.construct_classifier(para_estimator) if scoring != 'average_precision_weighted': @@ -192,14 +208,36 @@ def fit_and_score(X, y, scoring, feature_values = np.asarray([x[0] for x in X]) feature_labels = np.asarray([x[1] for x in X]) + # ------------------------------------------------------------------------ + # Feature scaling + if 'FeatureScaling' in para_estimator: + if verbose: + print("Fitting scaler and transforming features.") + + if para_estimator['FeatureScaling'] == 'z_score': + scaler = StandardScaler().fit(feature_values) + elif para_estimator['FeatureScaling'] == 'minmax': + scaler = MinMaxScaler().fit(feature_values) + else: + scaler = None + + if scaler is not None: + feature_values = scaler.transform(feature_values) + del para_estimator['FeatureScaling'] + else: + scaler = None + + # Delete the object if we do not need to return it + if not return_all: + del scaler + # ------------------------------------------------------------------------ # Feature imputation if 'Imputation' in para_estimator.keys(): if para_estimator['Imputation'] == 'True': imp_type = para_estimator['ImputationMethod'] if verbose: - message = ('Imputing NaN with {}.').format(imp_type) - print(message) + print(f'Imputing NaN with {imp_type}.') imp_nn = para_estimator['ImputationNeighbours'] imputer = Imputer(missing_values=np.nan, strategy=imp_type, @@ -220,6 +258,9 @@ def fit_and_score(X, y, scoring, if not return_all: del imputer + # Remove any NaN feature values if these are still left after imputation + feature_values = replacenan(feature_values, verbose=verbose, feature_labels=feature_labels[0]) + # ------------------------------------------------------------------------ # Use SMOTE oversampling if 'SampleProcessing_SMOTE' in para_estimator.keys(): @@ -248,12 +289,8 @@ def fit_and_score(X, y, scoring, pos = int(np.sum(y)) neg = int(len(y) - pos) if verbose: - message = ("Sampling with SMOTE from {} ({} pos, {} neg) to {} ({} pos, {} neg) patients.").format(str(len_in), - str(pos_initial), - str(neg_initial), - str(len(y)), - str(pos), - str(neg)) + message = f"Sampling with SMOTE from {len_in} ({pos_initial} pos," +\ + f" {neg_initial} neg) to {len(y)} ({pos} pos, {neg} neg) patients." print(message) else: sm = None @@ -385,7 +422,9 @@ def fit_and_score(X, y, scoring, # Delete the non-used fields para_estimator = delete_nonestimator_parameters(para_estimator) - ret = [0, 0, 0, 0, 0, para_estimator, para] + ret = [train_score, test_score, test_sample_counts, + fit_time, score_time, para_estimator, para] + if return_all: return ret, GroupSel, VarSel, SelectModel, feature_labels[0], scaler, imputer, pca, StatisticalSel, ReliefSel, sm, ros else: @@ -438,43 +477,14 @@ def fit_and_score(X, y, scoring, SelectModel = None pca = None StatisticalSel = None - ret = [0, 0, 0, 0, 0, para_estimator, para] + ret = [train_score, test_score, test_sample_counts, + fit_time, score_time, para_estimator, para] + if return_all: return ret, GroupSel, VarSel, SelectModel, feature_labels[0], scaler, imputer, pca, StatisticalSel, ReliefSel, sm, ros else: return ret - # -------------------------------------------------------------------- - # Feature selection based on a statistical test - if 'StatisticalTestUse' in para_estimator.keys(): - if para_estimator['StatisticalTestUse'] == 'True': - metric = para_estimator['StatisticalTestMetric'] - threshold = para_estimator['StatisticalTestThreshold'] - if verbose: - print("Selecting features based on statistical test. Method {}, threshold {}.").format(metric, str(round(threshold, 2))) - if verbose: - print("Original Length: " + str(len(feature_values[0]))) - - StatisticalSel = StatisticalTestThreshold(metric=metric, - threshold=threshold) - - StatisticalSel.fit(feature_values, y) - feature_values = StatisticalSel.transform(feature_values) - feature_labels = StatisticalSel.transform(feature_labels) - if verbose: - print("New Length: " + str(len(feature_values[0]))) - else: - StatisticalSel = None - del para_estimator['StatisticalTestUse'] - del para_estimator['StatisticalTestMetric'] - del para_estimator['StatisticalTestThreshold'] - else: - StatisticalSel = None - - # Delete the object if we do not need to return it - if not return_all: - del StatisticalSel - # Check whether there are any features left if len(feature_values[0]) == 0: # TODO: Make a specific WORC exception for this warning. @@ -488,35 +498,14 @@ def fit_and_score(X, y, scoring, scaler = None SelectModel = None pca = None - ret = [0, 0, 0, 0, 0, para_estimator, para] + ret = [train_score, test_score, test_sample_counts, + fit_time, score_time, para_estimator, para] + if return_all: return ret, GroupSel, VarSel, SelectModel, feature_labels[0], scaler, imputer, pca, StatisticalSel, ReliefSel, sm, ros else: return ret - # ------------------------------------------------------------------------ - # Feature scaling - if 'FeatureScaling' in para_estimator: - if verbose: - print("Fitting scaler and transforming features.") - - if para_estimator['FeatureScaling'] == 'z_score': - scaler = StandardScaler().fit(feature_values) - elif para_estimator['FeatureScaling'] == 'minmax': - scaler = MinMaxScaler().fit(feature_values) - else: - scaler = None - - if scaler is not None: - feature_values = scaler.transform(feature_values) - del para_estimator['FeatureScaling'] - else: - scaler = None - - # Delete the object if we do not need to return it - if not return_all: - del scaler - # -------------------------------------------------------------------- # Relief feature selection, possibly multi classself. # Needs to be done after scaling! @@ -617,9 +606,14 @@ def fit_and_score(X, y, scoring, else: # Assume a fixed number of components n_components = int(para_estimator['PCAType']) - pca = PCA(n_components=n_components) - pca.fit(feature_values) - feature_values = pca.transform(feature_values) + + if n_components >= len(feature_values[0]): + print(f"[WORC WARNING] PCA n_components ({n_components})> n_features ({len(feature_values[0])}): skipping PCA.") + pca = None + else: + pca = PCA(n_components=n_components) + pca.fit(feature_values) + feature_values = pca.transform(feature_values) if verbose: print("New Length: " + str(len(feature_values[0]))) @@ -634,6 +628,37 @@ def fit_and_score(X, y, scoring, del para_estimator['UsePCA'] del para_estimator['PCAType'] + # -------------------------------------------------------------------- + # Feature selection based on a statistical test + if 'StatisticalTestUse' in para_estimator.keys(): + if para_estimator['StatisticalTestUse'] == 'True': + metric = para_estimator['StatisticalTestMetric'] + threshold = para_estimator['StatisticalTestThreshold'] + if verbose: + print(f"Selecting features based on statistical test. Method {metric}, threshold {round(threshold, 2)}.") + if verbose: + print("Original Length: " + str(len(feature_values[0]))) + + StatisticalSel = StatisticalTestThreshold(metric=metric, + threshold=threshold) + + StatisticalSel.fit(feature_values, y) + feature_values = StatisticalSel.transform(feature_values) + feature_labels = StatisticalSel.transform(feature_labels) + if verbose: + print("New Length: " + str(len(feature_values[0]))) + else: + StatisticalSel = None + del para_estimator['StatisticalTestUse'] + del para_estimator['StatisticalTestMetric'] + del para_estimator['StatisticalTestThreshold'] + else: + StatisticalSel = None + + # Delete the object if we do not need to return it + if not return_all: + del StatisticalSel + # ---------------------------------------------------------------- # Fitting and scoring # Only when using fastr this is an entry @@ -653,21 +678,36 @@ def fit_and_score(X, y, scoring, except IndexError: labellength = 1 - if labellength > 1 and type(estimator) != RankedSVM: - # Multiclass, hence employ a multiclass classifier for e.g. SVM, RF + if labellength > 1 and type(estimator) not in [RankedSVM, + RandomForestClassifier]: + # Multiclass, hence employ a multiclass classifier for e.g. SVM, LR estimator.set_params(**para_estimator) estimator = OneVsRestClassifier(estimator) para_estimator = {} if verbose: print("Fitting ML.") - ret = _fit_and_score(estimator, feature_values, y, - scorer, train, - test, verbose, - para_estimator, fit_params, return_train_score, - return_parameters, - return_n_test_samples, - return_times, error_score) + + try: + ret = _fit_and_score(estimator, feature_values, y, + scorer, train, + test, verbose, + para_estimator, fit_params, return_train_score, + return_parameters, + return_n_test_samples, + return_times, error_score) + except (ValueError, LinAlgError) as e: + if type(estimator) == LDA: + print('[WARNING]: skipping this setting due to LDA Error: ' + e.message) + ret = [train_score, test_score, test_sample_counts, + fit_time, score_time, para_estimator, para] + + if return_all: + return ret, GroupSel, VarSel, SelectModel, feature_labels[0], scaler, imputer, pca, StatisticalSel, ReliefSel, sm, ros + else: + return ret + else: + raise e # Remove 'estimator object', it's the causes of a bug. # Somewhere between scikit-learn 0.18.2 and 0.20.2 @@ -739,9 +779,9 @@ def replacenan(image_features, verbose=True, feature_labels=None): if np.isnan(value): if verbose: if feature_labels is not None: - print("[WORC WARNING] NaN found, patient {}, label {}. Replacing with zero.").format(pnum, feature_labels[fnum]) + print(f"[WORC WARNING] NaN found, patient {pnum}, label {feature_labels[fnum]}. Replacing with zero.") else: - print("[WORC WARNING] NaN found, patient {}, label {}. Replacing with zero.").format(pnum, fnum) + print(f"[WORC WARNING] NaN found, patient {pnum}, label {fnum}. Replacing with zero.") # Note: X is a list of lists, hence we cannot index the element directly image_features_temp[pnum, fnum] = 0 diff --git a/WORC/classification/metrics.py b/WORC/classification/metrics.py index 3af31449..dc65facd 100644 --- a/WORC/classification/metrics.py +++ b/WORC/classification/metrics.py @@ -16,7 +16,7 @@ # limitations under the License. from __future__ import division -from sklearn.metrics import accuracy_score +from sklearn.metrics import accuracy_score, balanced_accuracy_score from sklearn.metrics import roc_auc_score from sklearn.metrics import confusion_matrix from sklearn.metrics import f1_score @@ -26,6 +26,7 @@ from sklearn.metrics import make_scorer, average_precision_score from sklearn.metrics import check_scoring as check_scoring_sklearn from scipy.linalg import pinv +from imblearn.metrics import geometric_mean_score def performance_singlelabel(y_truth, y_prediction, y_score, regression=False): @@ -48,38 +49,74 @@ def performance_singlelabel(y_truth, y_prediction, y_score, regression=False): else: # Compute confuction matrics and extract measures c_mat = confusion_matrix(y_truth, y_prediction) - TN = c_mat[0, 0] - FN = c_mat[1, 0] - TP = c_mat[1, 1] - FP = c_mat[0, 1] + if c_mat.shape[0] == 0: + print('[WORC Warning] No samples in y_truth and y_prediction.') + TN = 0 + FN = 0 + TP = 0 + FP = 0 + elif c_mat.shape[0] == 1: + print('[WORC Warning] Only a single class represented in y_truth and y_prediction.') + if 0 in c_mat: + TN = c_mat[0, 0] + FN = 0 + TP = 0 + FP = 0 + else: + TN = 0 + FN = 0 + TP = c_mat[0, 0] + FP = 0 + else: + TN = c_mat[0, 0] + FN = c_mat[1, 0] + TP = c_mat[1, 1] + FP = c_mat[0, 1] - # compute confusion metric based statistics if FN == 0 and TP == 0: - sensitivity = 0 + if c_mat.shape[0] != 2: + sensitivity = np.NaN + else: + sensitivity = 0 else: sensitivity = float(TP)/(TP+FN) if FP == 0 and TN == 0: - specificity = 0 + if c_mat.shape[0] != 2: + specificity = np.NaN + else: + specificity = 0 else: specificity = float(TN)/(FP+TN) if TP == 0 and FP == 0: - precision = 0 + if c_mat.shape[0] != 2: + precision = np.NaN + else: + precision = 0 else: precision = float(TP)/(TP+FP) if TN == 0 and FN == 0: - NPV = 0 + if c_mat.shape[0] != 2: + npv = np.NaN + else: + npv = 0 else: - NPV = float(TN) / (TN + FN) + npv = float(TN) / (TN + FN) # Additionally, compute accuracy, AUC and f1-score accuracy = accuracy_score(y_truth, y_prediction) - auc = roc_auc_score(y_truth, y_score) + BCA = balanced_accuracy_score(y_truth, y_prediction) + try: + auc = roc_auc_score(y_truth, y_score) + except ValueError as e: + print('[WORC Warning] ' + e.message + '. Setting AUC to NaN.') + auc = np.NaN + f1_score_out = f1_score(y_truth, y_prediction, average='weighted') - return accuracy, sensitivity, specificity, precision, f1_score_out, auc + return accuracy, BCA, sensitivity, specificity, precision, npv, f1_score_out, auc def performance_multilabel(y_truth, y_prediction, y_score=None, beta=1): @@ -91,9 +128,11 @@ def performance_multilabel(y_truth, y_prediction, y_score=None, beta=1): y_truth = [0, 0, 0, 0, 0, 0, 2, 2, 1, 1, 2] ### Groundtruth y_prediction = [0, 0, 0, 0, 0, 0, 1, 2, 1, 2, 2] ### Predicted labels + y_score = [[0.3, 0.3, 0.4], [0.2, 0.6, 0.2], ... ] # Normalized score per patient for all labels (three in this example) Calculation of accuracy accorading to formula suggested in CAD Dementia Grand Challege http://caddementia.grand-challenge.org + and the TADPOLE challenge https://tadpole.grand-challenge.org/Performance_Metrics/ Calculation of Multi Class AUC according to classpy: https://bitbucket.org/bigr_erasmusmc/classpy/src/master/classpy/multi_class_auc.py ''' @@ -114,10 +153,19 @@ def performance_multilabel(y_truth, y_prediction, y_score=None, beta=1): FN[:, i] = np.sum(cm[i, :])-cm[i, i] FP[:, i] = np.sum(cm[:, i])-cm[i, i] TN[:, i] = np.sum(cm[:])-TP[:, i]-FP[:, i]-FN[:, i] - n[:, i] = np.sum(cm[:, i]) - # Calculation of accuracy accorading to formula suggested in CAD Dementia Grand Challege http://caddementia.grand-challenge.org - Accuracy = (np.sum(TP))/(np.sum(n)) + n = np.sum(cm) + + # Determine Accuracy + Accuracy = (np.sum(TP))/n + + # BCA: Balanced Class Accuracy + BCA = list() + for i in range(n_class): + BCAi = 1/2*(TP[:, i]/(TP[:, i] + FN[:, i]) + TN[:, i]/(TN[:, i] + FP[:, i])) + BCA.append(BCAi) + + AverageAccuracy = np.mean(BCA) # Determine total positives and negatives P = TP + FN @@ -136,6 +184,11 @@ def performance_multilabel(y_truth, y_prediction, y_score=None, beta=1): Precision = np.nan_to_num(Precision) Precision = np.mean(Precision) + # Calculation of NPV + NPV = TN/(TN+FN) + NPV = np.nan_to_num(NPV) + NPV = np.mean(NPV) + # Calculation of F1_Score F1_score = ((1+(beta**2))*(Sensitivity*Precision))/((beta**2)*(Precision + Sensitivity)) F1_score = np.nan_to_num(F1_score) @@ -147,7 +200,7 @@ def performance_multilabel(y_truth, y_prediction, y_score=None, beta=1): else: AUC = None - return Accuracy, Sensitivity, Specificity, Precision, F1_score, AUC + return Accuracy, Sensitivity, Specificity, Precision, NPV, F1_score, AUC, AverageAccuracy def pairwise_auc(y_truth, y_score, class_i, class_j): @@ -180,8 +233,8 @@ def pairwise_auc(y_truth, y_score, class_i, class_j): def multi_class_auc(y_truth, y_score): classes = np.unique(y_truth) - if any(t == 0.0 for t in np.sum(y_score, axis=1)): - raise ValueError('No AUC is calculated, output probabilities are missing') + # if any(t == 0.0 for t in np.sum(y_score, axis=1)): + # raise ValueError('No AUC is calculated, output probabilities are missing') pairwise_auc_list = [0.5 * (pairwise_auc(y_truth, y_score, i, j) + pairwise_auc(y_truth, y_score, j, i)) for i in classes for j in classes if i < j] @@ -191,7 +244,7 @@ def multi_class_auc(y_truth, y_score): def multi_class_auc_score(y_truth, y_score): - return metrics.make_scorer(multi_class_auc, needs_proba=True) + return make_scorer(multi_class_auc, needs_proba=True) def check_scoring(estimator, scoring=None, allow_none=False): @@ -200,7 +253,9 @@ def check_scoring(estimator, scoring=None, allow_none=False): scoring metrics. ''' if scoring == 'average_precision_weighted': - scorer = make_scorer(average_precision_score, average='weighted') + scorer = make_scorer(average_precision_score, average='weighted', needs_proba=True) + elif scoring == 'gmean': + scorer = make_scorer(geometric_mean_score(), needs_proba=True) else: scorer = check_scoring_sklearn(estimator, scoring=scoring) return scorer diff --git a/WORC/classification/parameter_optimization.py b/WORC/classification/parameter_optimization.py index 1a600a68..72038b9d 100644 --- a/WORC/classification/parameter_optimization.py +++ b/WORC/classification/parameter_optimization.py @@ -22,9 +22,10 @@ def random_search_parameters(features, labels, N_iter, test_size, - param_grid, scoring_method, + param_grid, scoring_method, n_splits=5, n_jobspercore=200, use_fastr=False, - n_cores=1, fastr_plugin=None): + n_cores=1, fastr_plugin=None, maxlen=100, + ranking_score='test_score'): """ Train a classifier and simultaneously optimizes hyperparameters using a randomized search. @@ -58,10 +59,10 @@ def random_search_parameters(features, labels, N_iter, test_size, regressors = ['SVR', 'RFR', 'SGDR', 'Lasso', 'ElasticNet'] if any(clf in regressors for clf in param_grid['classifiers']): # We cannot do a stratified shuffle split with regression - cv = ShuffleSplit(n_splits=5, test_size=test_size, + cv = ShuffleSplit(n_splits=n_splits, test_size=test_size, random_state=random_state) else: - cv = StratifiedShuffleSplit(n_splits=5, test_size=test_size, + cv = StratifiedShuffleSplit(n_splits=n_splits, test_size=test_size, random_state=random_state) if use_fastr: @@ -70,14 +71,20 @@ def random_search_parameters(features, labels, N_iter, test_size, scoring=scoring_method, n_jobs=n_cores, n_jobspercore=n_jobspercore, + maxlen=maxlen, verbose=1, cv=cv, - fastr_plugin=fastr_plugin) + fastr_plugin=fastr_plugin, + ranking_score=ranking_score) else: random_search = RandomizedSearchCVJoblib(param_distributions=param_grid, n_iter=N_iter, scoring=scoring_method, n_jobs=n_cores, - verbose=1, cv=cv) + n_jobspercore=n_jobspercore, + maxlen=maxlen, + verbose=1, cv=cv, + fastr_plugin=fastr_plugin, + ranking_score=ranking_score) random_search.fit(features, labels) print("Best found parameters:") for i in random_search.best_params_: diff --git a/build/lib/WORC/resources/fastr_types/PNGFile.py b/WORC/classification/regressors.py similarity index 78% rename from build/lib/WORC/resources/fastr_types/PNGFile.py rename to WORC/classification/regressors.py index 44f6b55b..cf2aa2eb 100644 --- a/build/lib/WORC/resources/fastr_types/PNGFile.py +++ b/WORC/classification/regressors.py @@ -1,4 +1,6 @@ -# Copyright 2017-2018 Biomedical Imaging Group Rotterdam, Departments of +#!/usr/bin/env python + +# Copyright 2016-2019 Biomedical Imaging Group Rotterdam, Departments of # Medical Informatics and Radiology, Erasmus MC, Rotterdam, The Netherlands # # Licensed under the Apache License, Version 2.0 (the "License"); @@ -13,10 +15,5 @@ # See the License for the specific language governing permissions and # limitations under the License. - -from fastr.datatypes import URLType - - -class PNGFile(URLType): - description = 'PNG file' - extension = 'png' +# Define all possible regressors +regressors = ['SVR', 'RFR', 'SGDR', 'Lasso', 'ElasticNet'] diff --git a/WORC/classification/trainclassifier.py b/WORC/classification/trainclassifier.py index 5b784756..7c111aaf 100644 --- a/WORC/classification/trainclassifier.py +++ b/WORC/classification/trainclassifier.py @@ -17,16 +17,14 @@ import json import os -import sklearn from WORC.classification import crossval as cv from WORC.classification import construct_classifier as cc from WORC.plotting.plot_SVM import plot_SVM -from WORC.plotting.plot_SVR import plot_single_SVR import WORC.IOparser.file_io as file_io import WORC.IOparser.config_io_classifier as config_io from scipy.stats import uniform -from WORC.classification.AdvancedSampler import discrete_uniform +from WORC.classification.AdvancedSampler import discrete_uniform, log_uniform def trainclassifier(feat_train, patientinfo_train, config, @@ -119,6 +117,9 @@ def trainclassifier(feat_train, patientinfo_train, config, print('[WORC Warning] You provided multiple output json files: only the first one will be used!') output_json = output_json[0] + if type(fixedsplits) is list: + fixedsplits = ''.join(fixedsplits) + # Load variables from the config file config = config_io.load_config(config) label_type = config['Labels']['label_names'] @@ -189,8 +190,8 @@ def trainclassifier(feat_train, patientinfo_train, config, param_grid['StatisticalTestMetric'] =\ config['Featsel']['StatisticalTestMetric'] param_grid['StatisticalTestThreshold'] =\ - uniform(loc=config['Featsel']['StatisticalTestThreshold'][0], - scale=config['Featsel']['StatisticalTestThreshold'][1]) + log_uniform(loc=config['Featsel']['StatisticalTestThreshold'][0], + scale=config['Featsel']['StatisticalTestThreshold'][1]) param_grid['ReliefUse'] =\ config['Featsel']['ReliefUse'] @@ -248,22 +249,33 @@ def trainclassifier(feat_train, patientinfo_train, config, # Calculate statistics of performance if feat_test is None: if not isclassifier: - statistics = plot_single_SVR(trained_classifier, label_data_train, - label_type) + statistics = plot_SVM(trained_classifier, label_data_train, + label_type, ensemble=config['Ensemble']['Use'], + bootstrap=config['Bootstrap']['Use'], + bootstrap_N=config['Bootstrap']['N_iterations']) else: statistics = plot_SVM(trained_classifier, label_data_train, - label_type, modus=modus) + label_type, modus=modus, + ensemble=config['Ensemble']['Use'], + bootstrap=config['Bootstrap']['Use'], + bootstrap_N=config['Bootstrap']['N_iterations']) else: if patientinfo_test is not None: if not isclassifier: - statistics = plot_single_SVR(trained_classifier, - label_data_test, - label_type) + statistics = plot_SVM(trained_classifier, + label_data_test, + label_type, + ensemble=config['Ensemble']['Use'], + bootstrap=config['Bootstrap']['Use'], + bootstrap_N=config['Bootstrap']['N_iterations']) else: statistics = plot_SVM(trained_classifier, label_data_test, label_type, - modus=modus) + modus=modus, + ensemble=config['Ensemble']['Use'], + bootstrap=config['Bootstrap']['Use'], + bootstrap_N=config['Bootstrap']['N_iterations']) else: statistics = None @@ -275,7 +287,7 @@ def trainclassifier(feat_train, patientinfo_train, config, os.makedirs(os.path.dirname(output_json)) with open(output_json, 'w') as fp: - json.dump(savedict, fp, indent=4) + json.dump(savedict, fp, sort_keys=True, indent=4) print("Saved data!") diff --git a/.eggs/PyWavelets-1.0.0-py3.7-linux-x86_64.egg/pywt/_extensions/__init__.py b/WORC/detectors/__init__.py similarity index 100% rename from .eggs/PyWavelets-1.0.0-py3.7-linux-x86_64.egg/pywt/_extensions/__init__.py rename to WORC/detectors/__init__.py diff --git a/WORC/detectors/detectors.py b/WORC/detectors/detectors.py new file mode 100644 index 00000000..e116dee3 --- /dev/null +++ b/WORC/detectors/detectors.py @@ -0,0 +1,93 @@ +import csv +import string +from abc import ABC, abstractmethod +from pathlib import Path +from os import environ +import platform + + +class AbstractDetector(ABC): + # noinspection PyBroadException + def do_detection(self, *args, **kwargs): + try: + result = self._is_detected(*args, **kwargs) + except: + result = False + print(self._generate_detector_message(result)) + return result + + def _generate_detector_message(self, detected_Value): + return f"{self.__class__.__name__[0:-8]} detected: {detected_Value}." + + @abstractmethod + def _is_detected(self, *args, **kwargs): + pass + + +class CsvDetector(AbstractDetector): + def __init__(self, csv_file_path): + self._csv_file_path = csv_file_path + + def _is_detected(self, *args, **kwargs): + try: + with open(self._csv_file_path, newline='') as csvfile: + start = csvfile.read(4096) + + # isprintable does not allow newlines, printable does not allow umlauts... + if not all([c in string.printable or c.isprintable() for c in start]): + return False + dialect = csv.Sniffer().sniff(start) # this triggers csv.Error if it can't sniff the csv dialect + return True + except csv.Error: + # Could not get a csv dialect -> probably not a csv. + return False + + +class CartesiusClusterDetector(AbstractDetector): + def _is_detected(self): + if LinuxDetector()._is_detected(): + try: + if 'cartesius' in Path('/etc/hosts').read_text(): + return True + except: + return False + return False + + +class DebugDetector(AbstractDetector): + def _is_detected(self): + try: + if environ.get('WORCDEBUG') is not None: + return True + else: + return False + except: + return False + + +class BigrClusterDetector(AbstractDetector): + def _is_detected(self): + if LinuxDetector()._is_detected(): + try: + if 'bigr-cluster' in Path('/etc/hosts').read_text(): + return True + except: + return False + return False + + +class HostnameDetector(AbstractDetector): + def _is_detected(self): + if platform.node() == self._expected_hostname: + return True + return False + + def __init__(self, expected_hostname): + self._expected_hostname = expected_hostname + + +class LinuxDetector(AbstractDetector): + def _is_detected(self): + if platform.system().lower().strip() == 'linux': + return True + return False diff --git a/WORC/doc/_build/doctrees/WORC.config.doctree b/WORC/doc/_build/doctrees/WORC.config.doctree new file mode 100644 index 00000000..c325461e Binary files /dev/null and b/WORC/doc/_build/doctrees/WORC.config.doctree differ diff --git a/WORC/doc/_build/doctrees/autogen/WORC.IOparser.doctree b/WORC/doc/_build/doctrees/autogen/WORC.IOparser.doctree index 144d0b3a..b403a4da 100644 Binary files a/WORC/doc/_build/doctrees/autogen/WORC.IOparser.doctree and b/WORC/doc/_build/doctrees/autogen/WORC.IOparser.doctree differ diff --git a/WORC/doc/_build/doctrees/autogen/WORC.classification.doctree b/WORC/doc/_build/doctrees/autogen/WORC.classification.doctree index e9eb4275..658873c2 100644 Binary files a/WORC/doc/_build/doctrees/autogen/WORC.classification.doctree and b/WORC/doc/_build/doctrees/autogen/WORC.classification.doctree differ diff --git a/WORC/doc/_build/doctrees/autogen/WORC.config.doctree b/WORC/doc/_build/doctrees/autogen/WORC.config.doctree new file mode 100644 index 00000000..dd1362ec Binary files /dev/null and b/WORC/doc/_build/doctrees/autogen/WORC.config.doctree differ diff --git a/WORC/doc/_build/doctrees/autogen/WORC.detectors.doctree b/WORC/doc/_build/doctrees/autogen/WORC.detectors.doctree new file mode 100644 index 00000000..36e1f3e0 Binary files /dev/null and b/WORC/doc/_build/doctrees/autogen/WORC.detectors.doctree differ diff --git a/WORC/doc/_build/doctrees/autogen/WORC.doctree b/WORC/doc/_build/doctrees/autogen/WORC.doctree index abde9ab4..e5c734ac 100644 Binary files a/WORC/doc/_build/doctrees/autogen/WORC.doctree and b/WORC/doc/_build/doctrees/autogen/WORC.doctree differ diff --git a/WORC/doc/_build/doctrees/autogen/WORC.exampledata.doctree b/WORC/doc/_build/doctrees/autogen/WORC.exampledata.doctree new file mode 100644 index 00000000..45e12c93 Binary files /dev/null and b/WORC/doc/_build/doctrees/autogen/WORC.exampledata.doctree differ diff --git a/WORC/doc/_build/doctrees/autogen/WORC.facade.doctree b/WORC/doc/_build/doctrees/autogen/WORC.facade.doctree new file mode 100644 index 00000000..322e2993 Binary files /dev/null and b/WORC/doc/_build/doctrees/autogen/WORC.facade.doctree differ diff --git a/WORC/doc/_build/doctrees/autogen/WORC.facade.intermediatefacade.doctree b/WORC/doc/_build/doctrees/autogen/WORC.facade.intermediatefacade.doctree new file mode 100644 index 00000000..d3c1f83c Binary files /dev/null and b/WORC/doc/_build/doctrees/autogen/WORC.facade.intermediatefacade.doctree differ diff --git a/WORC/doc/_build/doctrees/autogen/WORC.featureprocessing.doctree b/WORC/doc/_build/doctrees/autogen/WORC.featureprocessing.doctree index 144f1f7f..4172cfff 100644 Binary files a/WORC/doc/_build/doctrees/autogen/WORC.featureprocessing.doctree and b/WORC/doc/_build/doctrees/autogen/WORC.featureprocessing.doctree differ diff --git a/WORC/doc/_build/doctrees/autogen/WORC.plotting.doctree b/WORC/doc/_build/doctrees/autogen/WORC.plotting.doctree index ba08584c..34174b69 100644 Binary files a/WORC/doc/_build/doctrees/autogen/WORC.plotting.doctree and b/WORC/doc/_build/doctrees/autogen/WORC.plotting.doctree differ diff --git a/WORC/doc/_build/doctrees/autogen/WORC.processing.doctree b/WORC/doc/_build/doctrees/autogen/WORC.processing.doctree index c2828745..baba2d20 100644 Binary files a/WORC/doc/_build/doctrees/autogen/WORC.processing.doctree and b/WORC/doc/_build/doctrees/autogen/WORC.processing.doctree differ diff --git a/WORC/doc/_build/doctrees/autogen/WORC.resources.doctree b/WORC/doc/_build/doctrees/autogen/WORC.resources.doctree new file mode 100644 index 00000000..9cb804a5 Binary files /dev/null and b/WORC/doc/_build/doctrees/autogen/WORC.resources.doctree differ diff --git a/WORC/doc/_build/doctrees/autogen/WORC.resources.fastr_tests.doctree b/WORC/doc/_build/doctrees/autogen/WORC.resources.fastr_tests.doctree index 4af21a7e..3b15532b 100644 Binary files a/WORC/doc/_build/doctrees/autogen/WORC.resources.fastr_tests.doctree and b/WORC/doc/_build/doctrees/autogen/WORC.resources.fastr_tests.doctree differ diff --git a/WORC/doc/_build/doctrees/autogen/WORC.resources.fastr_tools.doctree b/WORC/doc/_build/doctrees/autogen/WORC.resources.fastr_tools.doctree new file mode 100644 index 00000000..5f50414d Binary files /dev/null and b/WORC/doc/_build/doctrees/autogen/WORC.resources.fastr_tools.doctree differ diff --git a/WORC/doc/_build/doctrees/autogen/WORC.tools.doctree b/WORC/doc/_build/doctrees/autogen/WORC.tools.doctree index 2e070ec8..d71b409e 100644 Binary files a/WORC/doc/_build/doctrees/autogen/WORC.tools.doctree and b/WORC/doc/_build/doctrees/autogen/WORC.tools.doctree differ diff --git a/WORC/doc/_build/doctrees/environment.pickle b/WORC/doc/_build/doctrees/environment.pickle index bed3fc86..75dc9e14 100644 Binary files a/WORC/doc/_build/doctrees/environment.pickle and b/WORC/doc/_build/doctrees/environment.pickle differ diff --git a/WORC/doc/_build/doctrees/index.doctree b/WORC/doc/_build/doctrees/index.doctree index 7b423f22..7ab0b80a 100644 Binary files a/WORC/doc/_build/doctrees/index.doctree and b/WORC/doc/_build/doctrees/index.doctree differ diff --git a/WORC/doc/_build/doctrees/static/changelog.doctree b/WORC/doc/_build/doctrees/static/changelog.doctree index 3a568d1b..8d75fc1e 100644 Binary files a/WORC/doc/_build/doctrees/static/changelog.doctree and b/WORC/doc/_build/doctrees/static/changelog.doctree differ diff --git a/WORC/doc/_build/doctrees/static/configuration.doctree b/WORC/doc/_build/doctrees/static/configuration.doctree index 9e13f773..5f54b60f 100644 Binary files a/WORC/doc/_build/doctrees/static/configuration.doctree and b/WORC/doc/_build/doctrees/static/configuration.doctree differ diff --git a/WORC/doc/_build/doctrees/static/quick_start.doctree b/WORC/doc/_build/doctrees/static/quick_start.doctree index e140196c..f9fb0197 100644 Binary files a/WORC/doc/_build/doctrees/static/quick_start.doctree and b/WORC/doc/_build/doctrees/static/quick_start.doctree differ diff --git a/WORC/doc/_build/doctrees/static/user_manual.doctree b/WORC/doc/_build/doctrees/static/user_manual.doctree index f7dbe551..ff3e381d 100644 Binary files a/WORC/doc/_build/doctrees/static/user_manual.doctree and b/WORC/doc/_build/doctrees/static/user_manual.doctree differ diff --git a/WORC/doc/_build/html/.buildinfo b/WORC/doc/_build/html/.buildinfo index 866db818..9730a1f5 100644 --- a/WORC/doc/_build/html/.buildinfo +++ b/WORC/doc/_build/html/.buildinfo @@ -1,4 +1,4 @@ # Sphinx build info version 1 # This file hashes the configuration used when building these files. When it is not found, a full rebuild will be done. -config: b0849071a31325117937fe1500f9c73f +config: b152a84316dacabb33ca9a33b5682953 tags: 645f666f9bcd5a90fca523b33c5a78b7 diff --git a/WORC/doc/_build/html/WORC.config.html b/WORC/doc/_build/html/WORC.config.html new file mode 100644 index 00000000..c3e2ca7c --- /dev/null +++ b/WORC/doc/_build/html/WORC.config.html @@ -0,0 +1,735 @@ + + + + + + + + + + + <no title> — WORC 3.0.0 documentation + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+ + + +
+ + + + + +
+ +
+ + + + + + + + + + + + + + + + + +
+ + + + +
+
+
+
+ + +++++++ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +

Key

Subkey

Description

Default

Options

General

cross_validation +Segmentix +FeatureCalculator +Preprocessing +RegistrationNode +TransformationNode +Joblib_ncores +Joblib_backend +tempsave

Determine whether a cross validation will be performed or not. Obsolete, will be removed. +Determine whether to use Segmentix tool for segmentation preprocessing. +Specifies which feature calculation tool should be used. +Specifies which tool will be used for image preprocessing. +Specifies which tool will be used for image registration. +Specifies which tool will be used for applying image transformations. +Number of cores to be used by joblib for multicore processing. +Type of backend to be used by joblib for multicore processing. +Determines whether after every cross validation iteration the result will be saved, in addition to the result after all iterations. Especially useful for debugging.

True +False +predict/CalcFeatures:1.0 +worc/PreProcess:1.0 +‘elastix4.8/Elastix:4.8’ +‘elastix4.8/Transformix:4.8’ +4 +multiprocessing +False

True, False +True, False +predict/CalcFeatures:1.0, pyradiomics/CF_pyradiomics:1.0, your own tool reference +worc/PreProcess:1.0, your own tool reference +‘elastix4.8/Elastix:4.8’, your own tool reference +‘elastix4.8/Transformix:4.8’, your own tool reference +Integer > 0 +multiprocessing, threading +True, False

Segmentix

mask +segtype +segradius +N_blobs +fillholes

If a mask is supplied, should the mask be subtracted from the contour or multiplied. +If Ring, then a ring around the segmentation will be used as contour. +Define the radius of the ring used if segtype is Ring. +How many of the largest blobs are extracted from the segmentation. If None, no blob extraction is used. +Determines whether hole filling will be used.

subtract +None +5 +1 +False

subtract, multiply +None, Ring +Integer > 0 +Integer > 0 +True, False

Normalize

ROI +Method

If a mask is supplied and this is set to True, normalize image based on supplied ROI. Otherwise, the full image is used for normalization using the SimpleITK Normalize function. Lastly, setting this to False will result in no normalization being applied. +Method used for normalization if ROI is supplied. Currently, z-scoring or using the minimum and median of the ROI can be used.

Full +z_score

True, False, Full +z_score, minmed

ImageFeatures

shape +histogram +orientation +texture_Gabor +texture_LBP +texture_GLCM +texture_GLCMMS +texture_GLRLM +texture_GLSZM +texture_NGTDM +coliage +vessel +log +phase +image_type +gabor_frequencies +gabor_angles +GLCM_angles +GLCM_levels +GLCM_distances +LBP_radius +LBP_npoints +phase_minwavelength +phase_nscale +log_sigma +vessel_scale_range +vessel_scale_step +vessel_radius

Determine whether orientation features are computed or not. +Determine whether histogram features are computed or not. +Determine whether orientation features are computed or not. +Determine whether Gabor texture features are computed or not. +Determine whether LBP texture features are computed or not. +Determine whether GLCM texture features are computed or not. +Determine whether GLCM Multislice texture features are computed or not. +Determine whether GLRLM texture features are computed or not. +Determine whether GLSZM texture features are computed or not. +Determine whether NGTDM texture features are computed or not. +Determine whether coliage features are computed or not. +Determine whether vessel features are computed or not. +Determine whether LoG features are computed or not. +Determine whether local phase features are computed or not. +Modality of images supplied. Determines how the image is loaded. +Frequencies of Gabor filters used: can be a single float or a list. +Angles of Gabor filters in degrees: can be a single integer or a list. +Angles used in GLCM computation in radians: can be a single float or a list. +Number of grayscale levels used in discretization before GLCM computation. +Distance(s) used in GLCM computation in pixels: can be a single integer or a list. +Radii used for LBP computation: can be a single integer or a list. +Number(s) of points used in LBP computation: can be a single integer or a list. +Minimal wavelength in pixels used for phase features. +Number of scales used in phase feature computation. +Standard deviation(s) in pixels used in log feature computation: can be a single integer or a list. +Scale in pixels used for Frangi vessel filter. Given as a minimum and a maximum. +Step size used to go from minimum to maximum scale on Frangi vessel filter. +Radius to determine boundary of between inner part and edge in Frangi vessel filter.

True +True +True +False +True +True +True +True +True +True +False +False +False +False +CT +0.05, 0.2, 0.5 +0, 45, 90, 135 +0, 0.79, 1.57, 2.36 +16 +1, 3 +3, 8, 15 +12, 24, 36 +3 +5 +1, 5, 10 +1, 10 +2 +5

True, False +True, False +True, False +True, False +True, False +True, False +True, False +True, False +True, False +True, False +True, False +True, False +True, False +True, False +CT +Float(s) +Integer(s) +Float(s) +Integer > 0 +Integer(s) > 0 +Integer(s) > 0 +Integer(s) > 0 +Integer > 0 +Integer > 0 +Integer(s) +Two integers: min and max. +Integer > 0 +Integer > 0

Featsel

Variance +GroupwiseSearch +SelectFromModel +UsePCA +PCAType +StatisticalTestUse +StatisticalTestMetric +StatisticalTestThreshold +ReliefUse +ReliefNN +ReliefSampleSize +ReliefDistanceP +ReliefNumFeatures

If True, exclude features which have a variance < 0.01. Based on ` sklearn <https://scikit-learn.org/stable/modules/generated/sklearn.feature_selection.VarianceThreshold.html/>`_. +Randomly select which feature groups to use. Parameters determined by the SelectFeatGroup config part, see below. +Select features by first training a LASSO model. The alpha for the LASSO model is randomly generated. See also sklearn. +If True, Use Principle Component Analysis (PCA) to select features. +Method to select number of components using PCA: Either the number of components that explains 95% of the variance, or use a fixed number of components.95variance +If True, use statistical test to select features. +Define the type of statistical test to be used. +Specify a threshold for the p-value threshold used in the statistical test to select features. The first element defines the lower boundary, the other the upper boundary. Random sampling will occur between the boundaries. +If True, use Relief to select features. +Min and max of number of nearest neighbors search range in Relief. +Min and max of sample size search range in Relief. +Min and max of positive distance search range in Relief. +Min and max of number of features that is selected search range in Relief.

True +True +False +False +95variance +False +ttest, Welch, Wilcoxon, MannWhitneyU +-2, 1.5 +False +2, 4 +1, 1 +1, 3 +25, 200

Boolean(s) +Boolean(s) +Boolean(s) +Boolean(s) +Inteteger(s), 95variance +Boolean(s) +ttest, Welch, Wilcoxon, MannWhitneyU +Two Integers: loc and scale +Boolean(s) +Two Integers: loc and scale +Two Integers: loc and scale +Two Integers: loc and scale +Two Integers: loc and scale

SelectFeatGroup

shape_features +histogram_features +orientation_features +texture_Gabor_features +texture_GLCM_features +texture_GLCMMS_features +texture_GLRLM_features +texture_GLSZM_features +texture_NGTDM_features +texture_LBP_features +patient_features +semantic_features +coliage_features +log_features +vessel_features +phase_features

If True, use shape features in model. +If True, use histogram features in model. +If True, use orientation features in model. +If True, use Gabor texture features in model. +If True, use GLCM texture features in model. +If True, use GLCM Multislice texture features in model. +If True, use GLRLM texture features in model. +If True, use GLSZM texture features in model. +If True, use NGTDM texture features in model. +If True, use LBP texture features in model. +If True, use patient features in model. +If True, use semantic features in model. +If True, use coliage features in model. +If True, use log features in model. +If True, use vessel features in model. +If True, use phase features in model.

True, False +True, False +True, False +False +True, False +True, False +True, False +True, False +True, False +True, False +False +False +False +False +False +False

Boolean(s) +Boolean(s) +Boolean(s) +Boolean(s) +Boolean(s) +Boolean(s) +Boolean(s) +Boolean(s) +Boolean(s) +Boolean(s) +Boolean(s) +Boolean(s) +Boolean(s) +Boolean(s) +Boolean(s) +Boolean(s)

Imputation

use +strategy +n_neighbors

If True, use feature imputation methods to replace NaN values. If False, all NaN features will be set to zero. +Method to be used for imputation. +When using k-Nearest Neighbors (kNN) for feature imputation, determines the number of neighbors used for imputation. Can be a single integer or a list.

False +mean, median, most_frequent, constant, knn +5, 5

Boolean(s) +mean, median, most_frequent, constant, knn +Two Integers: loc and scale

Classification

fastr +fastr_plugin +classifiers +max_iter +SVMKernel +SVMC +SVMdegree +SVMcoef0 +SVMgamma +RFn_estimators +RFmin_samples_split +RFmax_depth +LRpenalty +LRC +LDA_solver +LDA_shrinkage +QDA_reg_param +ElasticNet_alpha +ElasticNet_l1_ratio +SGD_alpha +SGD_l1_ratio +SGD_loss +SGD_penalty +CNB_alpha

Use fastr for the optimization gridsearch (recommended on clusters, default) or if set to False , joblib (recommended for PCs but not on Windows). +Name of execution plugin to be used. Default use the same as the self.fastr_plugin for the WORC object. +Select the estimator(s) to use. Most are implemented using sklearn. For abbreviations, see above. +Maximum number of iterations to use in training an estimator. Only for specific estimators, see sklearn. +When using a SVM, specify the kernel type. +Range of the SVM slack parameter. We sample on a uniform log scale: the parameters specify the range of the exponent (a, a + b). +Range of the SVM polynomial degree when using a polynomial kernel. We sample on a uniform scale: the parameters specify the range (a, a + b). +Range of SVM homogeneity parameter. We sample on a uniform scale: the parameters specify the range (a, a + b). +Range of the SVM gamma parameter. We sample on a uniform log scale: the parameters specify the range of the exponent (a, a + b) +Range of number of trees in a RF. We sample on a uniform scale: the parameters specify the range (a, a + b). +Range of minimum number of samples required to split a branch in a RF. We sample on a uniform scale: the parameters specify the range (a, a + b). +Range of maximum depth of a RF. We sample on a uniform scale: the parameters specify the range (a, a + b). +Penalty term used in LR. +Range of regularization strength in LR. We sample on a uniform scale: the parameters specify the range (a, a + b). +Solver used in LDA. +Range of the LDA shrinkage parameter. We sample on a uniform log scale: the parameters specify the range of the exponent (a, a + b). +Range of the QDA regularization parameter. We sample on a uniform log scale: the parameters specify the range of the exponent (a, a + b). +Range of the ElasticNet penalty parameter. We sample on a uniform log scale: the parameters specify the range of the exponent (a, a + b). +Range of l1 ratio in LR. We sample on a uniform scale: the parameters specify the range (a, a + b). +Range of the SGD penalty parameter. We sample on a uniform log scale: the parameters specify the range of the exponent (a, a + b). +Range of l1 ratio in SGD. We sample on a uniform scale: the parameters specify the range (a, a + b). +hinge, Loss function of SG +Penalty term in SGD. +Regularization strenght in ComplementNB. We sample on a uniform scale: the parameters specify the range (a, a + b)

True +LinearExecution +SVM +100000 +poly +0, 6 +1, 6 +0, 1 +-5, 5 +10, 90 +2, 3 +5, 5 +l2, l1 +0.01, 1.0 +svd, lsqr, eigen +-5, 5 +-5, 5 +-5, 5 +0, 1 +-5, 5 +0, 1 +hinge, squared_hinge, modified_huber +none, l2, l1 +0, 1

True, False +Any fastr execution plugin . +SVM , SVR, SGD, SGDR, RF, LDA, QDA, ComplementND, GaussianNB, LR, RFR, Lasso, ElasticNet. All are estimators from sklearn +Integer +poly, linear, rbf +Two Integers: loc and scale +Two Integers: loc and scale +Two Integers: loc and scale +Two Integers: loc and scale +Two Integers: loc and scale +Two Integers: loc and scale +Two Integers: loc and scale +none, l2, l1 +Two Integers: loc and scale +svd, lsqr, eigen +Two Integers: loc and scale +Two Integers: loc and scale +Two Integers: loc and scale +Two Integers: loc and scale +Two Integers: loc and scale +Two Integers: loc and scale +hinge, squared_hinge, modified_huber +none, l2, l1 +Two Integers: loc and scale

CrossValidation

N_iterations +test_size

Number of times the data is split in training and test in the outer cross-validation. +The percentage of data to be used for testing.

100 +0.2

Integer +Float

Labels

label_names +modus +url +projectID

The labels used from your label file for classification. +Determine whether multilabel or singlelabel classification or regression will be performed. +WIP +WIP

Label1, Label2 +singlelabel +WIP +WIP

String(s) +singlelabel, multilabel +Not Supported Yet +Not Supported Yet

HyperOptimization

scoring_method +test_size +n_splits +N_iterations +n_jobspercore +maxlen +ranking_score

Specify the optimization metric for your hyperparameter search. +Size of test set in the hyperoptimization cross validation, given as a percentage of the whole dataset.

+

Number of iterations used in the hyperparameter optimization. This corresponds to the number of samples drawn from the parameter grid. +Number of jobs assigned to a single core. Only used if fastr is set to true in the classfication.

+

f1_weighted +0.15 +5 +10000 +2000 +100 +test_score

Any sklearn metric +Float +5 +Integer +Integer +100 +test_score

FeatureScaling

scale_features +scaling_method

Determine whether to use feature scaling is. +Determine the scaling method.

True +z_score

Boolean(s) +z_score, minmax

SampleProcessing

SMOTE +SMOTE_ratio +SMOTE_neighbors +Oversampling

Determine whether to use SMOTE oversampling, see also ` imbalanced learn <https://imbalanced-learn.readthedocs.io/en/stable/generated/imblearn.over_sampling.SMOTE.html/>`_. +Determine the ratio of oversampling. If 1, the minority class will be oversampled to the same size as the majority class. We sample on a uniform scale: the parameters specify the range (a, a + b). +Number of neighbors used in SMOTE. This should be much smaller than the number of objects/patients you supply. We sample on a uniform scale: the parameters specify the range (a, a + b). +Determine whether to random oversampling.

True +1, 0 +5, 15 +False

Boolean(s) +Two Integers: loc and scale +Two Integers: loc and scale +Boolean(s)

Ensemble

Use

Determine whether to use ensembling or not. Either provide an integer to state how many estimators to include, or True, which will use the default ensembling method.

1

Boolean or Integer

Bootstrap

Use +N_iterations

False +1000

False +1000

+ + +
+ +
+
+ + +
+ +
+

+ © Copyright 2016 -- 2019, Biomedical Imaging Group Rotterdam, Departments of Medical Informatics and Radiology, Erasmus MC, Rotterdam, The Netherlands + +

+
+ Built with Sphinx using a theme provided by Read the Docs. + +
+ +
+
+ +
+ +
+ + + + + + + + + + + + \ No newline at end of file diff --git a/WORC/doc/_build/html/_modules/WORC/IOparser/config_WORC.html b/WORC/doc/_build/html/_modules/WORC/IOparser/config_WORC.html index da54aa30..8072c28e 100644 --- a/WORC/doc/_build/html/_modules/WORC/IOparser/config_WORC.html +++ b/WORC/doc/_build/html/_modules/WORC/IOparser/config_WORC.html @@ -8,7 +8,7 @@ - WORC.IOparser.config_WORC — WORC 3.0.0 documentation + WORC.IOparser.config_WORC — WORC 3.1.0 documentation @@ -59,7 +59,7 @@
- 3.0.0 + 3.1.0
diff --git a/WORC/doc/_build/html/_modules/WORC/IOparser/config_io_classifier.html b/WORC/doc/_build/html/_modules/WORC/IOparser/config_io_classifier.html index 620fe105..082ddd8e 100644 --- a/WORC/doc/_build/html/_modules/WORC/IOparser/config_io_classifier.html +++ b/WORC/doc/_build/html/_modules/WORC/IOparser/config_io_classifier.html @@ -8,7 +8,7 @@ - WORC.IOparser.config_io_classifier — WORC 3.0.0 documentation + WORC.IOparser.config_io_classifier — WORC 3.1.0 documentation @@ -59,7 +59,7 @@
- 3.0.0 + 3.1.0
@@ -190,14 +190,13 @@

Source code for WORC.IOparser.config_io_classifier

settings = configparser.ConfigParser() settings.read(config_file_path) - print(settings.keys()) settings_dict = {'General': dict(), 'CrossValidation': dict(), 'Labels': dict(), 'HyperOptimization': dict(), 'Classification': dict(), 'SelectFeatGroup': dict(), 'Featsel': dict(), 'FeatureScaling': dict(), 'SampleProcessing': dict(), 'Imputation': dict(), - 'Ensemble': dict()} + 'Ensemble': dict(), 'Bootstrap': dict()} settings_dict['General']['cross_validation'] =\ settings['General'].getboolean('cross_validation') @@ -399,14 +398,21 @@

Source code for WORC.IOparser.config_io_classifier

settings['HyperOptimization'].getfloat('test_size') settings_dict['HyperOptimization']['N_iter'] =\ settings['HyperOptimization'].getint('N_iterations') + settings_dict['HyperOptimization']['n_splits'] =\ + settings['HyperOptimization'].getint('n_splits') settings_dict['HyperOptimization']['n_jobspercore'] =\ int(settings['HyperOptimization']['n_jobspercore']) + settings_dict['HyperOptimization']['maxlen'] = \ + settings['HyperOptimization'].getint('maxlen') + settings_dict['HyperOptimization']['ranking_score'] = \ + str(settings['HyperOptimization']['ranking_score']) settings_dict['FeatureScaling']['scale_features'] =\ settings['FeatureScaling'].getboolean('scale_features') settings_dict['FeatureScaling']['scaling_method'] =\ str(settings['FeatureScaling']['scaling_method']) + # Settings for sample processing, i.e. oversampling, undersampling etc settings_dict['SampleProcessing']['SMOTE'] =\ [str(item).strip() for item in settings['SampleProcessing']['SMOTE'].split(',')] @@ -423,9 +429,17 @@

Source code for WORC.IOparser.config_io_classifier

[str(item).strip() for item in settings['SampleProcessing']['Oversampling'].split(',')] + # Settings for ensembling settings_dict['Ensemble']['Use'] =\ settings['Ensemble'].getboolean('Use') + # Settings for bootstrapping + settings_dict['Bootstrap']['Use'] =\ + settings['Bootstrap'].getboolean('Use') + + settings_dict['Bootstrap']['N_iterations'] =\ + settings['Bootstrap'].getint('N_iterations') + return settings_dict
diff --git a/WORC/doc/_build/html/_modules/WORC/IOparser/config_preprocessing.html b/WORC/doc/_build/html/_modules/WORC/IOparser/config_preprocessing.html index d939af43..dd7f2a32 100644 --- a/WORC/doc/_build/html/_modules/WORC/IOparser/config_preprocessing.html +++ b/WORC/doc/_build/html/_modules/WORC/IOparser/config_preprocessing.html @@ -8,7 +8,7 @@ - WORC.IOparser.config_preprocessing — WORC 3.0.0 documentation + WORC.IOparser.config_preprocessing — WORC 3.1.0 documentation @@ -59,7 +59,7 @@
- 3.0.0 + 3.1.0
diff --git a/WORC/doc/_build/html/_modules/WORC/IOparser/config_segmentix.html b/WORC/doc/_build/html/_modules/WORC/IOparser/config_segmentix.html index d0713f42..277c0da7 100644 --- a/WORC/doc/_build/html/_modules/WORC/IOparser/config_segmentix.html +++ b/WORC/doc/_build/html/_modules/WORC/IOparser/config_segmentix.html @@ -8,7 +8,7 @@ - WORC.IOparser.config_segmentix — WORC 3.0.0 documentation + WORC.IOparser.config_segmentix — WORC 3.1.0 documentation @@ -59,7 +59,7 @@
- 3.0.0 + 3.1.0
diff --git a/WORC/doc/_build/html/_modules/WORC/IOparser/file_io.html b/WORC/doc/_build/html/_modules/WORC/IOparser/file_io.html index ce04451e..84e1143a 100644 --- a/WORC/doc/_build/html/_modules/WORC/IOparser/file_io.html +++ b/WORC/doc/_build/html/_modules/WORC/IOparser/file_io.html @@ -8,7 +8,7 @@ - WORC.IOparser.file_io — WORC 3.0.0 documentation + WORC.IOparser.file_io — WORC 3.1.0 documentation @@ -59,7 +59,7 @@
- 3.0.0 + 3.1.0
@@ -253,7 +253,7 @@

Source code for WORC.IOparser.file_io

                                  pfiles,
                                  image_features)
         except ValueError as e:
-            message = e.message + '. Please take a look at your labels' +\
+            message = str(e) + '. Please take a look at your labels' +\
                 ' file and make sure it is formatted correctly. ' +\
                 'See also https://github.com/MStarmans91/WORC/wiki/The-WORC-configuration#genetics.'
             raise WORCexceptions.WORCValueError(message)
diff --git a/WORC/doc/_build/html/_modules/WORC/WORC.html b/WORC/doc/_build/html/_modules/WORC/WORC.html
index b8539902..e34e1eca 100644
--- a/WORC/doc/_build/html/_modules/WORC/WORC.html
+++ b/WORC/doc/_build/html/_modules/WORC/WORC.html
@@ -8,7 +8,7 @@
   
   
   
-  WORC.WORC — WORC 3.0.0 documentation
+  WORC.WORC — WORC 3.1.0 documentation
   
 
   
@@ -59,7 +59,7 @@
             
             
               
- 3.0.0 + 3.1.0
@@ -178,10 +178,12 @@

Source code for WORC.WORC

 from fastr.api import ResourceLimit
 import os
 from random import randint
+import graphviz
 import WORC.addexceptions as WORCexceptions
 import WORC.IOparser.config_WORC as config_io
 from WORC.tools.Elastix import Elastix
 from WORC.tools.Evaluate import Evaluate
+from WORC.tools.Slicer import Slicer
 
 
 
[docs]class WORC(object): @@ -258,7 +260,7 @@

Source code for WORC.WORC

 
     """
 
-
[docs] def __init__(self, name='WORC'): +
[docs] def __init__(self, name='test'): """Initialize WORC object. Set the initial variables all to None, except for some defaults. @@ -266,7 +268,7 @@

Source code for WORC.WORC

             name: name of the nework (string, optional)
 
         """
-        self.name = name
+        self.name = 'WORC_' + name
 
         # Initialize several objects
         self.configs = list()
@@ -277,6 +279,7 @@ 

Source code for WORC.WORC

         self.semantics_train = list()
         self.labels_train = list()
         self.masks_train = list()
+        self.masks_normalize_train = list()
         self.features_train = list()
         self.metadata_train = list()
 
@@ -285,20 +288,23 @@ 

Source code for WORC.WORC

         self.semantics_test = list()
         self.labels_test = list()
         self.masks_test = list()
+        self.masks_normalize_test = list()
         self.features_test = list()
         self.metadata_test = list()
 
         self.Elastix_Para = list()
+        self.label_names = 'Label1, Label2'
 
         # Set some defaults, name
-        self.fastr_plugin = 'ProcessPoolExecution'
+        self.fastr_plugin = 'LinearExecution'
         if name == '':
             name = [randint(0, 9) for p in range(0, 5)]
-        self.fastr_tmpdir = os.path.join(fastr.config.mounts['tmp'], 'WORC_' + str(name))
+        self.fastr_tmpdir = os.path.join(fastr.config.mounts['tmp'], self.name)
 
         self.additions = dict()
         self.CopyMetadata = True
-        self.segmode = []
+ self.segmode = [] + self._add_evaluation = False
[docs] def defaultconfig(self): """Generate a configparser object holding all default configuration values. @@ -389,14 +395,14 @@

Source code for WORC.WORC

 
         # Feature selection
         config['Featsel'] = dict()
-        config['Featsel']['Variance'] = 'True, False'
+        config['Featsel']['Variance'] = 'True'
         config['Featsel']['GroupwiseSearch'] = 'True'
         config['Featsel']['SelectFromModel'] = 'False'
         config['Featsel']['UsePCA'] = 'False'
         config['Featsel']['PCAType'] = '95variance'
         config['Featsel']['StatisticalTestUse'] = 'False'
         config['Featsel']['StatisticalTestMetric'] = 'ttest, Welch, Wilcoxon, MannWhitneyU'
-        config['Featsel']['StatisticalTestThreshold'] = '0.02, 0.2'
+        config['Featsel']['StatisticalTestThreshold'] = '-2, 1.5'
         config['Featsel']['ReliefUse'] = 'False'
         config['Featsel']['ReliefNN'] = '2, 4'
         config['Featsel']['ReliefSampleSize'] = '1, 1'
@@ -408,7 +414,7 @@ 

Source code for WORC.WORC

         config['SelectFeatGroup']['shape_features'] = 'True, False'
         config['SelectFeatGroup']['histogram_features'] = 'True, False'
         config['SelectFeatGroup']['orientation_features'] = 'True, False'
-        config['SelectFeatGroup']['texture_Gabor_features'] = 'True, False'
+        config['SelectFeatGroup']['texture_Gabor_features'] = 'False'
         config['SelectFeatGroup']['texture_GLCM_features'] = 'True, False'
         config['SelectFeatGroup']['texture_GLCMMS_features'] = 'True, False'
         config['SelectFeatGroup']['texture_GLRLM_features'] = 'True, False'
@@ -471,8 +477,11 @@ 

Source code for WORC.WORC

         config['HyperOptimization'] = dict()
         config['HyperOptimization']['scoring_method'] = 'f1_weighted'
         config['HyperOptimization']['test_size'] = '0.15'
+        config['HyperOptimization']['n_splits'] = '5'
         config['HyperOptimization']['N_iterations'] = '10000'
         config['HyperOptimization']['n_jobspercore'] = '2000'  # only relevant when using fastr in classification
+        config['HyperOptimization']['maxlen'] = '100'
+        config['HyperOptimization']['ranking_score'] = 'test_score'
 
         # Feature scaling options
         config['FeatureScaling'] = dict()
@@ -488,7 +497,12 @@ 

Source code for WORC.WORC

 
         # Ensemble options
         config['Ensemble'] = dict()
-        config['Ensemble']['Use'] = 'False'  # Still WIP
+        config['Ensemble']['Use'] = '1'
+
+        # Bootstrap options
+        config['Bootstrap'] = dict()
+        config['Bootstrap']['Use'] = 'False'
+        config['Bootstrap']['N_iterations'] = '1000'
 
         return config
@@ -526,7 +540,7 @@

Source code for WORC.WORC

                         self.configs = [self.defaultconfig()] * len(self.images_train)
                     else:
                         self.configs = [self.defaultconfig()] * len(self.features_train)
-                self.network = fastr.create_network('WORC_' + self.name)
+                self.network = fastr.create_network(self.name)
 
                 # BUG: We currently use the first configuration as general config
                 image_types = list()
@@ -566,6 +580,12 @@ 

Source code for WORC.WORC

                 self.sink_classification.input = self.classify.outputs['classification']
                 self.sink_performance.input = self.classify.outputs['performance']
 
+                if self.masks_normalize_train:
+                    self.sources_masks_normalize_train = dict()
+
+                if self.masks_normalize_test:
+                    self.sources_masks_normalize_test = dict()
+
                 if not self.features_train:
                     # Create nodes to compute features
                     self.sources_parameters = dict()
@@ -732,12 +752,24 @@ 

Source code for WORC.WORC

                         if self.metadata_test and len(self.metadata_test) >= nmod + 1:
                             self.preprocessing_test[label].inputs['metadata'] = self.sources_metadata_test[label].output
 
+                        # If there are masks to use in normalization, add them here
+                        if self.masks_normalize_train:
+                            self.sources_masks_normalize_train[label] = self.network.create_source('ITKImageFile', id='masks_normalize_train_' + label, node_group='train')
+                            self.preprocessing_train[label].inputs['mask'] = self.sources_masks_normalize_train[label].output
+
+                        if self.masks_normalize_test:
+                            self.sources_masks_normalize_test[label] = self.network.create_source('ITKImageFile', id='masks_normalize_test_' + label, node_group='test')
+                            self.preprocessing_test[label].inputs['mask'] = self.sources_masks_normalize_test[label].output
+
                         # -----------------------------------------------------
                         # Create a feature calculator node
                         calcfeat_node = str(self.configs[nmod]['General']['FeatureCalculator'])
-                        self.calcfeatures_train[label] = self.network.create_node(calcfeat_node, tool_version='1.0', id='calcfeatures_train_' + label, resources=ResourceLimit(memory='14G'))
+                        node_ID = '_'.join([self.configs[nmod]['General']['FeatureCalculator'].replace(':', '_').replace('.', '_').replace('/', '_'),
+                                            label])
+
+                        self.calcfeatures_train[label] = self.network.create_node(calcfeat_node, tool_version='1.0', id='calcfeatures_train_' + node_ID, resources=ResourceLimit(memory='14G'))
                         if self.images_test or self.features_test:
-                            self.calcfeatures_test[label] = self.network.create_node(calcfeat_node, tool_version='1.0', id='calcfeatures_test_' + label, resources=ResourceLimit(memory='14G'))
+                            self.calcfeatures_test[label] = self.network.create_node(calcfeat_node, tool_version='1.0', id='calcfeatures_test_' + node_ID, resources=ResourceLimit(memory='14G'))
 
                         # Create required links
                         self.calcfeatures_train[label].inputs['parameters'] = self.sources_parameters[label].output
@@ -750,8 +782,8 @@ 

Source code for WORC.WORC

                         if self.metadata_train and len(self.metadata_train) >= nmod + 1:
                             self.calcfeatures_train[label].inputs['metadata'] = self.sources_metadata_train[label].output
 
-                        if self.metadata_train and len(self.metadata_test) >= nmod + 1:
-                            self.calcfeatures_train[label].inputs['metadata'] = self.sources_metadata_train[label].output
+                        if self.metadata_test and len(self.metadata_test) >= nmod + 1:
+                            self.calcfeatures_test[label].inputs['metadata'] = self.sources_metadata_test[label].output
 
                         if self.semantics_train and len(self.semantics_train) >= nmod + 1:
                             self.sources_semantics_train[label] = self.network.create_source('CSVFile', id='semantics_train_' + label)
@@ -1032,12 +1064,12 @@ 

Source code for WORC.WORC

                 config = configparser.ConfigParser()
                 config.read(c)
                 c = config
-            cfile = os.path.join(fastr.config.mounts['tmp'], 'WORC_' + self.name, ("config_{}_{}.ini").format(self.name, num))
+            cfile = os.path.join(self.fastr_tmpdir, f"config_{self.name}_{num}.ini")
             if not os.path.exists(os.path.dirname(cfile)):
                 os.makedirs(os.path.dirname(cfile))
             with open(cfile, 'w') as configfile:
                 c.write(configfile)
-            self.fastrconfigs.append(("vfs://tmp/{}/config_{}_{}.ini").format('WORC_' + self.name, self.name, num))
+            self.fastrconfigs.append(cfile)
 
         # Generate gridsearch parameter files if required
         # TODO: We now use the first configuration for the classifier, but his needs to be separated from the rest per modality
@@ -1047,7 +1079,7 @@ 

Source code for WORC.WORC

         self.source_data['patientclass_train'] = self.labels_train
         self.source_data['patientclass_test'] = self.labels_test
 
-        self.sink_data['classification'] = ("vfs://output/{}/svm_{{sample_id}}_{{cardinality}}{{ext}}").format(self.name)
+        self.sink_data['classification'] = ("vfs://output/{}/estimator_{{sample_id}}_{{cardinality}}{{ext}}").format(self.name)
         self.sink_data['performance'] = ("vfs://output/{}/performance_{{sample_id}}_{{cardinality}}{{ext}}").format(self.name)
         self.sink_data['config_classification_sink'] = ("vfs://output/{}/config_{{sample_id}}_{{cardinality}}{{ext}}").format(self.name)
 
@@ -1062,6 +1094,9 @@ 

Source code for WORC.WORC

             if self.masks_train and len(self.masks_train) - 1 >= num:
                 self.source_data['mask_train_' + label] = self.masks_train[num]
 
+            if self.masks_normalize_train and len(self.masks_normalize_train) - 1 >= num:
+                self.source_data['masks_normalize_train_' + label] = self.masks_normalize_train[num]
+
             if self.metadata_train and len(self.metadata_train) - 1 >= num:
                 self.source_data['metadata_train_' + label] = self.metadata_train[num]
 
@@ -1091,6 +1126,9 @@ 

Source code for WORC.WORC

             if self.masks_test and len(self.masks_test) - 1 >= num:
                 self.source_data['mask_test_' + label] = self.masks_test[num]
 
+            if self.masks_normalize_test and len(self.masks_normalize_test) - 1 >= num:
+                self.source_data['masks_normalize_test_' + label] = self.masks_normalize_test[num]
+
             if self.metadata_test and len(self.metadata_test) - 1 >= num:
                 self.source_data['metadata_test_' + label] = self.metadata_test[num]
 
@@ -1120,14 +1158,23 @@ 

Source code for WORC.WORC

                 if self.segmode == 'Register':
                     self.sink_data['transformations_train_' + label] = ("vfs://output/{}/Elastix/transformation_{}_{{sample_id}}_{{cardinality}}{{ext}}").format(self.name, label)
                     if self.images_test or self.features_test:
-                        self.sink_data['transformations_test_' + label] = ("vfs://output/{}/Elastix/transformation_{}_{{sample_id}}_{{cardinality}}{{ext}}").format(self.name, label)
+ self.sink_data['transformations_test_' + label] = ("vfs://output/{}/Elastix/transformation_{}_{{sample_id}}_{{cardinality}}{{ext}}").format(self.name, label) + + if self._add_evaluation: + self.Evaluate.set()
[docs] def execute(self): """ Execute the network through the fastr.network.execute command. """ # Draw and execute nwtwork - self.network.draw(file_path=self.network.id + '.svg', draw_dimensions=True) - self.network.execute(self.source_data, self.sink_data, execution_plugin=self.fastr_plugin, tmpdir=self.fastr_tmpdir)
- # self.network.execute(self.source_data, self.sink_data) + try: + self.network.draw(file_path=self.network.id + '.svg', draw_dimensions=True) + except graphviz.backend.ExecutableNotFound: + print('[WORC WARNING] Graphviz executable not found: not drawing network diagram. MAke sure the Graphviz executables are on your systems PATH.') + self.network.execute(self.source_data, self.sink_data, execution_plugin=self.fastr_plugin, tmpdir=self.fastr_tmpdir)
+ +
[docs] def add_evaluation(self, label_type): + self.Evaluate = Evaluate(label_type=label_type, parent=self) + self._add_evaluation = True
[docs]class Tools(object): @@ -1137,7 +1184,8 @@

Source code for WORC.WORC

     '''
 
[docs] def __init__(self): self.Elastix = Elastix() - self.Evaluate = Evaluate()
+ self.Evaluate = Evaluate() + self.Slicer = Slicer()
diff --git a/WORC/doc/_build/html/_modules/WORC/addexceptions.html b/WORC/doc/_build/html/_modules/WORC/addexceptions.html index 1bde6d65..0bf87ebf 100644 --- a/WORC/doc/_build/html/_modules/WORC/addexceptions.html +++ b/WORC/doc/_build/html/_modules/WORC/addexceptions.html @@ -8,7 +8,7 @@ - WORC.addexceptions — WORC 3.0.0 documentation + WORC.addexceptions — WORC 3.1.0 documentation @@ -59,7 +59,7 @@
- 3.0.0 + 3.1.0
diff --git a/WORC/doc/_build/html/_modules/WORC/classification/AdvancedSampler.html b/WORC/doc/_build/html/_modules/WORC/classification/AdvancedSampler.html index 9d2babaf..01e30c52 100644 --- a/WORC/doc/_build/html/_modules/WORC/classification/AdvancedSampler.html +++ b/WORC/doc/_build/html/_modules/WORC/classification/AdvancedSampler.html @@ -8,7 +8,7 @@ - WORC.classification.AdvancedSampler — WORC 3.0.0 documentation + WORC.classification.AdvancedSampler — WORC 3.1.0 documentation @@ -59,7 +59,7 @@
- 3.0.0 + 3.1.0
diff --git a/WORC/doc/_build/html/_modules/WORC/classification/ObjectSampler.html b/WORC/doc/_build/html/_modules/WORC/classification/ObjectSampler.html new file mode 100644 index 00000000..7fba7880 --- /dev/null +++ b/WORC/doc/_build/html/_modules/WORC/classification/ObjectSampler.html @@ -0,0 +1,305 @@ + + + + + + + + + + + WORC.classification.ObjectSampler — WORC 3.1.0 documentation + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+ + + +
+ + + + + +
+ +
+ + + + + + + + + + + + + + + + + +
+ +
    + +
  • Docs »
  • + +
  • Module code »
  • + +
  • WORC.classification.ObjectSampler
  • + + +
  • + +
  • + +
+ + +
+
+
+
+ +

Source code for WORC.classification.ObjectSampler

+#!/usr/bin/env python
+
+# Copyright 2016-2019 Biomedical Imaging Group Rotterdam, Departments of
+# Medical Informatics and Radiology, Erasmus MC, Rotterdam, The Netherlands
+#
+# 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.
+
+from imblearn import over_sampling, under_sampling, combine
+import numpy as np
+from sklearn.utils import check_random_state
+import WORC.addexceptions as ae
+
+
+
[docs]class ObjectSampler(object): + """ + Samples objects for learning based on various under-, over- and combined sampling methods. + + The choice of included methods is largely based on: + + He, Haibo, and Edwardo A. Garcia. "Learning from imbalanced data." + IEEE Transactions on Knowledge & Data Engineering 9 (2008): 1263-1284. + + + """ +
[docs] def __init__(self, method, + sampling_strategy='auto', + SMOTE_ratio=1, + SMOTE_neighbors=5, + n_jobs=1, + n_neighbors=3, + ): + + # Initialize a random state + self.random_seed = np.random.randint(5000) + self.random_state = check_random_state(random_seed) + + # Initialize all objects as Nones: overriden when required by functions + self.sampling_strategy = None + self.object = None + self.n_neighbors = None + self.n_jobs = None + + if method == 'RandomUnderSampling': + self.init_RandomUnderSampling(sampling_strategy) + elif method == 'NearMiss': + self.init_NearMiss(sampling_strategy, n_neighbors, n_jobs) + elif method == 'NeigbourhoodCleaningRule': + self.init_NeigbourhoodCleaningRule() + elif method == 'RandomOverSampling': + self.init_RandomOverSampling(sampling_strategy) + elif method == 'ADASYN': + self.init_ADASYN() + elif method == 'BorderlineSMOTE': + self.init_BorderlineSMOTE() + elif method == 'SMOTEENN': + self.init_SMOTEENN() + elif method == 'SMOTETomek': + self.init_SMOTETomek() + else: + raise ae.WORCKeyError(f'{method} is not a valid sampling method!')
+ +
[docs] def init_RandomUnderSampling(self, sampling_strategy): + self.object = under_sampling.RandomUnderSampler(sampling_strategy=sampling_strategy, + random_state=self.random_state) + self.sampling_strategy = sampling_strategy
+ +
[docs] def init_NearMiss(self, sampling_strategy, n_neighbors, n_jobs): + self.object = under_sampling.NearMiss(sampling_strategy=sampling_strategy, + random_state=self.random_state, + n_neighbors=n_neighbors, + n_jobs=n_jobs) + + self.sampling_strategy = sampling_strategy + self.n_neighbors = n_neighbors + self.n_jobs = n_jobs
+ +
[docs] def init_RandomOverSampling(self, sampling_strategy): + self.object = over_sampling.RandomOverSampler(sampling_strategy=sampling_strategy, + random_state=self.random_state) + self.sampling_strategy = sampling_strategy
+ +
[docs] def init_SMOTE(self): + sm = SMOTE(random_state=None, + ratio=para_estimator['SampleProcessing_SMOTE_ratio'], + m_neighbors=para_estimator['SampleProcessing_SMOTE_neighbors'], + kind='borderline1', + n_jobs=para_estimator['SampleProcessing_SMOTE_n_cores']) + + self.object = sm
+ + def fit(self, **kwargs): + self.object.fit(**kwargs) + +
[docs] def fit(self, **kwargs): + self.object.fit(**kwargs)
+
+ +
+ +
+
+ + +
+ +
+

+ © Copyright 2016 -- 2019, Biomedical Imaging Group Rotterdam, Departments of Medical Informatics and Radiology, Erasmus MC, Rotterdam, The Netherlands + +

+
+ Built with Sphinx using a theme provided by Read the Docs. + +
+ +
+
+ +
+ +
+ + + + + + + + + + + + \ No newline at end of file diff --git a/WORC/doc/_build/html/_modules/WORC/classification/RankedSVM.html b/WORC/doc/_build/html/_modules/WORC/classification/RankedSVM.html index 23d1f36b..faff681d 100644 --- a/WORC/doc/_build/html/_modules/WORC/classification/RankedSVM.html +++ b/WORC/doc/_build/html/_modules/WORC/classification/RankedSVM.html @@ -8,7 +8,7 @@ - WORC.classification.RankedSVM — WORC 3.0.0 documentation + WORC.classification.RankedSVM — WORC 3.1.0 documentation @@ -59,7 +59,7 @@
- 3.0.0 + 3.1.0
@@ -749,6 +749,7 @@

Source code for WORC.classification.RankedSVM

return Weights,Bias,SVs
+
[docs]def RankSVM_test_original(test_data, test_target, Weights, Bias, SVs, svm='Poly', gamma=0.05, coefficient=0.05, degree=3): diff --git a/WORC/doc/_build/html/_modules/WORC/classification/SearchCV.html b/WORC/doc/_build/html/_modules/WORC/classification/SearchCV.html index fc183c9d..3ef64fb4 100644 --- a/WORC/doc/_build/html/_modules/WORC/classification/SearchCV.html +++ b/WORC/doc/_build/html/_modules/WORC/classification/SearchCV.html @@ -8,7 +8,7 @@ - WORC.classification.SearchCV — WORC 3.0.0 documentation + WORC.classification.SearchCV — WORC 3.1.0 documentation @@ -59,7 +59,7 @@
- 3.0.0 + 3.1.0
@@ -185,7 +185,7 @@

Source code for WORC.classification.SearchCV

from sklearn.externals import six
 from sklearn.utils.fixes import MaskedArray
 
-from sklearn.model_selection._search import _CVScoreTuple, ParameterSampler
+from sklearn.model_selection._search import ParameterSampler
 from sklearn.model_selection._search import ParameterGrid, _check_param_grid
 
 from abc import ABCMeta, abstractmethod
@@ -200,7 +200,7 @@ 

Source code for WORC.classification.SearchCV

import fastr
 from fastr.api import ResourceLimit
 from joblib import Parallel, delayed
-from WORC.classification.fitandscore import fit_and_score
+from WORC.classification.fitandscore import fit_and_score, replacenan
 from WORC.classification.fitandscore import delete_nonestimator_parameters
 import WORC.addexceptions as WORCexceptions
 import pandas as pd
@@ -255,6 +255,9 @@ 

Source code for WORC.classification.SearchCV

"""Ensemble of BaseSearchCV Estimators."""
     # @abstractmethod
 
[docs] def __init__(self, estimators): + if not estimators: + message = 'You supplied an empty list of estimators: No ensemble creation possible.' + raise WORCexceptions.WORCValueError(message) self.estimators = estimators self.n_estimators = len(estimators)
@@ -273,20 +276,36 @@

Source code for WORC.classification.SearchCV

        """
         self.estimators[0]._check_is_fitted('predict')
 
-        # NOTE: Check if we are dealing with multilabel
+        # Check if we are dealing with multilabel
+        if len(self.estimators[0].predict(X).shape) == 1:
+            nlabels = 1
+        else:
+            nlabels = self.estimators[0].predict(X).shape[1]
+
         if type(self.estimators[0].best_estimator_) == OneVsRestClassifier:
+            multilabel = True
+        elif nlabels > 1:
+            multilabel = True
+        else:
+            multilabel = False
+
+        if multilabel:
             # Multilabel
-            nlabels = self.estimators[0].predict(X).shape[1]
             outcome = np.zeros((self.n_estimators, len(X), nlabels))
             for num, est in enumerate(self.estimators):
                 if hasattr(est, 'predict_proba'):
                     # BUG: SVM kernel can be wrong type
                     if hasattr(est.best_estimator_, 'kernel'):
                         est.best_estimator_.kernel = str(est.best_estimator_.kernel)
-                    outcome[num, :, :] = est.predict_proba(X)[:, 1]
+                    outcome[num, :, :] = est.predict_proba(X)
                 else:
                     outcome[num, :, :] = est.predict(X)
 
+            # Replace NAN if they are there
+            if np.isnan(outcome).any():
+                print('[WARNING] Predictions contain NaN, removing those rows.')
+                outcome = outcome[~np.isnan(outcome).any(axis=1)]
+
             outcome = np.squeeze(np.mean(outcome, axis=0))
 
             # NOTE: Binarize specifically for multiclass
@@ -307,6 +326,9 @@ 

Source code for WORC.classification.SearchCV

else:
                     outcome[num, :] = est.predict(X)
 
+            # Replace NAN if they are there
+            outcome = outcome[~np.isnan(outcome).any(axis=1)]
+
             outcome = np.squeeze(np.mean(outcome, axis=0))
 
             # Binarize
@@ -333,19 +355,53 @@ 

Source code for WORC.classification.SearchCV

        """
         self.estimators[0]._check_is_fitted('predict_proba')
 
-        # For probabilities, we get both a class0 and a class1 score
-        outcome = np.zeros((len(X), 2))
-        outcome_class1 = np.zeros((self.n_estimators, len(X)))
-        outcome_class2 = np.zeros((self.n_estimators, len(X)))
-        for num, est in enumerate(self.estimators):
-            # BUG: SVM kernel can be wrong type
-            if hasattr(est.best_estimator_, 'kernel'):
-                est.best_estimator_.kernel = str(est.best_estimator_.kernel)
-            outcome_class1[num, :] = est.predict_proba(X)[:, 0]
-            outcome_class2[num, :] = est.predict_proba(X)[:, 1]
-
-        outcome[:, 0] = np.squeeze(np.mean(outcome_class1, axis=0))
-        outcome[:, 1] = np.squeeze(np.mean(outcome_class2, axis=0))
+        # Check if we are dealing with multilabel
+        if len(self.estimators[0].predict(X).shape) == 1:
+            nlabels = 1
+        else:
+            nlabels = self.estimators[0].predict(X).shape[1]
+
+        if type(self.estimators[0].best_estimator_) == OneVsRestClassifier:
+            multilabel = True
+        elif nlabels > 1:
+            multilabel = True
+        else:
+            multilabel = False
+
+        if multilabel:
+            # Multilabel
+            outcome = np.zeros((self.n_estimators, len(X), nlabels))
+            for num, est in enumerate(self.estimators):
+                if hasattr(est, 'predict_proba'):
+                    # BUG: SVM kernel can be wrong type
+                    if hasattr(est.best_estimator_, 'kernel'):
+                        est.best_estimator_.kernel = str(est.best_estimator_.kernel)
+                    outcome[num, :, :] = est.predict_proba(X)
+                else:
+                    outcome[num, :, :] = est.predict(X)
+
+            # Replace NAN if they are there
+            if np.isnan(outcome).any():
+                print('[WARNING] Predictions contain NaN, removing those rows.')
+                outcome = outcome[~np.isnan(outcome).any(axis=1)]
+
+            outcome = np.squeeze(np.mean(outcome, axis=0))
+        else:
+            # Single label
+            # For probabilities, we get both a class0 and a class1 score
+            outcome = np.zeros((len(X), 2))
+            outcome_class1 = np.zeros((self.n_estimators, len(X)))
+            outcome_class2 = np.zeros((self.n_estimators, len(X)))
+            for num, est in enumerate(self.estimators):
+                # BUG: SVM kernel can be wrong type
+                if hasattr(est.best_estimator_, 'kernel'):
+                    est.best_estimator_.kernel = str(est.best_estimator_.kernel)
+                outcome_class1[num, :] = est.predict_proba(X)[:, 0]
+                outcome_class2[num, :] = est.predict_proba(X)[:, 1]
+
+            outcome[:, 0] = np.squeeze(np.mean(outcome_class1, axis=0))
+            outcome[:, 1] = np.squeeze(np.mean(outcome_class2, axis=0))
+
         return outcome
[docs] def predict_log_proba(self, X): @@ -458,7 +514,8 @@

Source code for WORC.classification.SearchCV

fit_params=None, n_jobs=1, iid=True,
                  refit=True, cv=None, verbose=0, pre_dispatch='2*n_jobs',
                  random_state=None, error_score='raise', return_train_score=True,
-                 n_jobspercore=100, maxlen=100, fastr_plugin=None):
+                 n_jobspercore=100, maxlen=100, fastr_plugin=None,
+                 ranking_score='test_score'):
 
         # Added for fastr and joblib executions
         self.param_distributions = param_distributions
@@ -479,7 +536,8 @@ 

Source code for WORC.classification.SearchCV

self.pre_dispatch = pre_dispatch
         self.error_score = error_score
         self.return_train_score = return_train_score
-        self.maxlen = maxlen
+ self.maxlen = maxlen + self.ranking_score = ranking_score
@property def _estimator_type(self): @@ -665,9 +723,15 @@

Source code for WORC.classification.SearchCV

[docs]    def preprocess(self, X, y=None):
         '''Apply the available preprocssing methods to the features'''
+        if self.best_scaler is not None:
+            X = self.best_scaler.transform(X)
+
         if self.best_imputer is not None:
             X = self.best_imputer.transform(X)
 
+        # Replace nan if still left
+        X = replacenan(np.asarray(X)).tolist()
+
         # Only oversample in training phase, i.e. if we have the labels
         if y is not None:
             if self.best_SMOTE is not None:
@@ -685,9 +749,6 @@ 

Source code for WORC.classification.SearchCV

if self.best_statisticalsel is not None:
             X = self.best_statisticalsel.transform(X)
 
-        if self.best_scaler is not None:
-            X = self.best_scaler.transform(X)
-
         if self.best_reliefsel is not None:
             X = self.best_reliefsel.transform(X)
 
@@ -709,29 +770,6 @@ 

Source code for WORC.classification.SearchCV

check_is_fitted(self, 'cv_results_')
         return self.cv_results_['mean_test_score'][self.best_index_]
 
-    @property
-    def grid_scores_(self):
-        warnings.warn(
-            "The grid_scores_ attribute was deprecated in version 0.18"
-            " in favor of the more elaborate cv_results_ attribute."
-            " The grid_scores_ attribute will not be available from 0.20",
-            DeprecationWarning)
-
-        check_is_fitted(self, 'cv_results_')
-        grid_scores = list()
-
-        for i, (params, mean, std) in enumerate(zip(
-                self.cv_results_['params'],
-                self.cv_results_['mean_test_score'],
-                self.cv_results_['std_test_score'])):
-            scores = np.array(list(self.cv_results_['split%d_test_score'
-                                                    % s][i]
-                                   for s in range(self.n_splits_)),
-                              dtype=np.float64)
-            grid_scores.append(_CVScoreTuple(params, mean, scores))
-
-        return grid_scores
-
 
[docs] def process_fit(self, n_splits, parameters_est, parameters_all, test_sample_counts, test_scores, train_scores, fit_time, score_time, cv_iter, @@ -767,18 +805,22 @@

Source code for WORC.classification.SearchCV

try:
                 array_means = np.average(array, axis=1, weights=weights)
             except ZeroDivisionError as e:
-                e = ('[PREDICT Warning] {}. Setting {} to unweighted.').format(e, key_name)
+                e = f'[WORC Warning] {e}. Setting {key_name} to unweighted.'
                 print(e)
                 array_means = np.average(array, axis=1)
 
             results['mean_%s' % key_name] = array_means
+
+            array_mins = np.min(array, axis=1)
+            results['min_%s' % key_name] = array_mins
+
             # Weighted std is not directly available in numpy
             try:
                 array_stds = np.sqrt(np.average((array -
                                                  array_means[:, np.newaxis]) ** 2,
                                                 axis=1, weights=weights))
             except ZeroDivisionError as e:
-                e = ('[PREDICT Warning] {}. Setting {} to unweighted.').format(e, key_name)
+                e = f'[WORC Warning] {e}. Setting {key_name} to unweighted.'
                 print(e)
                 array_stds = np.sqrt(np.average((array -
                                                  array_means[:, np.newaxis]) ** 2,
@@ -797,8 +839,15 @@ 

Source code for WORC.classification.SearchCV

_store('fit_time', fit_time)
         _store('score_time', score_time)
 
+        # Compute the "Generalization" score
+        difference_score = abs(results['mean_train_score'] - results['mean_test_score'])
+        generalization_score = results['mean_test_score'] - difference_score
+        results['generalization_score'] = generalization_score
+        results['rank_generalization_score'] = np.asarray(
+            rankdata(-results['generalization_score'], method='min'), dtype=np.int32)
+
         # Rank the indices of scores from all parameter settings
-        ranked_test_scores = results["rank_test_score"]
+        ranked_test_scores = results["rank_" + self.ranking_score]
         indices = range(0, len(ranked_test_scores))
         sortedindices = [x for _, x in sorted(zip(ranked_test_scores, indices))]
 
@@ -814,7 +863,7 @@ 

Source code for WORC.classification.SearchCV

n_candidates = len(candidate_params_est)
 
         # Store the atributes of the best performing estimator
-        best_index = np.flatnonzero(results["rank_test_score"] == 1)[0]
+        best_index = np.flatnonzero(results["rank_" + self.ranking_score] == 1)[0]
         best_parameters_est = candidate_params_est[best_index]
         best_parameters_all = candidate_params_all[best_index]
 
@@ -938,7 +987,6 @@ 

Source code for WORC.classification.SearchCV

[docs]    def create_ensemble(self, X_train, Y_train, verbose=None, initialize=True,
                         scoring=None, method=50):
-        # NOTE: Function is still WIP, do not actually use this.
         '''
 
         Create an (optimal) ensemble of a combination of hyperparameter settings
@@ -979,7 +1027,7 @@ 

Source code for WORC.classification.SearchCV

elif scoring == 'sar':
                 perf = sar_score(Y_valid_truth, Y_valid_score)
             else:
-                raise KeyError('[PREDICT Warning] No valid score method given in ensembling: ' + str(scoring))
+                raise KeyError('[WORC Warning] No valid score method given in ensembling: ' + str(scoring))
 
             return perf
 
@@ -1005,7 +1053,11 @@ 

Source code for WORC.classification.SearchCV

# Simply take the top50 best hyperparameters
             if verbose:
                 print(f'Creating ensemble using top {str(method)} individual classifiers.')
-            ensemble = range(0, method)
+            if method == 1:
+                # Next functions expect list
+                ensemble = [0]
+            else:
+                ensemble = range(0, method)
 
         elif method == 'FitNumber':
             # Use optimum number of models
@@ -1331,7 +1383,7 @@ 

Source code for WORC.classification.SearchCV

print(f"Single estimator best {scoring}: {single_estimator_performance}.")
             print(f'Ensemble consists of {len(ensemble)} estimators {ensemble}.')
         else:
-            print('[PREDICT WARNING] No valid ensemble method given: {}. Not ensembling').format(str(method))
+            print(f'[WORC WARNING] No valid ensemble method given: {method}. Not ensembling')
             return self
 
         # Create the ensemble --------------------------------------------------
@@ -1358,9 +1410,8 @@ 

Source code for WORC.classification.SearchCV

estimators.append(base_estimator)
 
         self.ensemble = Ensemble(estimators)
-
-        print("\n")
-        return self
+ self.best_estimator_ = self.ensemble + print("\n")
[docs]class BaseSearchCVfastr(BaseSearchCV): @@ -1409,8 +1460,8 @@

Source code for WORC.classification.SearchCV

message = 'One or more of the values in your parameter sampler ' +\
                       'is either not iterable, or the distribution cannot ' +\
                       'generate valid samples. Please check your  ' +\
-                      (' parameters. At least {} gives an error.').format(k)
-            raise PREDICTexceptions.PREDICTValueError(message)
+                      f' parameters. At least {k} gives an error.'
+            raise WORCexceptions.WORCValueError(message)
 
         # Split the parameters files in equal parts
         keys = list(parameters_temp.keys())
@@ -1421,7 +1472,7 @@ 

Source code for WORC.classification.SearchCV

for number in k:
                 temp_dict[number] = parameters_temp[number]
 
-            fname = ('settings_{}.json').format(str(num))
+            fname = f'settings_{num}.json'
             sourcename = os.path.join(tempfolder, 'parameters', fname)
             if not os.path.exists(os.path.dirname(sourcename)):
                 os.makedirs(os.path.dirname(sourcename))
@@ -1429,10 +1480,7 @@ 

Source code for WORC.classification.SearchCV

json.dump(temp_dict, fp, indent=4)
 
             parameter_files[str(num)] =\
-                ('vfs://tmp/{}/{}/{}/{}').format('GS',
-                                                 name,
-                                                 'parameters',
-                                                 fname)
+                f'vfs://tmp/GS/{name}/parameters/{fname}'
 
         # Create test-train splits
         traintest_files = dict()
@@ -1445,16 +1493,13 @@ 

Source code for WORC.classification.SearchCV

index=source_labels,
                                     name='Train-test data')
 
-            fname = ('traintest_{}.hdf5').format(str(num))
+            fname = f'traintest_{num}.hdf5'
             sourcename = os.path.join(tempfolder, 'traintest', fname)
             if not os.path.exists(os.path.dirname(sourcename)):
                 os.makedirs(os.path.dirname(sourcename))
-            traintest_files[str(num)] = ('vfs://tmp/{}/{}/{}/{}').format('GS',
-                                                                         name,
-                                                                         'traintest',
-                                                                         fname)
+            traintest_files[str(num)] = f'vfs://tmp/GS/{name}/traintest/{fname}'
 
-            sourcelabel = ("Source Data Iteration {}").format(str(num))
+            sourcelabel = f"Source Data Iteration {num}"
             source_data.to_hdf(sourcename, sourcelabel)
 
             num += 1
@@ -1467,7 +1512,7 @@ 

Source code for WORC.classification.SearchCV

'error_score']
 
         estimator_data = pd.Series([X, y, self.scoring,
-                                    self.verbose,
+                                    False,
                                     self.fit_params, self.return_train_score,
                                     True, True, True,
                                     self.error_score],
@@ -1477,10 +1522,10 @@ 

Source code for WORC.classification.SearchCV

estimatorname = os.path.join(tempfolder, fname)
         estimator_data.to_hdf(estimatorname, 'Estimator Data')
 
-        estimatordata = ("vfs://tmp/{}/{}/{}").format('GS', name, fname)
+        estimatordata = f"vfs://tmp/GS/{name}/{fname}"
 
         # Create the fastr network
-        network = fastr.create_network('PREDICT_GridSearch_' + name)
+        network = fastr.create_network('WORC_GridSearch_' + name)
         estimator_data = network.create_source('HDF5', id='estimator_source')
         traintest_data = network.create_source('HDF5', id='traintest')
         parameter_data = network.create_source('JsonFile', id='parameters')
@@ -1499,7 +1544,7 @@ 

Source code for WORC.classification.SearchCV

source_data = {'estimator_source': estimatordata,
                        'traintest': traintest_files,
                        'parameters': parameter_files}
-        sink_data = {'output': ("vfs://tmp/{}/{}/output_{{sample_id}}_{{cardinality}}{{ext}}").format('GS', name)}
+        sink_data = {'output': f"vfs://tmp/GS/{name}/output_{{sample_id}}_{{cardinality}}{{ext}}"}
 
         network.execute(source_data, sink_data,
                         tmpdir=os.path.join(tempfolder, 'tmp'),
@@ -1526,11 +1571,11 @@ 

Source code for WORC.classification.SearchCV

except ValueError as e:
             print(e)
             message = ('Fitting classifiers has failed. The temporary ' +
-                       'results where not deleted and can be found in {}. ' +
+                       f'results where not deleted and can be found in {tempfolder}. ' +
                        'Probably your fitting and scoring failed: check out ' +
                        'the tmp/fitandscore folder within the tempfolder for ' +
-                       'the fastr job temporary results.').format(tempfolder)
-            raise PREDICTexceptions.PREDICTValueError(message)
+                       'the fastr job temporary results.')
+            raise WORCexceptions.WORCValueError(message)
 
         # Remove the temporary folder used
         shutil.rmtree(tempfolder)
@@ -1761,13 +1806,15 @@ 

Source code for WORC.classification.SearchCV

fit_params=None, n_jobs=1, iid=True, refit=True, cv=None,
                  verbose=0, pre_dispatch='2*n_jobs', random_state=None,
                  error_score='raise', return_train_score=True,
-                 n_jobspercore=100, fastr_plugin=None):
+                 n_jobspercore=100, fastr_plugin=None, maxlen=100,
+                 ranking_score='test_score'):
         super(RandomizedSearchCVfastr, self).__init__(
              param_distributions=param_distributions, scoring=scoring, fit_params=fit_params,
              n_iter=n_iter, random_state=random_state, n_jobs=n_jobs, iid=iid, refit=refit, cv=cv, verbose=verbose,
              pre_dispatch=pre_dispatch, error_score=error_score,
              return_train_score=return_train_score,
-             n_jobspercore=n_jobspercore, fastr_plugin=None)
+ n_jobspercore=n_jobspercore, fastr_plugin=fastr_plugin, + maxlen=maxlen, ranking_score=ranking_score)
[docs] def fit(self, X, y=None, groups=None): """Run fit on the estimator with randomly drawn parameters. @@ -1809,9 +1856,9 @@

Source code for WORC.classification.SearchCV

n_splits = cv.get_n_splits(X, y, groups)
         if self.verbose > 0 and isinstance(parameter_iterable, Sized):
             n_candidates = len(parameter_iterable)
-            print("Fitting {0} folds for each of {1} candidates, totalling"
-                  " {2} fits".format(n_splits, n_candidates,
-                                     n_candidates * n_splits))
+            print(f"Fitting {n_splits} folds for each of {n_candidates}" +\
+                  " candidates, totalling" +\
+                  " {n_candidates * n_splits} fits")
 
         pre_dispatch = self.pre_dispatch
         cv_iter = list(cv.split(X, y, groups))
@@ -1826,7 +1873,7 @@ 

Source code for WORC.classification.SearchCV

return_n_test_samples=True,
                                  return_times=True, return_parameters=True,
                                  error_score=self.error_score,
-                                 verbose=self.verbose,
+                                 verbose=False,
                                  return_all=False)
           for parameters in parameter_iterable
           for train, test in cv_iter)
@@ -2332,14 +2379,15 @@ 

Source code for WORC.classification.SearchCV

fit_params=None, n_jobs=1, iid=True, refit=True, cv=None,
                  verbose=0, pre_dispatch='2*n_jobs', random_state=None,
                  error_score='raise', return_train_score=True,
-                 n_jobspercore=100):
+                 n_jobspercore=100, maxlen=100, ranking_score='test_score'):
         super(RandomizedSearchCVJoblib, self).__init__(
              param_distributions=param_distributions,
              n_iter=n_iter, scoring=scoring, fit_params=fit_params,
              n_jobs=n_jobs, iid=iid, refit=refit, cv=cv, verbose=verbose,
              pre_dispatch=pre_dispatch, error_score=error_score,
              return_train_score=return_train_score,
-             n_jobspercore=n_jobspercore, random_state=random_state)
+ n_jobspercore=n_jobspercore, random_state=random_state, + maxlen=maxlen, ranking_score=ranking_score)
[docs] def fit(self, X, y=None, groups=None): """Run fit on the estimator with randomly drawn parameters. diff --git a/WORC/doc/_build/html/_modules/WORC/classification/construct_classifier.html b/WORC/doc/_build/html/_modules/WORC/classification/construct_classifier.html index dc787260..5fdb8b0c 100644 --- a/WORC/doc/_build/html/_modules/WORC/classification/construct_classifier.html +++ b/WORC/doc/_build/html/_modules/WORC/classification/construct_classifier.html @@ -8,7 +8,7 @@ - WORC.classification.construct_classifier — WORC 3.0.0 documentation + WORC.classification.construct_classifier — WORC 3.1.0 documentation @@ -59,7 +59,7 @@
- 3.0.0 + 3.1.0
diff --git a/WORC/doc/_build/html/_modules/WORC/classification/createfixedsplits.html b/WORC/doc/_build/html/_modules/WORC/classification/createfixedsplits.html new file mode 100644 index 00000000..5870af62 --- /dev/null +++ b/WORC/doc/_build/html/_modules/WORC/classification/createfixedsplits.html @@ -0,0 +1,327 @@ + + + + + + + + + + + WORC.classification.createfixedsplits — WORC 3.1.0 documentation + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+ + + +
+ + + + + +
+ +
+ + + + + + + + + + + + + + + + + +
+ +
    + +
  • Docs »
  • + +
  • Module code »
  • + +
  • WORC.classification.createfixedsplits
  • + + +
  • + +
  • + +
+ + +
+
+
+
+ +

Source code for WORC.classification.createfixedsplits

+#!/usr/bin/env python
+
+# Copyright 2016-2019 Biomedical Imaging Group Rotterdam, Departments of
+# Medical Informatics and Radiology, Erasmus MC, Rotterdam, The Netherlands
+#
+# 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 numpy as np
+from sklearn.model_selection import train_test_split
+import WORC.addexceptions as ae
+from WORC.processing.label_processing import load_labels
+import pandas as pd
+
+
+
[docs]def createfixedsplits(label_file=None, label_type=None, patient_IDs=None, + test_size=0.2, N_iterations=1, regression=False, + stratify=None, modus='singlelabel', output=None): + ''' + Create fixed splits for a cross validation. + ''' + # Check whether input is valid + if patient_IDs is None: + if label_file is not None and label_type is not None: + # Read the label file + label_data = load_labels(label_file, label_type) + patient_IDs = label_data['patient_IDs'] + + # Create the stratification object + if modus == 'singlelabel': + stratify = label_data['label'] + elif modus == 'multilabel': + # Create a stratification object from the labels + # Label = 0 means no label equals one + # Other label numbers refer to the label name that is 1 + stratify = list() + labels = label_data['label'] + for pnum in range(0, len(labels[0])): + plabel = 0 + for lnum, slabel in enumerate(labels): + if slabel[pnum] == 1: + plabel = lnum + 1 + stratify.append(plabel) + + else: + raise ae.WORCKeyError('{} is not a valid modus!').format(modus) + else: + raise ae.WORCIOError('Either a label file and label type or patient_IDs need to be provided!') + + pd_dict = dict() + for i in range(N_iterations): + print(f'Splitting iteration {i + 1} / {N_iterations}') + # Create a random seed for the splitting + random_seed = np.random.randint(5000) + + # Define stratification + unique_patient_IDs, unique_indices =\ + np.unique(np.asarray(patient_IDs), return_index=True) + if regression: + unique_stratify = None + else: + unique_stratify = [stratify[i] for i in unique_indices] + + # Split, throw error when dataset is too small for split ratio's + try: + unique_PID_train, indices_PID_test\ + = train_test_split(unique_patient_IDs, + test_size=test_size, + random_state=random_seed, + stratify=unique_stratify) + except ValueError as e: + e = str(e) + ' Increase the size of your test set.' + raise ae.WORCValueError(e) + + # Check for all IDs if they are in test or training + indices_train = list() + indices_test = list() + patient_ID_train = list() + patient_ID_test = list() + for num, pid in enumerate(patient_IDs): + if pid in unique_PID_train: + indices_train.append(num) + + # Make sure we get a unique ID + if pid in patient_ID_train: + n = 1 + while str(pid + '_' + str(n)) in patient_ID_train: + n += 1 + pid = str(pid + '_' + str(n)) + patient_ID_train.append(pid) + else: + indices_test.append(num) + + # Make sure we get a unique ID + if pid in patient_ID_test: + n = 1 + while str(pid + '_' + str(n)) in patient_ID_test: + n += 1 + pid = str(pid + '_' + str(n)) + patient_ID_test.append(pid) + + # Add to train object + pd_dict[str(i) + '_train'] = patient_ID_train + + # Test object has to be same length as training object + extras = [""]*(len(patient_ID_train) - len(patient_ID_test)) + patient_ID_test.extend(extras) + pd_dict[str(i) + '_test'] = patient_ID_test + + # Convert into pandas dataframe for easy use and conversion + df = pd.DataFrame(pd_dict) + + # Write output if required + if output is not None: + print("Writing Output.") + df.to_csv(output) + + return df
+
+ +
+ +
+
+ + +
+ +
+

+ © Copyright 2016 -- 2019, Biomedical Imaging Group Rotterdam, Departments of Medical Informatics and Radiology, Erasmus MC, Rotterdam, The Netherlands + +

+
+ Built with Sphinx using a theme provided by Read the Docs. + +
+ +
+
+ +
+ +
+ + + + + + + + + + + + \ No newline at end of file diff --git a/WORC/doc/_build/html/_modules/WORC/classification/crossval.html b/WORC/doc/_build/html/_modules/WORC/classification/crossval.html index d0efbfd2..395379eb 100644 --- a/WORC/doc/_build/html/_modules/WORC/classification/crossval.html +++ b/WORC/doc/_build/html/_modules/WORC/classification/crossval.html @@ -8,7 +8,7 @@ - WORC.classification.crossval — WORC 3.0.0 documentation + WORC.classification.crossval — WORC 3.1.0 documentation @@ -59,7 +59,7 @@
- 3.0.0 + 3.1.0
@@ -178,9 +178,9 @@

Source code for WORC.classification.crossval

import logging
 import os
 from sklearn.model_selection import train_test_split
-import xlrd
 from .parameter_optimization import random_search_parameters
 import WORC.addexceptions as ae
+from WORC.classification.regressors import regressors
 
 
 
[docs]def crossval(config, label_data, image_features, @@ -261,10 +261,6 @@

Source code for WORC.classification.crossval

if tempsave:
         import fastr
 
-
-    # Define all possible regressors
-    regressors = ['SVR', 'RFR', 'SGDR', 'Lasso', 'ElasticNet']
-
     # Process input data
     patient_IDs = label_data['patient_IDs']
     label_value = label_data['label']
@@ -290,10 +286,8 @@ 

Source code for WORC.classification.crossval

feature_labels = image_features[0][1]
 
     # Check if we need to use fixedsplits:
-    if fixedsplits is not None and '.xlsx' in fixedsplits:
-        # fixedsplits = '/home/mstarmans/Settings/RandomSufflingOfData.xlsx'
-        wb = xlrd.open_workbook(fixedsplits)
-        wb = wb.sheet_by_index(1)
+    if fixedsplits is not None and '.csv' in fixedsplits:
+        fixedsplits = pd.read_csv(fixedsplits, header=0)
 
     if modus == 'singlelabel':
         print('Performing Single class classification.')
@@ -409,17 +403,15 @@ 

Source code for WORC.classification.crossval

else:
                 # Use pre defined splits
-                indices = wb.col_values(i)
-                indices = [int(j) for j in indices[1:]]  # First element is "Iteration x"
-                train = indices[0:121]
-                test = indices[121:]
+                train = fixedsplits[str(i) + '_train'].values
+                test = fixedsplits[str(i) + '_test'].values
 
                 # Convert the numbers to the correct indices
                 ind_train = list()
                 for j in train:
                     success = False
                     for num, p in enumerate(patient_IDs):
-                        if str(j).zfill(3) == p[0:3]:
+                        if j == p:
                             ind_train.append(num)
                             success = True
                     if not success:
@@ -429,19 +421,27 @@ 

Source code for WORC.classification.crossval

for j in test:
                     success = False
                     for num, p in enumerate(patient_IDs):
-                        if str(j).zfill(3) == p[0:3]:
+                        if j == p:
                             ind_test.append(num)
                             success = True
                     if not success:
                         raise ae.WORCIOError("Patient " + str(j).zfill(3) + " is not included!")
 
-                X_train = np.asarray(image_features)[ind_train].tolist()
-                Y_train = np.asarray(i_class_temp)[ind_train].tolist()
+                X_train = [image_features[i] for i in ind_train]
+                X_test = [image_features[i] for i in ind_test]
+
                 patient_ID_train = patient_IDs[ind_train]
-                X_test = np.asarray(image_features)[ind_test].tolist()
-                Y_test = np.asarray(i_class_temp)[ind_test].tolist()
                 patient_ID_test = patient_IDs[ind_test]
 
+                if modus == 'singlelabel':
+                    Y_train = i_class_temp[ind_train]
+                    Y_test = i_class_temp[ind_test]
+                elif modus == 'multilabel':
+                    Y_train = i_class_temp[ind_train, :]
+                    Y_test = i_class_temp[ind_test, :]
+                else:
+                    raise ae.WORCKeyError('{} is not a valid modus!').format(modus)
+
             # Find best hyperparameters and construct classifier
             config['HyperOptimization']['use_fastr'] = use_fastr
             config['HyperOptimization']['fastr_plugin'] = fastr_plugin
@@ -453,8 +453,7 @@ 

Source code for WORC.classification.crossval

**config['HyperOptimization'])
 
             # Create an ensemble if required
-            if ensemble['Use']:
-                trained_classifier.create_ensemble(X_train, Y_train)
+            trained_classifier.create_ensemble(X_train, Y_train, method=ensemble['Use'])
 
             # We only want to save the feature values and one label array
             X_train = [x[0] for x in X_train]
@@ -469,12 +468,12 @@ 

Source code for WORC.classification.crossval

if tempsave:
                 panda_labels = ['trained_classifier', 'X_train', 'X_test', 'Y_train', 'Y_test',
                                 'config', 'patient_ID_train', 'patient_ID_test',
-                                'random_seed']
+                                'random_seed', 'feature_labels']
 
                 panda_data_temp =\
                     pd.Series([trained_classifier, X_train, X_test, Y_train,
                                Y_test, config, patient_ID_train,
-                               patient_ID_test, random_seed],
+                               patient_ID_test, random_seed, feature_labels],
                               index=panda_labels,
                               name='Constructed crossvalidation')
 
diff --git a/WORC/doc/_build/html/_modules/WORC/classification/estimators.html b/WORC/doc/_build/html/_modules/WORC/classification/estimators.html
index 61bd77aa..2f524355 100644
--- a/WORC/doc/_build/html/_modules/WORC/classification/estimators.html
+++ b/WORC/doc/_build/html/_modules/WORC/classification/estimators.html
@@ -8,7 +8,7 @@
   
   
   
-  WORC.classification.estimators — WORC 3.0.0 documentation
+  WORC.classification.estimators — WORC 3.1.0 documentation
   
 
   
@@ -59,7 +59,7 @@
             
             
               
- 3.0.0 + 3.1.0
@@ -177,7 +177,7 @@

Source code for WORC.classification.estimators

from sklearn.base import BaseEstimator, ClassifierMixin from sklearn.utils.validation import check_is_fitted from sklearn.utils.multiclass import unique_labels -import WORC.classification.RankedSVM as RSVM +from WORC.classification.RankedSVM import RankSVM_train, RankSVM_test

[docs]class RankedSVM(BaseEstimator, ClassifierMixin): @@ -235,7 +235,7 @@

Source code for WORC.classification.estimators

self.num_class = y.shape[0] Weights, Bias, SVs =\ - RSVM.RankSVM_train(train_data=X, + RankSVM_train(train_data=X, train_target=y, cost=self.cost, lambda_tol=self.lambda_tol, @@ -269,14 +269,14 @@

Source code for WORC.classification.estimators

check_is_fitted(self, ['X_', 'y_']) _, Predicted_Labels =\ - RSVM.RankSVM_test(test_data=X, - num_class=self.num_class, - Weights=self.Weights, - Bias=self.Bias, - SVs=self.SVs, - svm=self.svm, gamma=self.gamma, - coefficient=self.coefficient, - degree=self.degree) + RankSVM_test(test_data=X, + num_class=self.num_class, + Weights=self.Weights, + Bias=self.Bias, + SVs=self.SVs, + svm=self.svm, gamma=self.gamma, + coefficient=self.coefficient, + degree=self.degree) return Predicted_Labels

@@ -298,13 +298,13 @@

Source code for WORC.classification.estimators

check_is_fitted(self, ['X_', 'y_']) Probs, _ =\ - RSVM.RankSVM_test(test_data=X, - num_class=self.num_class, - Weights=self.Weights, - Bias=self.Bias, - svm=self.svm, gamma=self.gamma, - coefficient=self.coefficient, - degree=self.degree) + RankSVM_test(test_data=X, + num_class=self.num_class, + Weights=self.Weights, + Bias=self.Bias, + svm=self.svm, gamma=self.gamma, + coefficient=self.coefficient, + degree=self.degree) return Probs

diff --git a/WORC/doc/_build/html/_modules/WORC/classification/fitandscore.html b/WORC/doc/_build/html/_modules/WORC/classification/fitandscore.html index d1e42047..77b5943c 100644 --- a/WORC/doc/_build/html/_modules/WORC/classification/fitandscore.html +++ b/WORC/doc/_build/html/_modules/WORC/classification/fitandscore.html @@ -8,7 +8,7 @@ - WORC.classification.fitandscore — WORC 3.0.0 documentation + WORC.classification.fitandscore — WORC 3.1.0 documentation @@ -59,7 +59,7 @@
- 3.0.0 + 3.1.0
@@ -182,6 +182,7 @@

Source code for WORC.classification.fitandscore

< import scipy from sklearn.decomposition import PCA from sklearn.multiclass import OneVsRestClassifier +from sklearn.ensemble import RandomForestClassifier from imblearn.over_sampling import SMOTE, RandomOverSampler from sklearn.utils import check_random_state import random @@ -195,6 +196,10 @@

Source code for WORC.classification.fitandscore

< from WORC.featureprocessing.StatisticalTestThreshold import StatisticalTestThreshold from WORC.featureprocessing.SelectGroups import SelectGroups +# Specific imports for error management +from sklearn.discriminant_analysis import LinearDiscriminantAnalysis as LDA +from numpy.linalg import LinAlgError +
[docs]def fit_and_score(X, y, scoring, train, test, para, @@ -336,7 +341,18 @@

Source code for WORC.classification.fitandscore

< the fitted object. ''' + # Set some defaults for if a part fails and we return a dummy + test_sample_counts = len(test) + fit_time = np.inf + score_time = np.inf + train_score = np.nan + test_score = np.nan + # We copy the parameter object so we can alter it and keep the original + if verbose: + print("\n") + print('#######################################') + print('Starting fit and score of new workflow.') para_estimator = para.copy() estimator = cc.construct_classifier(para_estimator) if scoring != 'average_precision_weighted': @@ -350,14 +366,36 @@

Source code for WORC.classification.fitandscore

< feature_values = np.asarray([x[0] for x in X]) feature_labels = np.asarray([x[1] for x in X]) + # ------------------------------------------------------------------------ + # Feature scaling + if 'FeatureScaling' in para_estimator: + if verbose: + print("Fitting scaler and transforming features.") + + if para_estimator['FeatureScaling'] == 'z_score': + scaler = StandardScaler().fit(feature_values) + elif para_estimator['FeatureScaling'] == 'minmax': + scaler = MinMaxScaler().fit(feature_values) + else: + scaler = None + + if scaler is not None: + feature_values = scaler.transform(feature_values) + del para_estimator['FeatureScaling'] + else: + scaler = None + + # Delete the object if we do not need to return it + if not return_all: + del scaler + # ------------------------------------------------------------------------ # Feature imputation if 'Imputation' in para_estimator.keys(): if para_estimator['Imputation'] == 'True': imp_type = para_estimator['ImputationMethod'] if verbose: - message = ('Imputing NaN with {}.').format(imp_type) - print(message) + print(f'Imputing NaN with {imp_type}.') imp_nn = para_estimator['ImputationNeighbours'] imputer = Imputer(missing_values=np.nan, strategy=imp_type, @@ -378,6 +416,9 @@

Source code for WORC.classification.fitandscore

< if not return_all: del imputer + # Remove any NaN feature values if these are still left after imputation + feature_values = replacenan(feature_values, verbose=verbose, feature_labels=feature_labels[0]) + # ------------------------------------------------------------------------ # Use SMOTE oversampling if 'SampleProcessing_SMOTE' in para_estimator.keys(): @@ -406,12 +447,8 @@

Source code for WORC.classification.fitandscore

< pos = int(np.sum(y)) neg = int(len(y) - pos) if verbose: - message = ("Sampling with SMOTE from {} ({} pos, {} neg) to {} ({} pos, {} neg) patients.").format(str(len_in), - str(pos_initial), - str(neg_initial), - str(len(y)), - str(pos), - str(neg)) + message = f"Sampling with SMOTE from {len_in} ({pos_initial} pos," +\ + f" {neg_initial} neg) to {len(y)} ({pos} pos, {neg} neg) patients." print(message) else: sm = None @@ -543,7 +580,9 @@

Source code for WORC.classification.fitandscore

< # Delete the non-used fields para_estimator = delete_nonestimator_parameters(para_estimator) - ret = [0, 0, 0, 0, 0, para_estimator, para] + ret = [train_score, test_score, test_sample_counts, + fit_time, score_time, para_estimator, para] + if return_all: return ret, GroupSel, VarSel, SelectModel, feature_labels[0], scaler, imputer, pca, StatisticalSel, ReliefSel, sm, ros else: @@ -596,43 +635,14 @@

Source code for WORC.classification.fitandscore

< SelectModel = None pca = None StatisticalSel = None - ret = [0, 0, 0, 0, 0, para_estimator, para] + ret = [train_score, test_score, test_sample_counts, + fit_time, score_time, para_estimator, para] + if return_all: return ret, GroupSel, VarSel, SelectModel, feature_labels[0], scaler, imputer, pca, StatisticalSel, ReliefSel, sm, ros else: return ret - # -------------------------------------------------------------------- - # Feature selection based on a statistical test - if 'StatisticalTestUse' in para_estimator.keys(): - if para_estimator['StatisticalTestUse'] == 'True': - metric = para_estimator['StatisticalTestMetric'] - threshold = para_estimator['StatisticalTestThreshold'] - if verbose: - print("Selecting features based on statistical test. Method {}, threshold {}.").format(metric, str(round(threshold, 2))) - if verbose: - print("Original Length: " + str(len(feature_values[0]))) - - StatisticalSel = StatisticalTestThreshold(metric=metric, - threshold=threshold) - - StatisticalSel.fit(feature_values, y) - feature_values = StatisticalSel.transform(feature_values) - feature_labels = StatisticalSel.transform(feature_labels) - if verbose: - print("New Length: " + str(len(feature_values[0]))) - else: - StatisticalSel = None - del para_estimator['StatisticalTestUse'] - del para_estimator['StatisticalTestMetric'] - del para_estimator['StatisticalTestThreshold'] - else: - StatisticalSel = None - - # Delete the object if we do not need to return it - if not return_all: - del StatisticalSel - # Check whether there are any features left if len(feature_values[0]) == 0: # TODO: Make a specific WORC exception for this warning. @@ -646,35 +656,14 @@

Source code for WORC.classification.fitandscore

< scaler = None SelectModel = None pca = None - ret = [0, 0, 0, 0, 0, para_estimator, para] + ret = [train_score, test_score, test_sample_counts, + fit_time, score_time, para_estimator, para] + if return_all: return ret, GroupSel, VarSel, SelectModel, feature_labels[0], scaler, imputer, pca, StatisticalSel, ReliefSel, sm, ros else: return ret - # ------------------------------------------------------------------------ - # Feature scaling - if 'FeatureScaling' in para_estimator: - if verbose: - print("Fitting scaler and transforming features.") - - if para_estimator['FeatureScaling'] == 'z_score': - scaler = StandardScaler().fit(feature_values) - elif para_estimator['FeatureScaling'] == 'minmax': - scaler = MinMaxScaler().fit(feature_values) - else: - scaler = None - - if scaler is not None: - feature_values = scaler.transform(feature_values) - del para_estimator['FeatureScaling'] - else: - scaler = None - - # Delete the object if we do not need to return it - if not return_all: - del scaler - # -------------------------------------------------------------------- # Relief feature selection, possibly multi classself. # Needs to be done after scaling! @@ -775,9 +764,14 @@

Source code for WORC.classification.fitandscore

< else: # Assume a fixed number of components n_components = int(para_estimator['PCAType']) - pca = PCA(n_components=n_components) - pca.fit(feature_values) - feature_values = pca.transform(feature_values) + + if n_components >= len(feature_values[0]): + print(f"[WORC WARNING] PCA n_components ({n_components})> n_features ({len(feature_values[0])}): skipping PCA.") + pca = None + else: + pca = PCA(n_components=n_components) + pca.fit(feature_values) + feature_values = pca.transform(feature_values) if verbose: print("New Length: " + str(len(feature_values[0]))) @@ -792,6 +786,37 @@

Source code for WORC.classification.fitandscore

< del para_estimator['UsePCA'] del para_estimator['PCAType'] + # -------------------------------------------------------------------- + # Feature selection based on a statistical test + if 'StatisticalTestUse' in para_estimator.keys(): + if para_estimator['StatisticalTestUse'] == 'True': + metric = para_estimator['StatisticalTestMetric'] + threshold = para_estimator['StatisticalTestThreshold'] + if verbose: + print(f"Selecting features based on statistical test. Method {metric}, threshold {round(threshold, 2)}.") + if verbose: + print("Original Length: " + str(len(feature_values[0]))) + + StatisticalSel = StatisticalTestThreshold(metric=metric, + threshold=threshold) + + StatisticalSel.fit(feature_values, y) + feature_values = StatisticalSel.transform(feature_values) + feature_labels = StatisticalSel.transform(feature_labels) + if verbose: + print("New Length: " + str(len(feature_values[0]))) + else: + StatisticalSel = None + del para_estimator['StatisticalTestUse'] + del para_estimator['StatisticalTestMetric'] + del para_estimator['StatisticalTestThreshold'] + else: + StatisticalSel = None + + # Delete the object if we do not need to return it + if not return_all: + del StatisticalSel + # ---------------------------------------------------------------- # Fitting and scoring # Only when using fastr this is an entry @@ -811,21 +836,36 @@

Source code for WORC.classification.fitandscore

< except IndexError: labellength = 1 - if labellength > 1 and type(estimator) != RankedSVM: - # Multiclass, hence employ a multiclass classifier for e.g. SVM, RF + if labellength > 1 and type(estimator) not in [RankedSVM, + RandomForestClassifier]: + # Multiclass, hence employ a multiclass classifier for e.g. SVM, LR estimator.set_params(**para_estimator) estimator = OneVsRestClassifier(estimator) para_estimator = {} if verbose: print("Fitting ML.") - ret = _fit_and_score(estimator, feature_values, y, - scorer, train, - test, verbose, - para_estimator, fit_params, return_train_score, - return_parameters, - return_n_test_samples, - return_times, error_score) + + try: + ret = _fit_and_score(estimator, feature_values, y, + scorer, train, + test, verbose, + para_estimator, fit_params, return_train_score, + return_parameters, + return_n_test_samples, + return_times, error_score) + except (ValueError, LinAlgError) as e: + if type(estimator) == LDA: + print('[WARNING]: skipping this setting due to LDA Error: ' + e.message) + ret = [train_score, test_score, test_sample_counts, + fit_time, score_time, para_estimator, para] + + if return_all: + return ret, GroupSel, VarSel, SelectModel, feature_labels[0], scaler, imputer, pca, StatisticalSel, ReliefSel, sm, ros + else: + return ret + else: + raise e # Remove 'estimator object', it's the causes of a bug. # Somewhere between scikit-learn 0.18.2 and 0.20.2 @@ -897,9 +937,9 @@

Source code for WORC.classification.fitandscore

< if np.isnan(value): if verbose: if feature_labels is not None: - print("[WORC WARNING] NaN found, patient {}, label {}. Replacing with zero.").format(pnum, feature_labels[fnum]) + print(f"[WORC WARNING] NaN found, patient {pnum}, label {feature_labels[fnum]}. Replacing with zero.") else: - print("[WORC WARNING] NaN found, patient {}, label {}. Replacing with zero.").format(pnum, fnum) + print(f"[WORC WARNING] NaN found, patient {pnum}, label {fnum}. Replacing with zero.") # Note: X is a list of lists, hence we cannot index the element directly image_features_temp[pnum, fnum] = 0 diff --git a/WORC/doc/_build/html/_modules/WORC/classification/metrics.html b/WORC/doc/_build/html/_modules/WORC/classification/metrics.html index 22daa37e..f0b908c0 100644 --- a/WORC/doc/_build/html/_modules/WORC/classification/metrics.html +++ b/WORC/doc/_build/html/_modules/WORC/classification/metrics.html @@ -8,7 +8,7 @@ - WORC.classification.metrics — WORC 3.0.0 documentation + WORC.classification.metrics — WORC 3.1.0 documentation @@ -59,7 +59,7 @@
- 3.0.0 + 3.1.0
@@ -174,7 +174,7 @@

Source code for WORC.classification.metrics

 # limitations under the License.
 
 from __future__ import division
-from sklearn.metrics import accuracy_score
+from sklearn.metrics import accuracy_score, balanced_accuracy_score
 from sklearn.metrics import roc_auc_score
 from sklearn.metrics import confusion_matrix
 from sklearn.metrics import f1_score
@@ -184,6 +184,7 @@ 

Source code for WORC.classification.metrics

 from sklearn.metrics import make_scorer, average_precision_score
 from sklearn.metrics import check_scoring as check_scoring_sklearn
 from scipy.linalg import pinv
+from imblearn.metrics import geometric_mean_score
 
 
 
[docs]def performance_singlelabel(y_truth, y_prediction, y_score, regression=False): @@ -206,38 +207,74 @@

Source code for WORC.classification.metrics

     else:
         # Compute confuction matrics and extract measures
         c_mat = confusion_matrix(y_truth, y_prediction)
-        TN = c_mat[0, 0]
-        FN = c_mat[1, 0]
-        TP = c_mat[1, 1]
-        FP = c_mat[0, 1]
+        if c_mat.shape[0] == 0:
+            print('[WORC Warning] No samples in y_truth and y_prediction.')
+            TN = 0
+            FN = 0
+            TP = 0
+            FP = 0
+        elif c_mat.shape[0] == 1:
+            print('[WORC Warning] Only a single class represented in y_truth and y_prediction.')
+            if 0 in c_mat:
+                TN = c_mat[0, 0]
+                FN = 0
+                TP = 0
+                FP = 0
+            else:
+                TN = 0
+                FN = 0
+                TP = c_mat[0, 0]
+                FP = 0
+        else:
+            TN = c_mat[0, 0]
+            FN = c_mat[1, 0]
+            TP = c_mat[1, 1]
+            FP = c_mat[0, 1]
 
-        # compute confusion metric based statistics
         if FN == 0 and TP == 0:
-            sensitivity = 0
+            if c_mat.shape[0] != 2:
+                sensitivity = np.NaN
+            else:
+                sensitivity = 0
         else:
             sensitivity = float(TP)/(TP+FN)
 
         if FP == 0 and TN == 0:
-            specificity = 0
+            if c_mat.shape[0] != 2:
+                specificity = np.NaN
+            else:
+                specificity = 0
         else:
             specificity = float(TN)/(FP+TN)
 
         if TP == 0 and FP == 0:
-            precision = 0
+            if c_mat.shape[0] != 2:
+                precision = np.NaN
+            else:
+                precision = 0
         else:
             precision = float(TP)/(TP+FP)
 
         if TN == 0 and FN == 0:
-            NPV = 0
+            if c_mat.shape[0] != 2:
+                npv = np.NaN
+            else:
+                npv = 0
         else:
-            NPV = float(TN) / (TN + FN)
+            npv = float(TN) / (TN + FN)
 
         # Additionally, compute accuracy, AUC and f1-score
         accuracy = accuracy_score(y_truth, y_prediction)
-        auc = roc_auc_score(y_truth, y_score)
+        BCA = balanced_accuracy_score(y_truth, y_prediction)
+        try:
+            auc = roc_auc_score(y_truth, y_score)
+        except ValueError as e:
+            print('[WORC Warning] ' + e.message + '. Setting AUC to NaN.')
+            auc = np.NaN
+
         f1_score_out = f1_score(y_truth, y_prediction, average='weighted')
 
-        return accuracy, sensitivity, specificity, precision, f1_score_out, auc
+ return accuracy, BCA, sensitivity, specificity, precision, npv, f1_score_out, auc
[docs]def performance_multilabel(y_truth, y_prediction, y_score=None, beta=1): @@ -249,9 +286,11 @@

Source code for WORC.classification.metrics

 
     y_truth = [0, 0,	0,	0,	0,	0,	2,	2,	1,	1,	2]    ### Groundtruth
     y_prediction = [0, 0,	0,	0,	0,	0,	1,	2,	1,	2,	2]    ### Predicted labels
+    y_score = [[0.3, 0.3, 0.4], [0.2, 0.6, 0.2], ... ] # Normalized score per patient for all labels (three in this example)
 
 
     Calculation of accuracy accorading to formula suggested in CAD Dementia Grand Challege http://caddementia.grand-challenge.org
+    and the TADPOLE challenge https://tadpole.grand-challenge.org/Performance_Metrics/
     Calculation of Multi Class AUC according to classpy: https://bitbucket.org/bigr_erasmusmc/classpy/src/master/classpy/multi_class_auc.py
 
     '''
@@ -272,10 +311,19 @@ 

Source code for WORC.classification.metrics

         FN[:, i] = np.sum(cm[i, :])-cm[i, i]
         FP[:, i] = np.sum(cm[:, i])-cm[i, i]
         TN[:, i] = np.sum(cm[:])-TP[:, i]-FP[:, i]-FN[:, i]
-        n[:, i] = np.sum(cm[:, i])
 
-    # Calculation of accuracy accorading to formula suggested in CAD Dementia Grand Challege http://caddementia.grand-challenge.org
-    Accuracy = (np.sum(TP))/(np.sum(n))
+    n = np.sum(cm)
+
+    # Determine Accuracy
+    Accuracy = (np.sum(TP))/n
+
+    # BCA: Balanced Class Accuracy
+    BCA = list()
+    for i in range(n_class):
+        BCAi = 1/2*(TP[:, i]/(TP[:, i] + FN[:, i]) + TN[:, i]/(TN[:, i] + FP[:, i]))
+        BCA.append(BCAi)
+
+    AverageAccuracy = np.mean(BCA)
 
     # Determine total positives and negatives
     P = TP + FN
@@ -294,6 +342,11 @@ 

Source code for WORC.classification.metrics

     Precision = np.nan_to_num(Precision)
     Precision = np.mean(Precision)
 
+    # Calculation of NPV
+    NPV = TN/(TN+FN)
+    NPV = np.nan_to_num(NPV)
+    NPV = np.mean(NPV)
+
     # Calculation  of F1_Score
     F1_score = ((1+(beta**2))*(Sensitivity*Precision))/((beta**2)*(Precision + Sensitivity))
     F1_score = np.nan_to_num(F1_score)
@@ -305,7 +358,7 @@ 

Source code for WORC.classification.metrics

     else:
         AUC = None
 
-    return Accuracy, Sensitivity, Specificity, Precision, F1_score, AUC
+ return Accuracy, Sensitivity, Specificity, Precision, NPV, F1_score, AUC, AverageAccuracy
[docs]def pairwise_auc(y_truth, y_score, class_i, class_j): @@ -338,8 +391,8 @@

Source code for WORC.classification.metrics

 
[docs]def multi_class_auc(y_truth, y_score): classes = np.unique(y_truth) - if any(t == 0.0 for t in np.sum(y_score, axis=1)): - raise ValueError('No AUC is calculated, output probabilities are missing') + # if any(t == 0.0 for t in np.sum(y_score, axis=1)): + # raise ValueError('No AUC is calculated, output probabilities are missing') pairwise_auc_list = [0.5 * (pairwise_auc(y_truth, y_score, i, j) + pairwise_auc(y_truth, y_score, j, i)) for i in classes for j in classes if i < j] @@ -349,7 +402,7 @@

Source code for WORC.classification.metrics

 
 
 
[docs]def multi_class_auc_score(y_truth, y_score): - return metrics.make_scorer(multi_class_auc, needs_proba=True)
+ return make_scorer(multi_class_auc, needs_proba=True)
[docs]def check_scoring(estimator, scoring=None, allow_none=False): @@ -358,7 +411,9 @@

Source code for WORC.classification.metrics

     scoring metrics.
     '''
     if scoring == 'average_precision_weighted':
-        scorer = make_scorer(average_precision_score, average='weighted')
+        scorer = make_scorer(average_precision_score, average='weighted', needs_proba=True)
+    elif scoring == 'gmean':
+        scorer = make_scorer(geometric_mean_score(), needs_proba=True)
     else:
         scorer = check_scoring_sklearn(estimator, scoring=scoring)
     return scorer
diff --git a/WORC/doc/_build/html/_modules/WORC/classification/parameter_optimization.html b/WORC/doc/_build/html/_modules/WORC/classification/parameter_optimization.html index fabbbdd1..d33b21e7 100644 --- a/WORC/doc/_build/html/_modules/WORC/classification/parameter_optimization.html +++ b/WORC/doc/_build/html/_modules/WORC/classification/parameter_optimization.html @@ -8,7 +8,7 @@ - WORC.classification.parameter_optimization — WORC 3.0.0 documentation + WORC.classification.parameter_optimization — WORC 3.1.0 documentation @@ -59,7 +59,7 @@
- 3.0.0 + 3.1.0
@@ -180,9 +180,10 @@

Source code for WORC.classification.parameter_optimization

[docs]def random_search_parameters(features, labels, N_iter, test_size, - param_grid, scoring_method, + param_grid, scoring_method, n_splits=5, n_jobspercore=200, use_fastr=False, - n_cores=1, fastr_plugin=None): + n_cores=1, fastr_plugin=None, maxlen=100, + ranking_score='test_score'): """ Train a classifier and simultaneously optimizes hyperparameters using a randomized search. @@ -216,10 +217,10 @@

Source code for WORC.classification.parameter_optimization

regressors = ['SVR', 'RFR', 'SGDR', 'Lasso', 'ElasticNet'] if any(clf in regressors for clf in param_grid['classifiers']): # We cannot do a stratified shuffle split with regression - cv = ShuffleSplit(n_splits=5, test_size=test_size, + cv = ShuffleSplit(n_splits=n_splits, test_size=test_size, random_state=random_state) else: - cv = StratifiedShuffleSplit(n_splits=5, test_size=test_size, + cv = StratifiedShuffleSplit(n_splits=n_splits, test_size=test_size, random_state=random_state) if use_fastr: @@ -228,14 +229,20 @@

Source code for WORC.classification.parameter_optimization

scoring=scoring_method, n_jobs=n_cores, n_jobspercore=n_jobspercore, + maxlen=maxlen, verbose=1, cv=cv, - fastr_plugin=fastr_plugin) + fastr_plugin=fastr_plugin, + ranking_score=ranking_score) else: random_search = RandomizedSearchCVJoblib(param_distributions=param_grid, n_iter=N_iter, scoring=scoring_method, n_jobs=n_cores, - verbose=1, cv=cv) + n_jobspercore=n_jobspercore, + maxlen=maxlen, + verbose=1, cv=cv, + fastr_plugin=fastr_plugin, + ranking_score=ranking_score) random_search.fit(features, labels) print("Best found parameters:") for i in random_search.best_params_: diff --git a/WORC/doc/_build/html/_modules/WORC/classification/trainclassifier.html b/WORC/doc/_build/html/_modules/WORC/classification/trainclassifier.html index 126638e9..848b97e1 100644 --- a/WORC/doc/_build/html/_modules/WORC/classification/trainclassifier.html +++ b/WORC/doc/_build/html/_modules/WORC/classification/trainclassifier.html @@ -8,7 +8,7 @@ - WORC.classification.trainclassifier — WORC 3.0.0 documentation + WORC.classification.trainclassifier — WORC 3.1.0 documentation @@ -59,7 +59,7 @@
- 3.0.0 + 3.1.0
@@ -175,16 +175,14 @@

Source code for WORC.classification.trainclassifier

import json import os -import sklearn from WORC.classification import crossval as cv from WORC.classification import construct_classifier as cc from WORC.plotting.plot_SVM import plot_SVM -from WORC.plotting.plot_SVR import plot_single_SVR import WORC.IOparser.file_io as file_io import WORC.IOparser.config_io_classifier as config_io from scipy.stats import uniform -from WORC.classification.AdvancedSampler import discrete_uniform +from WORC.classification.AdvancedSampler import discrete_uniform, log_uniform
[docs]def trainclassifier(feat_train, patientinfo_train, config, @@ -277,6 +275,9 @@

Source code for WORC.classification.trainclassifier

print('[WORC Warning] You provided multiple output json files: only the first one will be used!') output_json = output_json[0] + if type(fixedsplits) is list: + fixedsplits = ''.join(fixedsplits) + # Load variables from the config file config = config_io.load_config(config) label_type = config['Labels']['label_names'] @@ -347,8 +348,8 @@

Source code for WORC.classification.trainclassifier

param_grid['StatisticalTestMetric'] =\ config['Featsel']['StatisticalTestMetric'] param_grid['StatisticalTestThreshold'] =\ - uniform(loc=config['Featsel']['StatisticalTestThreshold'][0], - scale=config['Featsel']['StatisticalTestThreshold'][1]) + log_uniform(loc=config['Featsel']['StatisticalTestThreshold'][0], + scale=config['Featsel']['StatisticalTestThreshold'][1]) param_grid['ReliefUse'] =\ config['Featsel']['ReliefUse'] @@ -406,22 +407,33 @@

Source code for WORC.classification.trainclassifier

# Calculate statistics of performance if feat_test is None: if not isclassifier: - statistics = plot_single_SVR(trained_classifier, label_data_train, - label_type) + statistics = plot_SVM(trained_classifier, label_data_train, + label_type, ensemble=config['Ensemble']['Use'], + bootstrap=config['Bootstrap']['Use'], + bootstrap_N=config['Bootstrap']['N_iterations']) else: statistics = plot_SVM(trained_classifier, label_data_train, - label_type, modus=modus) + label_type, modus=modus, + ensemble=config['Ensemble']['Use'], + bootstrap=config['Bootstrap']['Use'], + bootstrap_N=config['Bootstrap']['N_iterations']) else: if patientinfo_test is not None: if not isclassifier: - statistics = plot_single_SVR(trained_classifier, - label_data_test, - label_type) + statistics = plot_SVM(trained_classifier, + label_data_test, + label_type, + ensemble=config['Ensemble']['Use'], + bootstrap=config['Bootstrap']['Use'], + bootstrap_N=config['Bootstrap']['N_iterations']) else: statistics = plot_SVM(trained_classifier, label_data_test, label_type, - modus=modus) + modus=modus, + ensemble=config['Ensemble']['Use'], + bootstrap=config['Bootstrap']['Use'], + bootstrap_N=config['Bootstrap']['N_iterations']) else: statistics = None @@ -433,7 +445,7 @@

Source code for WORC.classification.trainclassifier

os.makedirs(os.path.dirname(output_json)) with open(output_json, 'w') as fp: - json.dump(savedict, fp, indent=4) + json.dump(savedict, fp, sort_keys=True, indent=4) print("Saved data!")
diff --git a/WORC/doc/_build/html/_modules/WORC/detectors/detectors.html b/WORC/doc/_build/html/_modules/WORC/detectors/detectors.html new file mode 100644 index 00000000..fdaad20c --- /dev/null +++ b/WORC/doc/_build/html/_modules/WORC/detectors/detectors.html @@ -0,0 +1,293 @@ + + + + + + + + + + + WORC.detectors.detectors — WORC 3.1.0 documentation + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+ + + +
+ + + + + +
+ +
+ + + + + + + + + + + + + + + + + +
+ +
    + +
  • Docs »
  • + +
  • Module code »
  • + +
  • WORC.detectors.detectors
  • + + +
  • + +
  • + +
+ + +
+
+
+
+ +

Source code for WORC.detectors.detectors

+import csv
+import string
+from abc import ABC, abstractmethod
+from pathlib import Path
+from os import environ
+import platform
+
+
+
[docs]class AbstractDetector(ABC): + # noinspection PyBroadException +
[docs] def do_detection(self, *args, **kwargs): + try: + result = self._is_detected(*args, **kwargs) + except: + result = False + print(self._generate_detector_message(result)) + return result
+ + def _generate_detector_message(self, detected_Value): + return f"{self.__class__.__name__[0:-8]} detected: {detected_Value}." + + @abstractmethod + def _is_detected(self, *args, **kwargs): + pass
+ + +
[docs]class CsvDetector(AbstractDetector): +
[docs] def __init__(self, csv_file_path): + self._csv_file_path = csv_file_path
+ + def _is_detected(self, *args, **kwargs): + try: + with open(self._csv_file_path, newline='') as csvfile: + start = csvfile.read(4096) + + # isprintable does not allow newlines, printable does not allow umlauts... + if not all([c in string.printable or c.isprintable() for c in start]): + return False + dialect = csv.Sniffer().sniff(start) # this triggers csv.Error if it can't sniff the csv dialect + return True + except csv.Error: + # Could not get a csv dialect -> probably not a csv. + return False
+ + +
[docs]class CartesiusClusterDetector(AbstractDetector): + def _is_detected(self): + if LinuxDetector()._is_detected(): + try: + if 'cartesius' in Path('/etc/hosts').read_text(): + return True + except: + return False + return False
+ + +
[docs]class DebugDetector(AbstractDetector): + def _is_detected(self): + try: + if environ.get('WORCDEBUG') is not None: + return True + else: + return False + except: + return False
+ + +
[docs]class BigrClusterDetector(AbstractDetector): + def _is_detected(self): + if LinuxDetector()._is_detected(): + try: + if 'bigr-cluster' in Path('/etc/hosts').read_text(): + return True + except: + return False + return False
+ + +
[docs]class HostnameDetector(AbstractDetector): + def _is_detected(self): + if platform.node() == self._expected_hostname: + return True + return False + +
[docs] def __init__(self, expected_hostname): + self._expected_hostname = expected_hostname
+ + +
[docs]class LinuxDetector(AbstractDetector): + def _is_detected(self): + if platform.system().lower().strip() == 'linux': + return True + return False
+
+ +
+ +
+
+ + +
+ +
+

+ © Copyright 2016 -- 2019, Biomedical Imaging Group Rotterdam, Departments of Medical Informatics and Radiology, Erasmus MC, Rotterdam, The Netherlands + +

+
+ Built with Sphinx using a theme provided by Read the Docs. + +
+ +
+
+ +
+ +
+ + + + + + + + + + + + \ No newline at end of file diff --git a/WORC/doc/_build/html/_modules/WORC/exampledata/datadownloader.html b/WORC/doc/_build/html/_modules/WORC/exampledata/datadownloader.html new file mode 100644 index 00000000..2a63a6a4 --- /dev/null +++ b/WORC/doc/_build/html/_modules/WORC/exampledata/datadownloader.html @@ -0,0 +1,356 @@ + + + + + + + + + + + WORC.exampledata.datadownloader — WORC 3.1.0 documentation + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+ + + +
+ + + + + +
+ +
+ + + + + + + + + + + + + + + + + +
+ +
    + +
  • Docs »
  • + +
  • Module code »
  • + +
  • WORC.exampledata.datadownloader
  • + + +
  • + +
  • + +
+ + +
+
+
+
+ +

Source code for WORC.exampledata.datadownloader

+import xnat
+import os
+import sys
+import shutil
+from glob import glob
+
+from xnat.exceptions import XNATResponseError
+
+
+
[docs]def download_subject(project, subject, datafolder, session, verbose=False): + # Download all data and keep track of resources + download_counter = 0 + resource_labels = list() + for e in subject.experiments: + resmap = {} + experiment = subject.experiments[e] + + # FIXME: Need a way to smartly check whether we have a matching RT struct and image + # Current solution: We only download the CT sessions, no PET / MRI / Other scans + # Specific for STW Strategy BMIA XNAT projects + + if experiment.session_type is None: # some files in project don't have _CT postfix + print(f"\tSkipping patient {subject.label}, experiment {experiment.label}: type is not CT but {experiment.session_type}.") + continue + + if '_CT' not in experiment.session_type: + print(f"\tSkipping patient {subject.label}, experiment {experiment.label}: type is not CT but {experiment.session_type}.") + continue + + for s in experiment.scans: + scan = experiment.scans[s] + print(("\tDownloading patient {}, experiment {}, scan {}.").format(subject.label, experiment.label, + scan.id)) + for res in scan.resources: + resource_label = scan.resources[res].label + if resource_label == 'NIFTI': + # Create output directory + outdir = datafolder + '/{}'.format(subject.label) + if not os.path.exists(outdir): + os.makedirs(outdir) + + resmap[resource_label] = scan + print(f'resource is {resource_label}') + scan.resources[res].download_dir(outdir) + resource_labels.append(resource_label) + download_counter += 1 + + # Parse resources and throw warnings if they not meet the requirements + subject_name = subject.label + if download_counter == 0: + print(f'[WARNING] Skipping subject {subject_name}: no (suitable) resources found.') + return False + + if 'NIFTI' not in resource_labels: + print(f'[WARNING] Skipping subject {subject_name}: no NIFTI resources found.') + return False + + if resource_labels.count('NIFTI') < 2: + print(f'[WARNING] Skipping subject {subject_name}: only one NIFTI resource found, need two (mask and image).') + return False + elif resource_labels.count('NIFTI') > 2: + count = resource_labels.count('NIFTI') + print(f'[WARNING] Skipping subject {subject_name}: {str(count)} NIFTI resources found, need two (mask and image).') + return False + + # Check what the mask and image folders are + NIFTI_folders = glob(os.path.join(outdir, '*', 'scans', '*', 'resources', 'NIFTI', 'files')) + if 'mask' in glob(os.path.join(NIFTI_folders[0], '*.nii.gz'))[0]: + NIFTI_image_folder = NIFTI_folders[1] + NIFTI_mask_folder = NIFTI_folders[0] + else: + NIFTI_image_folder = NIFTI_folders[0] + NIFTI_mask_folder = NIFTI_folders[1] + + NIFTI_files = glob(os.path.join(NIFTI_image_folder, '*')) + if len(NIFTI_files) == 0: + print(f'[WARNING] Skipping subject {subject_name}: image NIFTI resources is empty.') + shutil.rmtree(outdir) + return False + + NIFTI_files = glob(os.path.join(NIFTI_mask_folder, '*')) + if len(NIFTI_files) == 0: + print(f'[WARNING] Skipping subject {subject_name}: mask NIFTI resources is empty.') + shutil.rmtree(outdir) + return False + + # Patient is included, so cleanup folder structure + os.rename(os.path.join(NIFTI_image_folder, 'image.nii.gz'), + os.path.join(outdir, 'image.nii.gz')) + os.rename(os.path.join(NIFTI_mask_folder, 'mask_GTV-1.nii.gz'), + os.path.join(outdir, 'mask.nii.gz')) + + for folder in glob(os.path.join(outdir, '*', 'scans')): + folder = os.path.dirname(folder) + shutil.rmtree(folder) + + return True
+ + +
[docs]def download_project(project_name, xnat_url, datafolder, nsubjects=10, + verbose=True): + + # Connect to XNAT and retreive project + session = xnat.connect(xnat_url) + project = session.projects[project_name] + + # Create the data folder if it does not exist yet + datafolder = os.path.join(datafolder, project_name) + if not os.path.exists(datafolder): + os.makedirs(datafolder) + + subjects_len = len(project.subjects) + if nsubjects == 'all': + nsubjects = subjects_len + else: + nsubjects = min(nsubjects, subjects_len) + + subjects_counter = 1 + downloaded_subjects_counter = 0 + for s in range(0, subjects_len): + s = project.subjects[s] + print(f'Working on subject {subjects_counter}/{subjects_len}') + subjects_counter += 1 + + success = download_subject(project_name, s, datafolder, session, verbose) + if success: + downloaded_subjects_counter += 1 + + # Stop downloading if we have reached the required number of subjects + if downloaded_subjects_counter == nsubjects: + break + + # Disconnect the session + session.disconnect() + if downloaded_subjects_counter < nsubjects: + raise ValueError(f'Number of subjects downloaded {downloaded_subjects_counter} is smaller than the number required {nsubjects}.') + + print('Done downloading!')
+ + +
[docs]def download_HeadAndNeck(datafolder=None, nsubjects=10): + if datafolder is None: + # Download data to path in which this script is located + Data + cwd = os.getcwd() + datafolder = os.path.join(cwd, 'Data') + if not os.path.exists(datafolder): + os.makedirs(datafolder) + + xnat_url = 'https://xnat.bmia.nl/' + project_name = 'stwstrategyhn1' + download_project(project_name, xnat_url, datafolder, nsubjects=nsubjects, + verbose=True)
+ + +if __name__ == '__main__': + download_HeadAndNeck() +
+ +
+ +
+
+ + +
+ +
+

+ © Copyright 2016 -- 2019, Biomedical Imaging Group Rotterdam, Departments of Medical Informatics and Radiology, Erasmus MC, Rotterdam, The Netherlands + +

+
+ Built with Sphinx using a theme provided by Read the Docs. + +
+ +
+
+ +
+ +
+ + + + + + + + + + + + \ No newline at end of file diff --git a/WORC/doc/_build/html/_modules/WORC/facade/intermediatefacade/configbuilder.html b/WORC/doc/_build/html/_modules/WORC/facade/intermediatefacade/configbuilder.html new file mode 100644 index 00000000..8458f08d --- /dev/null +++ b/WORC/doc/_build/html/_modules/WORC/facade/intermediatefacade/configbuilder.html @@ -0,0 +1,306 @@ + + + + + + + + + + + WORC.facade.intermediatefacade.configbuilder — WORC 3.1.0 documentation + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+ + + +
+ + + + + +
+ +
+ + + + + + + + + + + + + + + + + +
+ +
    + +
  • Docs »
  • + +
  • Module code »
  • + +
  • WORC.facade.intermediatefacade.configbuilder
  • + + +
  • + +
  • + +
+ + +
+
+
+
+ +

Source code for WORC.facade.intermediatefacade.configbuilder

+from WORC.detectors.detectors import BigrClusterDetector, CartesiusClusterDetector
+import configparser
+
+
+
[docs]class ConfigBuilder(): +
[docs] def __init__(self): + # initalize the main config object and the custom overrids + self._config = configparser.ConfigParser() + self._custom_overrides = {} + + # Detect when using a cluster and override relevant config fields + self._cluster_config_overrides()
+ +
[docs] def build_config(self, defaultconfig): + defaultconfig.read_dict({**self._config}) + defaultconfig.read_dict({**self._custom_overrides}) + self._config = defaultconfig + return defaultconfig
+ +
[docs] def custom_config_overrides(self, config): + self._custom_overrides.update(config)
+ + def _cluster_config_overrides(self): + if BigrClusterDetector().do_detection(): + overrides = { + 'General': {'Joblib_ncores': '1', + 'Joblib_backend': 'threading'}, + 'Classification': {'fastr': 'True', + 'fastr_plugin': 'DRMAAExecution'}, + 'HyperOptimization': {'n_jobspercore': '4000'} + } + elif CartesiusClusterDetector().do_detection(): + overrides = { + 'Classification': {'fastr': 'True', + 'fastr_plugin': 'ProcessPoolExecution'}, + 'HyperOptimization': {'n_jobspercore': '4000'} + } + else: + overrides = {} # not a cluster or unsupported + + self._custom_overrides.update(overrides) + return overrides + +
[docs] def estimator_scoring_overrides(self, estimators, scoring_method): + overrides = { + 'Classification': {'classifiers': ', '.join(estimators)}, + 'HyperOptimization': {'scoring_method': scoring_method} + } + self._custom_overrides.update(overrides) + return overrides
+ +
[docs] def coarse_overrides(self): + overrides = { + 'ImageFeatures': { + 'texture_Gabor': 'False', + 'vessel': 'False', + 'log': 'False', + 'phase': 'False' + }, + 'SelectFeatGroup': { + 'texture_Gabor_features': 'False', + 'log_features': 'False', + 'vessel_features': 'False', + 'phase_features': 'False' + }, + 'CrossValidation': {'N_iterations': '3'}, + 'HyperOptimization': {'N_iterations': '1000', + 'n_jobspercore': '500'}, + 'Ensemble': {'Use': '1'}, + 'SampleProcessing': {'SMOTE': 'False'}, + } + self._custom_overrides.update(overrides) + return overrides
+ +
[docs] def full_overrides(self): + overrides = { + 'ImageFeatures': { + 'texture_Gabor': 'True', + 'vessel': 'True', + 'log': 'True', + 'phase': 'True' + }, + 'SelectFeatGroup': { + 'texture_Gabor_features': 'True, False', + 'log_features': 'True, False', + 'vessel_features': 'True, False', + 'phase_features': 'True, False' + }, + 'CrossValidation': {'N_iterations': '100'}, + 'HyperOptimization': {'N_iterations': '100000', + 'n_jobspercore': '4000'}, + 'Ensemble': {'Use': '50'}, + 'SampleProcessing': {'SMOTE': 'True'}, + } + self._custom_overrides.update(overrides) + return overrides
+ +
[docs] def fullprint(self): + ''' + Print the full contents of the config to the console. + ''' + for k, v in self._config.items(): + print(f"{k}:") + for k2, v2 in v.items(): + print(f"\t {k2}: {v2}") + print("\n")
+
+ +
+ +
+
+ + +
+ +
+

+ © Copyright 2016 -- 2019, Biomedical Imaging Group Rotterdam, Departments of Medical Informatics and Radiology, Erasmus MC, Rotterdam, The Netherlands + +

+
+ Built with Sphinx using a theme provided by Read the Docs. + +
+ +
+
+ +
+ +
+ + + + + + + + + + + + \ No newline at end of file diff --git a/WORC/doc/_build/html/_modules/WORC/facade/intermediatefacade/exceptions.html b/WORC/doc/_build/html/_modules/WORC/facade/intermediatefacade/exceptions.html new file mode 100644 index 00000000..1ed317b7 --- /dev/null +++ b/WORC/doc/_build/html/_modules/WORC/facade/intermediatefacade/exceptions.html @@ -0,0 +1,221 @@ + + + + + + + + + + + WORC.facade.intermediatefacade.exceptions — WORC 3.1.0 documentation + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+ + + +
+ + + + + +
+ +
+ + + + + + + + + + + + + + + + + +
+ +
    + +
  • Docs »
  • + +
  • Module code »
  • + +
  • WORC.facade.intermediatefacade.exceptions
  • + + +
  • + +
  • + +
+ + +
+
+
+
+ +

Source code for WORC.facade.intermediatefacade.exceptions

+
[docs]class InvalidOrderException(Exception): +
[docs] def __init__(self, function, execute_first): + super(InvalidOrderException, self).__init__(f'Invalid order for function {path} call {execute_first} before calling this function')
+ +
[docs]class InvalidCsvFileException(Exception): +
[docs] def __init__(self, path): + super(InvalidCsvFileException, self).__init__(f'Invalid or unreadable csv file: {path}')
+ +
[docs]class PathNotFoundException(Exception): +
[docs] def __init__(self, path): + super(PathNotFoundException, self).__init__(f'Path not found: {path}')
+ + +
[docs]class NoImagesFoundException(Exception): +
[docs] def __init__(self, path): + super(NoImagesFoundException, self).__init__(f'No images found in directory {path}')
+ + +
[docs]class NoSegmentationsFoundException(Exception): +
[docs] def __init__(self, path): + super(NoSegmentationsFoundException, self).__init__(f'No segmentations found in directory {path}')
+
+ +
+ +
+
+ + +
+ +
+

+ © Copyright 2016 -- 2019, Biomedical Imaging Group Rotterdam, Departments of Medical Informatics and Radiology, Erasmus MC, Rotterdam, The Netherlands + +

+
+ Built with Sphinx using a theme provided by Read the Docs. + +
+ +
+
+ +
+ +
+ + + + + + + + + + + + \ No newline at end of file diff --git a/WORC/doc/_build/html/_modules/WORC/facade/intermediatefacade/intermediatefacade.html b/WORC/doc/_build/html/_modules/WORC/facade/intermediatefacade/intermediatefacade.html new file mode 100644 index 00000000..6dd92ee9 --- /dev/null +++ b/WORC/doc/_build/html/_modules/WORC/facade/intermediatefacade/intermediatefacade.html @@ -0,0 +1,440 @@ + + + + + + + + + + + WORC.facade.intermediatefacade.intermediatefacade — WORC 3.1.0 documentation + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+ + + +
+ + + + + +
+ +
+ + + + + + + + + + + + + + + + + +
+ +
    + +
  • Docs »
  • + +
  • Module code »
  • + +
  • WORC.facade.intermediatefacade.intermediatefacade
  • + + +
  • + +
  • + +
+ + +
+
+
+
+ +

Source code for WORC.facade.intermediatefacade.intermediatefacade

+from WORC import WORC
+
+from pathlib import Path
+
+from WORC.detectors.detectors import CsvDetector
+from WORC.facade.intermediatefacade.configbuilder import ConfigBuilder
+from .exceptions import PathNotFoundException, NoImagesFoundException, NoSegmentationsFoundException, \
+    InvalidCsvFileException
+
+
+def _for_all_methods(decorator):
+    def decorate(cls):
+        for attr in cls.__dict__:  # there's propably a better way to do this
+            if callable(getattr(cls, attr)):
+                setattr(cls, attr, decorator(getattr(cls, attr)))
+        return cls
+
+    return decorate
+
+
+def _error_buldozer(func):
+    _valid_exceptions = [
+        PathNotFoundException, NoImagesFoundException,
+        NoSegmentationsFoundException, InvalidCsvFileException,
+        TypeError, ValueError, NotImplementedError
+    ]
+
+    unexpected_exception_exception = Exception('A blackhole to another dimenstion has opened. This exception should never be thrown. Double check your code or make an issue on the WORC github so that we can fix this issue.')
+
+    def dec(*args, **kwargs):
+        try:
+            func(*args, **kwargs)
+        except Exception as e:
+            if e.__class__ not in _valid_exceptions:
+                raise unexpected_exception_exception
+            raise e
+    return dec
+
+
+
[docs]@_for_all_methods(_error_buldozer) +class IntermediateFacade(): +
[docs] def __init__(self, name='WORC'): + # Set some config values + self._worc = WORC(name) + + self._images_train = [] + self._images_test = [] + self._segmentations_train = [] + self._segmentations_test = [] + self._semantics_file_train = None + self._semantics_file_test = None + + self._labels_file_train = None + self._labels_file_test = None + self._label_names = [] + + self._method = None + + self._config_builder = ConfigBuilder() + self._add_evaluation = False
+ +
[docs] def images_from_this_directory(self, directory, image_file_name='image.nii.gz', glob='*/', is_training=True): + directory = Path(directory).expanduser() + if not directory.exists(): + raise PathNotFoundException(directory) + + images = list(directory.glob(f'{glob}{image_file_name}')) + + if len(images) == 0: + raise NoImagesFoundException(f'{directory}{glob}{image_file_name}') + + images_per_subject = {image.parent.name: str(image.absolute()) for image in images} + if is_training: + self._images_train.append(images_per_subject) + else: + self._images_test.append(images_per_subject)
+ +
[docs] def segmentations_from_this_directory(self, directory, segmentation_file_name='segmentation.nii.gz', glob='*/', + is_training=True): + directory = Path(directory).expanduser() + if not directory.exists(): + raise PathNotFoundException(directory) + + segmentations = list(directory.glob(f'{glob}{segmentation_file_name}')) + + if len(segmentations) == 0: + raise NoSegmentationsFoundException(str(directory)) + + segmentations_per_subject = {image.parent.name: str(image.absolute()) for image in segmentations} + if is_training: + self._segmentations_train.append(segmentations_per_subject) + else: + self._segmentations_test.append(segmentations_per_subject)
+ +
[docs] def labels_from_this_file(self, file_path, is_training=True): + labels_file = Path(file_path).expanduser() + + if not labels_file.is_file(): + raise PathNotFoundException(file_path) + + if not CsvDetector(labels_file.absolute()): + raise InvalidCsvFileException(labels_file.absolute()) + + # TODO: implement sanity check labels file e.g. is it a labels file and are there labels available + if is_training: + self._labels_file_train = labels_file.absolute() + else: + self._labels_file_test = labels_file.absolute()
+ +
[docs] def semantics_from_this_file(self, file_path, is_training=True): + semantics_file = Path(file_path).expanduser() + + if not semantics_file.is_file(): + raise PathNotFoundException(file_path) + + if not CsvDetector(semantics_file.absolute()): + raise InvalidCsvFileException(semantics_file.absolute()) + + # TODO: implement sanity check semantics file e.g. is it a semantics file and are there semantics available + if is_training: + self._semantics_file_train = semantics_file.absolute() + else: + self._semantics_file_test = semantics_file.absolute()
+ +
[docs] def predict_labels(self, label_names: list): + if not self._labels_file_train: + raise ValueError('No labels file set trough labels_from_this_file') + + if not isinstance(label_names, list): + raise TypeError(f'label_names is of type {type(label_names)} while list is expected') + + for label in label_names: + if len(label.strip()) == 0: + raise ValueError('Invalid label, length = 0') + + # TODO: check if labels is in labels file + + # self._worc.label_names = ', '.join(label_names) + self._label_names = label_names
+ + def _set_and_validate_estimators(self, estimators, scoring_method, method, coarse): + # validate + if method == 'classification': + valid_estimators = ['SVM', 'RF', 'SGD', 'LR', 'GaussianNB', 'ComplementNB', 'LDA', 'QDA', 'RankedSVM'] + elif method == 'regression': + valid_estimators = ['SVR', 'RFR', 'ElasticNet', 'Lasso', 'SGDR'] + else: + valid_estimators = [] + + for estimator in estimators: + if estimator not in valid_estimators: + raise ValueError( + f'Invalid estimator {estimator} for {method}; must be one of {", ".join(valid_estimators)}') + + # TODO: sanity check scoring method per estimator + + # set + self._config_builder.estimator_scoring_overrides(estimators, scoring_method) + + if coarse: + self._config_builder.coarse_overrides() + else: + self._config_builder.full_overrides() + + self._method = method + + def _validate(self): + if not self._images_train: + pass # TODO: throw exception + + if not self._segmentations_train: + pass # TODO: throw exception + + if not self._labels_file_train: + pass # TODO: throw an exception + + if not self._label_names: + pass # TODO: throw exception + + if not self._method: + pass # TODO: throw exception + + if len(self._images_train) == len(self._segmentations_train): + for index, subjects_dict in enumerate(self._images_train): + try: + if subjects_dict.keys() != self._segmentations_train[index].keys(): + raise ValueError('Subjects in images_train and segmentations_train are not the same') + + # TODO: verify subjects in labels files as well + # TODO: peform same checks on images_test and segmentations_test if those are not None + except IndexError: + # this should never be thrown, but i put it here just in case + raise ValueError( + 'A blackhole to another dimenstion has opened. This exception should never be thrown. Double check your code or make an issue on the WORC github so that we can fix this issue.') + +
[docs] def execute(self): + # this function is kind of like the build()-function in a builder, except it peforms execute on the object being built as well + self._validate() # do some final sanity checking before we execute the thing + + self._worc.images_train = self._images_train + self._worc.segmentations_train = self._segmentations_train + self._worc.labels_train = self._labels_file_train + self._worc.semantics_train = self._semantics_file_train + + if self._images_test: + self._worc.images_test = self._images_test + + if self._segmentations_test: + self._worc.segmentations_test = self._segmentations_test + + if self._labels_file_test: + self._worc.labels_test = self._labels_file_test + + self._worc.label_names = ', '.join(self._label_names) + self._config_builder._custom_overrides['Labels'] = dict() + self._config_builder._custom_overrides['Labels']['label_names'] = self._worc.label_names + + self._worc.configs = [self._config_builder.build_config(self._worc.defaultconfig())] + self._worc.build() + if self._add_evaluation: + self._worc.add_evaluation(label_type=self._label_names[self._selected_label]) + + self._worc.set() + self._worc.execute()
+ +
[docs] def binary_classification(self, estimators=['SVM'], scoring_method='f1', coarse=True): + self._set_and_validate_estimators(estimators, scoring_method, 'classification', coarse)
+ +
[docs] def regression(self, estimators=['SVR'], scoring_method='r2', coarse=True): + self._set_and_validate_estimators(estimators, scoring_method, 'regression', coarse)
+ +
[docs] def survival(self, estimators, scoring_method, coarse=True): + raise NotImplementedError()
+ +
[docs] def add_config_overrides(self, config): + self._config_builder.custom_config_overrides(config)
+ +
[docs] def add_evaluation(self, selected_label=0): + self._add_evaluation = True + self._selected_label = 0
+
+ +
+ +
+
+ + +
+ +
+

+ © Copyright 2016 -- 2019, Biomedical Imaging Group Rotterdam, Departments of Medical Informatics and Radiology, Erasmus MC, Rotterdam, The Netherlands + +

+
+ Built with Sphinx using a theme provided by Read the Docs. + +
+ +
+
+ +
+ +
+ + + + + + + + + + + + \ No newline at end of file diff --git a/WORC/doc/_build/html/_modules/WORC/featureprocessing/Imputer.html b/WORC/doc/_build/html/_modules/WORC/featureprocessing/Imputer.html index 4ddce7c4..286fe418 100644 --- a/WORC/doc/_build/html/_modules/WORC/featureprocessing/Imputer.html +++ b/WORC/doc/_build/html/_modules/WORC/featureprocessing/Imputer.html @@ -8,7 +8,7 @@ - WORC.featureprocessing.Imputer — WORC 3.0.0 documentation + WORC.featureprocessing.Imputer — WORC 3.1.0 documentation @@ -59,7 +59,7 @@
- 3.0.0 + 3.1.0
diff --git a/WORC/doc/_build/html/_modules/WORC/featureprocessing/Relief.html b/WORC/doc/_build/html/_modules/WORC/featureprocessing/Relief.html index 1f69734b..e66eaaf0 100644 --- a/WORC/doc/_build/html/_modules/WORC/featureprocessing/Relief.html +++ b/WORC/doc/_build/html/_modules/WORC/featureprocessing/Relief.html @@ -8,7 +8,7 @@ - WORC.featureprocessing.Relief — WORC 3.0.0 documentation + WORC.featureprocessing.Relief — WORC 3.1.0 documentation @@ -59,7 +59,7 @@
- 3.0.0 + 3.1.0
diff --git a/WORC/doc/_build/html/_modules/WORC/featureprocessing/SelectGroups.html b/WORC/doc/_build/html/_modules/WORC/featureprocessing/SelectGroups.html index 5e636265..d2742c30 100644 --- a/WORC/doc/_build/html/_modules/WORC/featureprocessing/SelectGroups.html +++ b/WORC/doc/_build/html/_modules/WORC/featureprocessing/SelectGroups.html @@ -8,7 +8,7 @@ - WORC.featureprocessing.SelectGroups — WORC 3.0.0 documentation + WORC.featureprocessing.SelectGroups — WORC 3.1.0 documentation @@ -59,7 +59,7 @@
- 3.0.0 + 3.1.0
diff --git a/WORC/doc/_build/html/_modules/WORC/featureprocessing/SelectIndividuals.html b/WORC/doc/_build/html/_modules/WORC/featureprocessing/SelectIndividuals.html index 341ac7b6..123eeac7 100644 --- a/WORC/doc/_build/html/_modules/WORC/featureprocessing/SelectIndividuals.html +++ b/WORC/doc/_build/html/_modules/WORC/featureprocessing/SelectIndividuals.html @@ -8,7 +8,7 @@ - WORC.featureprocessing.SelectIndividuals — WORC 3.0.0 documentation + WORC.featureprocessing.SelectIndividuals — WORC 3.1.0 documentation @@ -59,7 +59,7 @@
- 3.0.0 + 3.1.0
diff --git a/WORC/doc/_build/html/_modules/WORC/featureprocessing/StatisticalTestFeatures.html b/WORC/doc/_build/html/_modules/WORC/featureprocessing/StatisticalTestFeatures.html new file mode 100644 index 00000000..65b72a3f --- /dev/null +++ b/WORC/doc/_build/html/_modules/WORC/featureprocessing/StatisticalTestFeatures.html @@ -0,0 +1,373 @@ + + + + + + + + + + + WORC.featureprocessing.StatisticalTestFeatures — WORC 3.1.0 documentation + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+ + + +
+ + + + + +
+ +
+ + + + + + + + + + + + + + + + + +
+ +
    + +
  • Docs »
  • + +
  • Module code »
  • + +
  • WORC.featureprocessing.StatisticalTestFeatures
  • + + +
  • + +
  • + +
+ + +
+
+
+
+ +

Source code for WORC.featureprocessing.StatisticalTestFeatures

+#!/usr/bin/env python
+
+# Copyright 2016-2019 Biomedical Imaging Group Rotterdam, Departments of
+# Medical Informatics and Radiology, Erasmus MC, Rotterdam, The Netherlands
+#
+# 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 csv
+import numpy as np
+from scipy.stats import ttest_ind, ranksums, mannwhitneyu
+import WORC.IOparser.config_io_classifier as config_io
+from WORC.classification.trainclassifier import load_features
+
+
+
[docs]def StatisticalTestFeatures(features, patientinfo, config, output=None, + verbose=True, label_type=None): + ''' + Perform several statistical tests on features, such as a student t-test. + Useage is similar to trainclassifier. + + Parameters + ---------- + features: string, mandatory + contains the paths to all .hdf5 feature files used. + modalityname1=file1,file2,file3,... modalityname2=file1,... + Thus, modalities names are always between a space and a equal + sign, files are split by commas. We assume that the lists of + files for each modality has the same length. Files on the + same position on each list should belong to the same patient. + + patientinfo: string, mandatory + Contains the path referring to a .txt file containing the + patient label(s) and value(s) to be used for learning. See + the Github Wiki for the format. + + config: string, mandatory + path referring to a .ini file containing the parameters + used for feature extraction. See the Github Wiki for the possible + fields and their description. + + # TODO: outputs + + verbose: boolean, default True + print final feature values and labels to command line or not. + + ''' + # Load variables from the config file + config = config_io.load_config(config) + + if type(patientinfo) is list: + patientinfo = ''.join(patientinfo) + + if type(config) is list: + config = ''.join(config) + + if type(output) is list: + output = ''.join(output) + + # Create output folder if required + if not os.path.exists(os.path.dirname(output)): + os.makedirs(os.path.dirname(output)) + + if label_type is None: + label_type = config['Labels']['label_names'] + + # Read the features and classification data + print("Reading features and label data.") + label_data, image_features =\ + load_features(features, patientinfo, label_type) + + # Extract feature labels and put values in an array + feature_labels = image_features[0][1] + feature_values = np.zeros([len(image_features), len(feature_labels)]) + for num, x in enumerate(image_features): + feature_values[num, :] = x[0] + + # ----------------------------------------------------------------------- + # Perform statistical tests + print("Performing statistical tests.") + label_value = label_data['label'] + label_name = label_data['label_name'] + + header = list() + subheader = list() + for i_name in label_name: + header.append(str(i_name[0])) + header.append('') + header.append('') + header.append('') + header.append('') + header.append('') + + subheader.append('Label') + subheader.append('Ttest') + subheader.append('Welch') + subheader.append('Wilcoxon') + subheader.append('Mann-Whitney') + subheader.append('') + + # Open the output file + if output is not None: + myfile = open(output, 'w') + wr = csv.writer(myfile, quoting=csv.QUOTE_ALL) + wr.writerow(header) + wr.writerow(subheader) + + savedict = dict() + for i_class, i_name in zip(label_value, label_name): + savedict[i_name[0]] = dict() + pvalues = list() + pvalueswelch = list() + pvalueswil = list() + pvaluesmw = list() + + for num, fl in enumerate(feature_labels): + fv = feature_values[:, num] + classlabels = i_class.ravel() + + class1 = [i for j, i in enumerate(fv) if classlabels[j] == 1] + class2 = [i for j, i in enumerate(fv) if classlabels[j] == 0] + + pvalues.append(ttest_ind(class1, class2)[1]) + pvalueswelch.append(ttest_ind(class1, class2, equal_var=False)[1]) + pvalueswil.append(ranksums(class1, class2)[1]) + try: + pvaluesmw.append(mannwhitneyu(class1, class2)[1]) + except ValueError as e: + print("[PREDICT Warning] " + str(e) + '. Replacing metric value by 1.') + pvaluesmw.append(1) + + # Sort based on p-values: + indices = np.argsort(np.asarray(pvaluesmw)) + feature_labels_o = np.asarray(feature_labels)[indices].tolist() + + pvalues = np.asarray(pvalues)[indices].tolist() + pvalueswelch = np.asarray(pvalueswelch)[indices].tolist() + pvalueswil = np.asarray(pvalueswil)[indices].tolist() + pvaluesmw = np.asarray(pvaluesmw)[indices].tolist() + + savedict[i_name[0]]['ttest'] = pvalues + savedict[i_name[0]]['welch'] = pvalueswelch + savedict[i_name[0]]['wil'] = pvalueswil + savedict[i_name[0]]['mw'] = pvaluesmw + savedict[i_name[0]]['labels'] = feature_labels_o + + if output is not None: + for num in range(0, len(savedict[i_name[0]]['ttest'])): + writelist = list() + for i_name in savedict.keys(): + labeldict = savedict[i_name] + writelist.append(labeldict['labels'][num]) + writelist.append(labeldict['ttest'][num]) + writelist.append(labeldict['welch'][num]) + writelist.append(labeldict['wil'][num]) + writelist.append(labeldict['mw'][num]) + writelist.append('') + + wr.writerow(writelist) + + print("Saved data!") + + return savedict
+
+ +
+ +
+
+ + +
+ +
+

+ © Copyright 2016 -- 2019, Biomedical Imaging Group Rotterdam, Departments of Medical Informatics and Radiology, Erasmus MC, Rotterdam, The Netherlands + +

+
+ Built with Sphinx using a theme provided by Read the Docs. + +
+ +
+
+ +
+ +
+ + + + + + + + + + + + \ No newline at end of file diff --git a/WORC/doc/_build/html/_modules/WORC/featureprocessing/StatisticalTestThreshold.html b/WORC/doc/_build/html/_modules/WORC/featureprocessing/StatisticalTestThreshold.html index eceeb535..81be8cfa 100644 --- a/WORC/doc/_build/html/_modules/WORC/featureprocessing/StatisticalTestThreshold.html +++ b/WORC/doc/_build/html/_modules/WORC/featureprocessing/StatisticalTestThreshold.html @@ -8,7 +8,7 @@ - WORC.featureprocessing.StatisticalTestThreshold — WORC 3.0.0 documentation + WORC.featureprocessing.StatisticalTestThreshold — WORC 3.1.0 documentation @@ -59,7 +59,7 @@
- 3.0.0 + 3.1.0
@@ -229,17 +229,40 @@

Source code for WORC.featureprocessing.StatisticalTestThreshold

self.parameters = {} # Perform the statistical test for each feature + multilabel = type(Y_train[0]) is np.ndarray for n_feat in range(0, X_train.shape[1]): - fv = X_train[:, n_feat] - - class1 = [i for j, i in enumerate(fv) if Y_train[j] == 1] - class2 = [i for j, i in enumerate(fv) if Y_train[j] == 0] + # Select only this specific feature for all objects - try: - metric_value = self.metric_function(class1, class2, **self.parameters)[1] - except ValueError as e: - print("[PREDICT Warning] " + str(e) + '. Replacing metric value by 1.') - metric_value = 1 + fv = X_train[:, n_feat] + if multilabel: + # print('Multilabel: take minimum p-value for all label tests.') + # We do a statistical test per label and take the minimum p-value + n_label = Y_train[0].shape[0] + metric_values = list() + for i in range(n_label): + class1 = [i for j, i in enumerate(fv) if np.argmax(Y_train[j]) == n_label] + class2 = [i for j, i in enumerate(fv) if np.argmax(Y_train[j]) != n_label] + + try: + metric_value_temp = self.metric_function(class1, class2, **self.parameters)[1] + except ValueError as e: + print("[PREDICT Warning] " + str(e) + '. Replacing metric value by 1.') + metric_value_temp + + metric_values.append(metric_value_temp) + + metric_value = np.min(metric_values) + + else: + # Singlelabel + class1 = [i for j, i in enumerate(fv) if Y_train[j] == 1] + class2 = [i for j, i in enumerate(fv) if Y_train[j] == 0] + + try: + metric_value = self.metric_function(class1, class2, **self.parameters)[1] + except ValueError as e: + print("[PREDICT Warning] " + str(e) + '. Replacing metric value by 1.') + metric_value = 1 self.metric_values.append(metric_value) if metric_value < self.threshold: diff --git a/WORC/doc/_build/html/_modules/WORC/featureprocessing/VarianceThreshold.html b/WORC/doc/_build/html/_modules/WORC/featureprocessing/VarianceThreshold.html index 739c8860..b450b760 100644 --- a/WORC/doc/_build/html/_modules/WORC/featureprocessing/VarianceThreshold.html +++ b/WORC/doc/_build/html/_modules/WORC/featureprocessing/VarianceThreshold.html @@ -8,7 +8,7 @@ - WORC.featureprocessing.VarianceThreshold — WORC 3.0.0 documentation + WORC.featureprocessing.VarianceThreshold — WORC 3.1.0 documentation @@ -59,7 +59,7 @@
- 3.0.0 + 3.1.0
diff --git a/WORC/doc/_build/html/_modules/WORC/plotting/compute_CI.html b/WORC/doc/_build/html/_modules/WORC/plotting/compute_CI.html index 6b2f37f8..6c46da68 100644 --- a/WORC/doc/_build/html/_modules/WORC/plotting/compute_CI.html +++ b/WORC/doc/_build/html/_modules/WORC/plotting/compute_CI.html @@ -8,7 +8,7 @@ - WORC.plotting.compute_CI — WORC 3.0.0 documentation + WORC.plotting.compute_CI — WORC 3.1.0 documentation @@ -59,7 +59,7 @@
- 3.0.0 + 3.1.0
@@ -179,17 +179,35 @@

Source code for WORC.plotting.compute_CI

 from scipy.special import logit, expit
 
 
+
[docs]def compute_confidence_bootstrap(bootstrap_metric, test_metric, N_1, alpha=0.95): + """ + Function to calculate confidence interval for bootstrapped samples. + metric: numpy array containing the result for a metric for the different bootstrap iterations + test_metric: the value of the metric evaluated on the true, full test set + alpha: float ranging from 0 to 1 to calculate the alpha*100% CI, default 0.95 + """ + metric_std = np.std(bootstrap_metric) + CI = st.norm.interval(alpha, loc=test_metric, scale=metric_std) + return CI
+ +
[docs]def compute_confidence(metric, N_train, N_test, alpha=0.95): """ - Function to calculate the adjusted confidence interval + Function to calculate the adjusted confidence interval for cross-validation. metric: numpy array containing the result for a metric for the different cross validations (e.g. If 20 cross-validations are performed it is a list of length 20 with the calculated accuracy for each cross validation) N_train: Integer, number of training samples N_test: Integer, number of test_samples - alpha: float ranging from 0 to 1 to calculate the alpha*100% CI, default 95% + alpha: float ranging from 0 to 1 to calculate the alpha*100% CI, default 0.95 """ + # Remove NaN values if they are there + if np.isnan(metric).any(): + print('[WORC Warning] Array contains nan: removing.') + metric = np.asarray(metric) + metric = metric[np.logical_not(np.isnan(metric))] + # Convert to floats, as python 2 rounds the divisions if we have integers N_train = float(N_train) N_test = float(N_test) diff --git a/WORC/doc/_build/html/_modules/WORC/plotting/linstretch.html b/WORC/doc/_build/html/_modules/WORC/plotting/linstretch.html index bd7a7833..5acffb1b 100644 --- a/WORC/doc/_build/html/_modules/WORC/plotting/linstretch.html +++ b/WORC/doc/_build/html/_modules/WORC/plotting/linstretch.html @@ -8,7 +8,7 @@ - WORC.plotting.linstretch — WORC 3.0.0 documentation + WORC.plotting.linstretch — WORC 3.1.0 documentation @@ -59,7 +59,7 @@
- 3.0.0 + 3.1.0
diff --git a/WORC/doc/_build/html/_modules/WORC/plotting/plot_ROC.html b/WORC/doc/_build/html/_modules/WORC/plotting/plot_ROC.html index f89e028e..52cf4c22 100644 --- a/WORC/doc/_build/html/_modules/WORC/plotting/plot_ROC.html +++ b/WORC/doc/_build/html/_modules/WORC/plotting/plot_ROC.html @@ -8,7 +8,7 @@ - WORC.plotting.plot_ROC — WORC 3.0.0 documentation + WORC.plotting.plot_ROC — WORC 3.1.0 documentation @@ -59,7 +59,7 @@
- 3.0.0 + 3.1.0
@@ -210,7 +210,19 @@

Source code for WORC.plotting.plot_ROC

     fprev = -np.inf
     i = 0
     N = float(np.bincount(y_truth)[0])
-    P = float(np.bincount(y_truth)[1])
+    if len(np.bincount(y_truth)) == 1:
+        # No class = 1 present.
+        P = 0
+    else:
+        P = float(np.bincount(y_truth)[1])
+
+    if N == 0:
+        print('[WORC Warning] No negative class samples found, cannot determine ROC. Skipping iteration.')
+        return fpr, tpr, thresholds
+    elif P == 0:
+        print('[WORC Warning] No positive class samples found, cannot determine ROC. Skipping iteration.')
+        return fpr, tpr, thresholds
+
     while i < len(y_truth_sorted):
         if y_score[i] != fprev:
             fpr.append(1 - FP/N)
@@ -288,10 +300,11 @@ 

Source code for WORC.plotting.plot_ROC

     thresholds = list()
     for yt, ys in zip(y_truth, y_score):
         fpr_temp, tpr_temp, thresholds_temp = plot_single_ROC(yt, ys)
-        roc_auc.append(roc_auc_score(yt, ys))
-        fprt.append(fpr_temp)
-        tprt.append(tpr_temp)
-        thresholds.append(thresholds_temp)
+        if fpr_temp:
+            roc_auc.append(roc_auc_score(yt, ys))
+            fprt.append(fpr_temp)
+            tprt.append(tpr_temp)
+            thresholds.append(thresholds_temp)
 
     # Sample FPR and TPR at numerous points
     fpr, tpr, th = ROC_thresholding(fprt, tprt, thresholds, tsamples)
@@ -506,7 +519,7 @@ 

Source code for WORC.plotting.plot_ROC

 
     # Determine the predicted score per patient
     print('Determining score per patient.')
-    y_truths, y_scores, _, _ = plot_SVM(prediction, pinfo, label_type,
+    y_truths, y_scores, _, _ = plot_SVM(prediction, pinfo, [label_type],
                                         show_plots=False,
                                         alpha=0.95, ensemble=ensemble,
                                         output='decision')
@@ -530,7 +543,7 @@ 

Source code for WORC.plotting.plot_ROC

 
     # Save ROC values as JSON
     if output_csv is not None:
-        with open(output_csv, 'wb') as csv_file:
+        with open(output_csv, 'w') as csv_file:
             writer = csv.writer(csv_file)
             writer.writerow(['FPR', 'TPR'])
             for i in range(0, len(fpr)):
diff --git a/WORC/doc/_build/html/_modules/WORC/plotting/plot_SVM.html b/WORC/doc/_build/html/_modules/WORC/plotting/plot_SVM.html
index 598adc35..66781695 100644
--- a/WORC/doc/_build/html/_modules/WORC/plotting/plot_SVM.html
+++ b/WORC/doc/_build/html/_modules/WORC/plotting/plot_SVM.html
@@ -8,7 +8,7 @@
   
   
   
-  WORC.plotting.plot_SVM — WORC 3.0.0 documentation
+  WORC.plotting.plot_SVM — WORC 3.1.0 documentation
   
 
   
@@ -59,7 +59,7 @@
             
             
               
- 3.0.0 + 3.1.0
@@ -176,19 +176,72 @@

Source code for WORC.plotting.plot_SVM

 
 import numpy as np
 import sys
-import WORC.plotting.compute_CI as compute_CI
+from WORC.plotting.compute_CI import compute_confidence
+from WORC.plotting.compute_CI import compute_confidence_bootstrap
 import pandas as pd
 import os
+import lifelines as ll
 import WORC.processing.label_processing as lp
 from WORC.classification import metrics
 import WORC.addexceptions as ae
 from sklearn.base import is_regressor
+from collections import OrderedDict
+
+
+
[docs]def fit_thresholds(thresholds, estimator, X_train, Y_train, ensemble, ensemble_scoring): + print('Fitting thresholds on validation set') + if not hasattr(estimator, 'cv_iter'): + cv_iter = list(estimator.cv.split(X_train, Y_train)) + estimator.cv_iter = cv_iter + + p_est = estimator.cv_results_['params'][0] + p_all = estimator.cv_results_['params_all'][0] + n_iter = len(estimator.cv_iter) + + thresholds_low = list() + thresholds_high = list() + for it, (train, valid) in enumerate(estimator.cv_iter): + print(' - iteration {it + 1} / {n_iter}.') + # NOTE: Explicitly exclude validation set, elso refit and score + # somehow still seems to use it. + X_train_temp = [X_train[i] for i in train] + Y_train_temp = [Y_train[i] for i in train] + train_temp = range(0, len(train)) + + # Refit a SearchCV object with the provided parameters + if ensemble: + estimator.create_ensemble(X_train_temp, Y_train_temp, + method=ensemble, verbose=False, + scoring=ensemble_scoring) + else: + estimator.refit_and_score(X_train_temp, Y_train_temp, p_all, + p_est, train_temp, train_temp, + verbose=False) + + # Predict and save scores + X_train_values = [x[0] for x in X_train] # Throw away labels + X_train_values_valid = [X_train_values[i] for i in valid] + Y_valid_score_temp = estimator.predict_proba(X_train_values_valid) + + # Only take the probabilities for the second class + Y_valid_score_temp = Y_valid_score_temp[:, 1] + + # Select thresholds + thresholds_low.append(np.percentile(Y_valid_score_temp, thresholds[0]*100.0)) + thresholds_high.append(np.percentile(Y_valid_score_temp, thresholds[1]*100.0)) + + thresholds_val = [np.mean(thresholds_low), np.mean(thresholds_high)] + print(f'Thresholds {thresholds} converted to {thresholds_val}.') + return thresholds_val
[docs]def plot_SVM(prediction, label_data, label_type, show_plots=False, alpha=0.95, ensemble=False, verbose=True, ensemble_scoring=None, output='stats', - modus='singlelabel'): + modus='singlelabel', + thresholds=None, survival=False, + generalization=False, shuffle_estimators=False, + bootstrap=False, bootstrap_N=1000): ''' Plot the output of a single binary estimator, e.g. a SVM. @@ -231,6 +284,11 @@

Source code for WORC.plotting.plot_SVM

         Determine which results are put out. If stats, the statistics of the
         estimator will be returned. If scores, the scores will be returned.
 
+    thresholds: list of integer(s), default None
+        If None, use default threshold of sklearn (0.5) on posteriors to
+        converge to a binary prediction. If one integer is provided, use that one.
+        If two integers are provided, posterior < thresh[0] = 0, posterior > thresh[1] = 1.
+
     Returns
     ----------
     Depending on the output parameters, the following outputs are returned:
@@ -251,7 +309,7 @@ 

Source code for WORC.plotting.plot_SVM

     y_predictions: list
         Contains the predicted label for each object.
 
-    PIDs: list
+    pids: list
         Contains the patient ID/name for each object.
     '''
 
@@ -276,12 +334,14 @@ 

Source code for WORC.plotting.plot_SVM

                 label_type = [[label_type]]
             label_data = lp.load_labels(label_data, label_type)
 
+    n_labels = len(label_type)
     patient_IDs = label_data['patient_IDs']
     labels = label_data['label']
 
     if type(label_type) is list:
         # FIXME: Support for multiple label types not supported yet.
         print('[WORC Warning] Support for multiple label types not supported yet. Taking first label for plot_SVM.')
+        original_label_type = label_type[:]
         label_type = keys[0]
 
     # Extract the estimators, features and labels
@@ -294,35 +354,98 @@ 

Source code for WORC.plotting.plot_SVM

     feature_labels = prediction[label_type]['feature_labels']
 
     # Create lists for performance measures
-    sensitivity = list()
-    specificity = list()
-    precision = list()
-    accuracy = list()
-    auc = list()
-    f1_score_list = list()
+    if not regression:
+        sensitivity = list()
+        specificity = list()
+        precision = list()
+        npv = list()
+        accuracy = list()
+        bca = list()
+        auc = list()
+        f1_score_list = list()
+
+        if modus == 'multilabel':
+            acc_av = list()
+
+            # Also add scoring measures for all single label scores
+            sensitivity_single = list()
+            specificity_single = list()
+            precision_single = list()
+            npv_single = list()
+            accuracy_single = list()
+            bca_single = list()
+            auc_single = list()
+            f1_score_list_single = list()
+
+    else:
+        r2score = list()
+        MSE = list()
+        coefICC = list()
+        PearsonC = list()
+        PearsonP = list()
+        SpearmanC = list()
+        SpearmanP = list()
+        cindex = list()
+        coxcoef = list()
+        coxp = list()
+
     patient_classification_list = dict()
+    percentages_selected = list()
+
     if output in ['scores', 'decision']:
         # Keep track of all groundth truths and scores
         y_truths = list()
         y_scores = list()
         y_predictions = list()
-        PIDs = list()
+        pids = list()
 
-    # Loop over the test sets, which probably correspond with cross validation
-    # iterations
-    for i in range(0, len(Y_test)):
+    # Loop over the test sets, which correspond to cross-validation
+    # or bootstrapping iterations
+    if bootstrap:
+        iterobject = range(0, bootstrap_N)
+    else:
+        iterobject = range(0, len(Y_test))
+
+    for i in iterobject:
         print("\n")
-        print(("Cross validation {} / {}.").format(str(i + 1), str(len(Y_test))))
-        test_patient_IDs = prediction[label_type]['patient_ID_test'][i]
-        train_patient_IDs = prediction[label_type]['patient_ID_train'][i]
-        X_test_temp = X_test[i]
-        X_train_temp = X_train[i]
-        Y_train_temp = Y_train[i]
-        Y_test_temp = Y_test[i]
+        if bootstrap:
+            print(f"Bootstrap {i + 1} / {bootstrap_N}.")
+        else:
+            print(f"Cross validation {i + 1} / {len(Y_test)}.")
+
         test_indices = list()
 
+        # When bootstrapping, there is only a single train/test set.
+        if bootstrap:
+            X_test_temp = X_test[0]
+            X_train_temp = X_train[0]
+            Y_train_temp = Y_train[0]
+            Y_test_temp = Y_test[0]
+            test_patient_IDs = prediction[label_type]['patient_ID_test'][0]
+            train_patient_IDs = prediction[label_type]['patient_ID_train'][0]
+            fitted_model = SVMs[0]
+        else:
+            X_test_temp = X_test[i]
+            X_train_temp = X_train[i]
+            Y_train_temp = Y_train[i]
+            Y_test_temp = Y_test[i]
+            test_patient_IDs = prediction[label_type]['patient_ID_test'][i]
+            train_patient_IDs = prediction[label_type]['patient_ID_train'][i]
+            fitted_model = SVMs[i]
+
+        # If bootstrap, generate a bootstrapped sample
+        if bootstrap:
+            X_test_temp, Y_test_temp, test_patient_IDs = resample(X_test_temp, Y_test_temp, test_patient_IDs)
+
         # Check which patients are in the test set.
         for i_ID in test_patient_IDs:
+            if i_ID not in patient_IDs:
+                print(f'[WORC WARNING] Patient {i_ID} is not found the patient labels, removing underscore.')
+                i_ID = np.where(patient_IDs == i_ID.split("_")[0])
+                if i_ID not in patient_IDs:
+                    print(f'[WORC WARNING] Did not help, excluding patient {i_ID}.')
+                    continue
+
             test_indices.append(np.where(patient_IDs == i_ID)[0][0])
 
             # Initiate counting how many times a patient is classified correctly
@@ -337,26 +460,81 @@ 

Source code for WORC.plotting.plot_SVM

         # Extract ground truth
         y_truth = Y_test_temp
 
+        # If required, shuffle estimators for "Random" ensembling
+        if shuffle_estimators:
+            # Compute generalization score
+            print('Shuffling estimators for random ensembling.')
+            shuffle(fitted_model.cv_results_['params'])
+            shuffle(fitted_model.cv_results_['params_all'])
+
+        # If required, rank according to generalization score instead of mean_validation_score
+        if generalization:
+            # Compute generalization score
+            print('Using generalization score for estimator ranking.')
+            difference_score = abs(fitted_model.cv_results_['mean_train_score'] - fitted_model.cv_results_['mean_test_score'])
+            generalization_score = fitted_model.cv_results_['mean_test_score'] - difference_score
+
+            # Rerank based on score
+            indices = np.argsort(generalization_score)
+            fitted_model.cv_results_['params'] = [fitted_model.cv_results_['params'][i] for i in indices[::-1]]
+            fitted_model.cv_results_['params_all'] = [fitted_model.cv_results_['params_all'][i] for i in indices[::-1]]
+
         # If requested, first let the SearchCV object create an ensemble
-        if ensemble:
+        if bootstrap and i > 0:
+            # For bootstrapping, only do this at the first iteration
+            pass
+        elif ensemble > 1:
             # NOTE: Added for backwards compatability
-            if not hasattr(SVMs[i], 'cv_iter'):
-                cv_iter = list(SVMs[i].cv.split(X_train_temp, Y_train_temp))
-                SVMs[i].cv_iter = cv_iter
+            if not hasattr(fitted_model, 'cv_iter'):
+                cv_iter = list(fitted_model.cv.split(X_train_temp, Y_train_temp))
+                fitted_model.cv_iter = cv_iter
 
             # Create the ensemble
             X_train_temp = [(x, feature_labels) for x in X_train_temp]
-            SVMs[i].create_ensemble(X_train_temp, Y_train_temp,
+            fitted_model.create_ensemble(X_train_temp, Y_train_temp,
                                     method=ensemble, verbose=verbose,
                                     scoring=ensemble_scoring)
 
         # Create prediction
-        y_prediction = SVMs[i].predict(X_test_temp)
+        y_prediction = fitted_model.predict(X_test_temp)
 
         if regression:
             y_score = y_prediction
+        elif modus == 'multilabel':
+            y_score = fitted_model.predict_proba(X_test_temp)
         else:
-            y_score = SVMs[i].predict_proba(X_test_temp)[:, 1]
+            y_score = fitted_model.predict_proba(X_test_temp)[:, 1]
+
+        # Create a new binary score based on the thresholds if given
+        if thresholds is not None:
+            if len(thresholds) == 1:
+                y_prediction = y_score >= thresholds[0]
+            elif len(thresholds) == 2:
+                # X_train_temp = [x[0] for x in X_train_temp]
+
+                y_score_temp = list()
+                y_prediction_temp = list()
+                y_truth_temp = list()
+                test_patient_IDs_temp = list()
+
+                thresholds_val = fit_thresholds(thresholds, fitted_model, X_train_temp, Y_train_temp, ensemble,
+                                                ensemble_scoring)
+                for pnum in range(len(y_score)):
+                    if y_score[pnum] <= thresholds_val[0] or y_score[pnum] > thresholds_val[1]:
+                        y_score_temp.append(y_score[pnum])
+                        y_prediction_temp.append(y_prediction[pnum])
+                        y_truth_temp.append(y_truth[pnum])
+                        test_patient_IDs_temp.append(test_patient_IDs[pnum])
+
+                perc = float(len(y_prediction_temp))/float(len(y_prediction))
+                percentages_selected.append(perc)
+                print(f"Selected {len(y_prediction_temp)} from {len(y_prediction)} ({perc}%) patients using two thresholds.")
+                y_score = y_score_temp
+                y_prediction = y_prediction_temp
+                y_truth = y_truth_temp
+                test_patient_IDs = test_patient_IDs_temp
+            else:
+                raise ae.WORCValueError(f"Need None, one or two thresholds on the posterior; got {len(thresholds)}.")
 
         print("Truth: " + str(y_truth))
         print("Prediction: " + str(y_prediction))
@@ -373,21 +551,19 @@ 

Source code for WORC.plotting.plot_SVM

             else:
                 patient_classification_list[i_test_ID]['N_wrong'] += 1
 
-        y_score = SVMs[i].predict_proba(X_test_temp)[:, 1]
-
         if output == 'decision':
             # Output the posteriors
             y_scores.append(y_score)
             y_truths.append(y_truth)
             y_predictions.append(y_prediction)
-            PIDs.append(test_patient_IDs)
+            pids.append(test_patient_IDs)
 
         elif output == 'scores':
             # Output the posteriors
             y_scores.append(y_score)
             y_truths.append(y_truth)
             y_predictions.append(y_prediction)
-            PIDs.append(test_patient_IDs)
+            pids.append(test_patient_IDs)
 
         elif output == 'stats':
             # Compute statistics
@@ -395,15 +571,17 @@ 

Source code for WORC.plotting.plot_SVM

             if modus == 'singlelabel':
                 # Compute singlelabel performance metrics
                 if not regression:
-                    accuracy_temp, sensitivity_temp, specificity_temp,\
-                        precision_temp, f1_score_temp, auc_temp =\
+                    accuracy_temp, bca_temp, sensitivity_temp,\
+                        specificity_temp,\
+                        precision_temp, npv_temp, f1_score_temp, auc_temp =\
                         metrics.performance_singlelabel(y_truth,
                                                         y_prediction,
                                                         y_score,
                                                         regression)
                 else:
-                    r2score, MSE, coefICC, PearsonC, PearsonP, SpearmanC,\
-                        SpearmanP =\
+                    r2score_temp, MSE_temp, coefICC_temp, PearsonC_temp,\
+                        PearsonP_temp, SpearmanC_temp,\
+                        SpearmanP_temp =\
                         metrics.performance_singlelabel(y_truth,
                                                         y_prediction,
                                                         y_score,
@@ -427,157 +605,297 @@ 

Source code for WORC.plotting.plot_SVM

 
                 # Compute multilabel performance metrics
                 accuracy_temp, sensitivity_temp, specificity_temp,\
-                    precision_temp, f1_score_temp, auc_temp =\
+                    precision_temp, npv_temp, f1_score_temp, auc_temp, acc_av_temp =\
                     metrics.performance_multilabel(y_truth,
                                                    y_prediction,
                                                    y_score)
 
+                # Compute all single label performance metrics as well
+                for i_label in range(n_labels):
+                    y_truth_single = [i == i_label for i in y_truth]
+                    y_prediction_single = [i == i_label for i in y_prediction]
+                    y_score_single = y_score[:, i_label]
+
+                    accuracy_temp_single, bca_temp_single, sensitivity_temp_single, specificity_temp_single,\
+                        precision_temp_single, npv_temp_single, f1_score_temp_single, auc_temp_single =\
+                        metrics.performance_singlelabel(y_truth_single,
+                                                        y_prediction_single,
+                                                        y_score_single,
+                                                        regression)
+
             else:
-                raise ae.WORCKeyError('{} is not a valid modus!').format(modus)
+                raise ae.WORCKeyError('{modus} is not a valid modus!')
 
             # Print AUC to keep you up to date
-            print('AUC: ' + str(auc_temp))
+            if not regression:
+                print('AUC: ' + str(auc_temp))
+
+                # Append performance to lists for all cross validations
+                accuracy.append(accuracy_temp)
+                bca.append(bca_temp)
+                sensitivity.append(sensitivity_temp)
+                specificity.append(specificity_temp)
+                auc.append(auc_temp)
+                f1_score_list.append(f1_score_temp)
+                precision.append(precision_temp)
+                npv.append(npv_temp)
+
+                if modus == 'multilabel':
+                    acc_av.append(acc_av_temp)
+
+                    accuracy_single.append(accuracy_temp_single)
+                    bca_single.append(bca_temp_single)
+                    sensitivity_single.append(sensitivity_temp_single)
+                    specificity_single.append(specificity_temp_single)
+                    auc_single.append(auc_temp_single)
+                    f1_score_list_single.append(f1_score_temp_single)
+                    precision_single.append(precision_temp_single)
+                    npv_single.append(npv_temp_single)
+
+            else:
+                print('R2 Score: ' + str(r2score_temp))
+
+                r2score.append(r2score_temp)
+                MSE.append(MSE_temp)
+                coefICC.append(coefICC_temp)
+                PearsonC.append(PearsonC_temp)
+                PearsonP.append(PearsonP_temp)
+                SpearmanC.append(SpearmanC_temp)
+                SpearmanP.append(SpearmanP_temp)
+
+        if survival:
+            # Extract time to event and event from label data
+            E_truth = np.asarray([labels[1][k][0] for k in test_indices])
+            T_truth = np.asarray([labels[2][k][0] for k in test_indices])
+
+            # Concordance index
+            cindex.append(1 - ll.utils.concordance_index(T_truth, y_prediction, E_truth))
+
+            # Fit Cox model using SVR output, time to event and event
+            data = {'predict': y_prediction, 'E': E_truth, 'T': T_truth}
+            data = pd.DataFrame(data=data, index=test_patient_IDs)
+
+            cph = ll.CoxPHFitter()
+            cph.fit(data, duration_col='T', event_col='E')
 
-            # Append performance to lists for all cross validations
-            accuracy.append(accuracy_temp)
-            sensitivity.append(sensitivity_temp)
-            specificity.append(specificity_temp)
-            auc.append(auc_temp)
-            f1_score_list.append(f1_score_temp)
-            precision.append(precision_temp)
+            coxcoef.append(cph.summary['coef']['predict'])
+            coxp.append(cph.summary['p']['predict'])
 
     if output in ['scores', 'decision']:
         # Return the scores and true values of all patients
-        return y_truths, y_scores, y_predictions, PIDs
+        return y_truths, y_scores, y_predictions, pids
     elif output == 'stats':
         # Compute statistics
         # Extract sample size
         N_1 = float(len(train_patient_IDs))
         N_2 = float(len(test_patient_IDs))
 
-        # Compute alpha confidence intervallen
+        # Compute alpha confidence intervals (CIs)
         stats = dict()
-        stats["Accuracy 95%:"] = str(compute_CI.compute_confidence(accuracy, N_1, N_2, alpha))
-
-        stats["AUC 95%:"] = str(compute_CI.compute_confidence(auc, N_1, N_2, alpha))
-
-        stats["F1-score 95%:"] = str(compute_CI.compute_confidence(f1_score_list, N_1, N_2, alpha))
-
-        stats["Precision 95%:"] = str(compute_CI.compute_confidence(precision, N_1, N_2, alpha))
+        if not regression:
+            if bootstrap:
+                # Compute once for the real test set the performance
+                X_test_temp = X_test[0]
+                y_truth = Y_test[0]
+                y_prediction = fitted_model.predict(X_test_temp)
+
+                if regression:
+                    y_score = y_prediction
+                else:
+                    y_score = fitted_model.predict_proba(X_test_temp)[:, 1]
+
+                accuracy_test, bca_test, sensitivity_test, specificity_test,\
+                    precision_test, npv_test, f1_score_test, auc_test =\
+                    metrics.performance_singlelabel(y_truth,
+                                                    y_prediction,
+                                                    y_score,
+                                                    regression)
+
+                stats["Accuracy 95%:"] = f"{accuracy_test} {str(compute_confidence_bootstrap(accuracy, accuracy_test, N_1, alpha))}"
+                stats["BCA 95%:"] = f"{bca_test} {str(compute_confidence_bootstrap(bca, bca_test, N_1, alpha))}"
+                stats["AUC 95%:"] = f"{auc_test} {str(compute_confidence_bootstrap(auc, auc_test, N_1, alpha))}"
+                stats["F1-score 95%:"] = f"{f1_score_list_test} {str(compute_confidence_bootstrap(f1_score_list, f1_score_test, N_1, alpha))}"
+                stats["Precision 95%:"] = f"{precision_test} {str(compute_confidence_bootstrap(precision, precision_test, N_1, alpha))}"
+                stats["NPV 95%:"] = f"{npv_test} {str(compute_confidence_bootstrap(npv, npv_test, N_1, alpha))}"
+                stats["Sensitivity 95%: "] = f"{sensitivity_test} {str(compute_confidence_bootstrap(sensitivity, sensitivity_test, N_1, alpha))}"
+                stats["Specificity 95%:"] = f"{specificity_test} {str(compute_confidence_bootstrap(specificity, specificity_test, N_1, alpha))}"
+            else:
+                stats["Accuracy 95%:"] = f"{np.nanmean(accuracy)} {str(compute_confidence(accuracy, N_1, N_2, alpha))}"
+                stats["BCA 95%:"] = f"{np.nanmean(bca)} {str(compute_confidence(bca, N_1, N_2, alpha))}"
+                stats["AUC 95%:"] = f"{np.nanmean(auc)} {str(compute_confidence(auc, N_1, N_2, alpha))}"
+                stats["F1-score 95%:"] = f"{np.nanmean(f1_score_list)} {str(compute_confidence(f1_score_list, N_1, N_2, alpha))}"
+                stats["Precision 95%:"] = f"{np.nanmean(precision)} {str(compute_confidence(precision, N_1, N_2, alpha))}"
+                stats["NPV 95%:"] = f"{np.nanmean(npv)} {str(compute_confidence(npv, N_1, N_2, alpha))}"
+                stats["Sensitivity 95%: "] = f"{np.nanmean(sensitivity)} {str(compute_confidence(sensitivity, N_1, N_2, alpha))}"
+                stats["Specificity 95%:"] = f"{np.nanmean(specificity)} {str(compute_confidence(specificity, N_1, N_2, alpha))}"
 
-        stats["Sensitivity 95%: "] = str(compute_CI.compute_confidence(sensitivity, N_1, N_2, alpha))
+            if modus == 'multilabel':
+                stats["Average Accuracy 95%:"] = f"{np.nanmean(acc_av)} {str(compute_confidence(acc_av, N_1, N_2, alpha))}"
+
+            if thresholds is not None:
+                if len(thresholds) == 2:
+                    # Compute percentage of patients that was selected
+                    stats["Percentage Selected 95%:"] = f"{np.nanmean(percentages_selected)} {str(compute_confidence(percentages_selected, N_1, N_2, alpha))}"
+
+            # Extract statistics on how often patients got classified correctly
+            alwaysright = dict()
+            alwayswrong = dict()
+            percentages = dict()
+            for i_ID in patient_classification_list:
+                percentage_right = patient_classification_list[i_ID]['N_correct'] / float(patient_classification_list[i_ID]['N_test'])
+
+                if i_ID in patient_IDs:
+                    label = labels[0][np.where(i_ID == patient_IDs)]
+                else:
+                    # Multiple instance of one patient
+                    label = labels[0][np.where(i_ID.split('_')[0] == patient_IDs)]
+
+                label = label[0][0]
+                percentages[i_ID] = str(label) + ': ' + str(round(percentage_right, 2) * 100) + '%'
+                if percentage_right == 1.0:
+                    alwaysright[i_ID] = label
+                    print(f"Always Right: {i_ID}, label {label}.")
+
+                elif percentage_right == 0:
+                    alwayswrong[i_ID] = label
+                    print(f"Always Wrong: {i_ID}, label {label}.")
+
+            stats["Always right"] = alwaysright
+            stats["Always wrong"] = alwayswrong
+            stats['Percentages'] = percentages
+        else:
+            # Regression
+            stats['R2-score 95%: '] = f"{np.nanmean(r2_score)} {str(compute_confidence(r2score, N_1, N_2, alpha))}"
+            stats['MSE 95%: '] = f"{np.nanmean(MSE)} {str(compute_confidence(MSE, N_1, N_2, alpha))}"
+            stats['ICC 95%: '] = f"{np.nanmean(coefICC)} {str(compute_confidence(coefICC, N_1, N_2, alpha))}"
+            stats['PearsonC 95%: '] = f"{np.nanmean(PearsonC)} {str(compute_confidence(PearsonC, N_1, N_2, alpha))}"
+            stats['PearsonP 95%: '] = f"{np.nanmean(PearsonP)} {str(compute_confidence(PearsonP, N_1, N_2, alpha))}"
+            stats['SpearmanC 95%: '] = f"{np.nanmean(SpearmanC)} {str(compute_confidence(SpearmanC, N_1, N_2, alpha))}"
+            stats['SpearmanP 95%: '] = f"{np.nanmean(SpearmanP)} {str(compute_confidence(SpearmanP, N_1, N_2, alpha))}"
+
+            if survival:
+                stats["Concordance 95%:"] = f"{np.nanmean(cindex)} {str(compute_confidence(cindex, N_1, N_2, alpha))}"
+                stats["Cox coef. 95%:"] = f"{np.nanmean(coxcoef)} {str(compute_confidence(coxcoef, N_1, N_2, alpha))}"
+                stats["Cox p 95%:"] = f"{np.nanmean(coxp)} {str(compute_confidence(coxp, N_1, N_2, alpha))}"
+
+        # Print all CI's
+        stats = OrderedDict(sorted(stats.items()))
+        for k, v in stats.items():
+            print(f"{k} : {v}.")
 
-        stats["Specificity 95%:"] = str(compute_CI.compute_confidence(specificity, N_1, N_2, alpha))
+        return stats
- print("Accuracy 95%:" + str(compute_CI.compute_confidence(accuracy, N_1, N_2, alpha))) - print("AUC 95%:" + str(compute_CI.compute_confidence(auc, N_1, N_2, alpha))) +
[docs]def combine_multiple_estimators(predictions, label_data, multilabel_type, label_types, + ensemble=1, strategy='argmax', alpha=0.95): + ''' + Combine multiple estimators in a single model. - print("F1-score 95%:" + str(compute_CI.compute_confidence(f1_score_list, N_1, N_2, alpha))) + Note: the multilabel_type labels should correspond to the ordering in label_types. + Hence, if multilabel_type = 0, the prediction is label_type[0] etc. + ''' - print("Precision 95%:" + str(compute_CI.compute_confidence(precision, N_1, N_2, alpha))) + # Load the multilabel label data + label_data = lp.load_labels(label_data, multilabel_type) + patient_IDs = label_data['patient_IDs'] + labels = label_data['label'] - print("Sensitivity 95%: " + str(compute_CI.compute_confidence(sensitivity, N_1, N_2, alpha))) + # Initialize some objects + y_truths = list() + y_scores = list() + y_predictions = list() + pids = list() - print("Specificity 95%:" + str(compute_CI.compute_confidence(specificity, N_1, N_2, alpha))) + y_truths_train = list() + y_scores_train = list() + y_predictions_train = list() + pids_train = list() - # Extract statistics on how often patients got classified correctly - alwaysright = dict() - alwayswrong = dict() - percentages = dict() - for i_ID in patient_classification_list: - percentage_right = patient_classification_list[i_ID]['N_correct'] / float(patient_classification_list[i_ID]['N_test']) + accuracy = list() + sensitivity = list() + specificity = list() + auc = list() + f1_score_list = list() + precision = list() + npv = list() + acc_av = list() + + # Extract all the predictions from the estimators + for prediction, label_type in zip(predictions, label_types): + y_truth, y_score, y_prediction, pid,\ + y_truth_train, y_score_train, y_prediction_train, pid_train =\ + plot_SVM(prediction, label_data, label_type, + ensemble=ensemble, output='allscores') + y_truths.append(y_truth) + y_scores.append(y_score) + y_predictions.append(y_prediction) + pids.append(pid) + + y_truths_train.append(y_truth_train) + y_scores_train.append(y_score_train) + y_predictions_train.append(y_prediction_train) + pids_train.append(pid_train) + + # Combine the predictions + for i_crossval in range(0, len(y_truths[0])): + # Extract all values for this cross validation iteration from all objects + y_truth = [t[i_crossval] for t in y_truths] + y_score = [t[i_crossval] for t in y_scores] + pid = [t[i_crossval] for t in pids] + + if strategy == 'argmax': + # For each patient, take the maximum posterior + y_prediction = np.argmax(y_score, axis=0) + y_score = np.max(y_score, axis=0) + elif strategy == 'decisiontree': + # Fit a decision tree on the training set + a = 1 + else: + raise ae.WORCValueError(f"{strategy} is not a valid estimation combining strategy! Should be one of [argmax].") - if i_ID in patient_IDs: - label = labels[0][np.where(i_ID == patient_IDs)] - else: - # Multiple instance of one patient - label = labels[0][np.where(i_ID.split('_')[0] == patient_IDs)] - - label = label[0][0] - percentages[i_ID] = str(label) + ': ' + str(round(percentage_right, 2) * 100) + '%' - if percentage_right == 1.0: - alwaysright[i_ID] = label - print(("Always Right: {}, label {}").format(i_ID, label)) - - elif percentage_right == 0: - alwayswrong[i_ID] = label - print(("Always Wrong: {}, label {}").format(i_ID, label)) - - stats["Always right"] = alwaysright - stats["Always wrong"] = alwayswrong - stats['Percentages'] = percentages - - if show_plots: - # Plot some characteristics in boxplots - import matplotlib.pyplot as plt - - plt.figure() - plt.boxplot(accuracy) - plt.ylim([-0.05, 1.05]) - plt.ylabel('Accuracy') - plt.tick_params( - axis='x', # changes apply to the x-axis - which='both', # both major and minor ticks are affected - bottom='off', # ticks along the bottom edge are off - top='off', # ticks along the top edge are off - labelbottom='off') # labels along the bottom edge are off - plt.tight_layout() - plt.show() - - plt.figure() - plt.boxplot(auc) - plt.ylim([-0.05, 1.05]) - plt.ylabel('AUC') - plt.tick_params( - axis='x', # changes apply to the x-axis - which='both', # both major and minor ticks are affected - bottom='off', # ticks along the bottom edge are off - top='off', # ticks along the top edge are off - labelbottom='off') # labels along the bottom edge are off - plt.tight_layout() - plt.show() - - plt.figure() - plt.boxplot(precision) - plt.ylim([-0.05, 1.05]) - plt.ylabel('Precision') - plt.tick_params( - axis='x', # changes apply to the x-axis - which='both', # both major and minor ticks are affected - bottom='off', # ticks along the bottom edge are off - top='off', # ticks along the top edge are off - labelbottom='off') # labels along the bottom edge are off - plt.tight_layout() - plt.show() - - plt.figure() - plt.boxplot(sensitivity) - plt.ylim([-0.05, 1.05]) - plt.ylabel('Sensitivity') - plt.tick_params( - axis='x', # changes apply to the x-axis - which='both', # both major and minor ticks are affected - bottom='off', # ticks along the bottom edge are off - top='off', # ticks along the top edge are off - labelbottom='off') # labels along the bottom edge are off - plt.tight_layout() - plt.show() - - plt.figure() - plt.boxplot(specificity) - plt.ylim([-0.05, 1.05]) - plt.ylabel('Specificity') - plt.tick_params( - axis='x', # changes apply to the x-axis - which='both', # both major and minor ticks are affected - bottom='off', # ticks along the bottom edge are off - top='off', # ticks along the top edge are off - labelbottom='off') # labels along the bottom edge are off - plt.tight_layout() - plt.show() + # Compute multilabel performance metrics + y_truth = np.argmax(y_truth, axis=0) + accuracy_temp, sensitivity_temp, specificity_temp, \ + precision_temp, npv_temp, f1_score_temp, auc_temp, accav_temp = \ + metrics.performance_multilabel(y_truth, + y_prediction, + y_score) - return stats
+ print("Truth: " + str(y_truth)) + print("Prediction: " + str(y_prediction)) + print('AUC: ' + str(auc_temp)) + + # Append performance to lists for all cross validations + accuracy.append(accuracy_temp) + sensitivity.append(sensitivity_temp) + specificity.append(specificity_temp) + auc.append(auc_temp) + f1_score_list.append(f1_score_temp) + precision.append(precision_temp) + npv.append(npv_temp) + acc_av.append(acc_av_temp) + + # Extract sample size + N_1 = float(len(train_patient_IDs)) + N_2 = float(len(test_patient_IDs)) + + # Compute confidence intervals + stats = dict() + stats["Accuracy 95%:"] = f"{np.nanmean(accuracy)} {str(compute_confidence(accuracy, N_1, N_2, alpha))}" + stats["Average Accuracy 95%:"] = f"{np.nanmean(acc_av)} {str(compute_confidence(accuracy, N_1, N_2, alpha))}" + stats["AUC 95%:"] = f"{np.nanmean(auc)} {str(compute_confidence(auc, N_1, N_2, alpha))}" + stats["F1-score 95%:"] = f"{np.nanmean(f1_score_list)} {str(compute_confidence(f1_score_list, N_1, N_2, alpha))}" + stats["Precision 95%:"] = f"{np.nanmean(precision)} {str(compute_confidence(precision, N_1, N_2, alpha))}" + stats["NPV 95%:"] = f"{np.nanmean(npv)} {str(compute_confidence(npv, N_1, N_2, alpha))}" + stats["Sensitivity 95%: "] = f"{np.nanmean(sensitivity)} {str(compute_confidence(sensitivity, N_1, N_2, alpha))}" + stats["Specificity 95%:"] = f"{np.nanmean(specificity)} {str(compute_confidence(specificity, N_1, N_2, alpha))}" + + # Print all CI's + stats = OrderedDict(sorted(stats.items())) + for k, v in stats.items(): + print(f"{k} : {v}.") + + return stats
[docs]def main(): diff --git a/WORC/doc/_build/html/_modules/WORC/plotting/plot_SVR.html b/WORC/doc/_build/html/_modules/WORC/plotting/plot_SVR.html index a11140c8..0b3ffd29 100644 --- a/WORC/doc/_build/html/_modules/WORC/plotting/plot_SVR.html +++ b/WORC/doc/_build/html/_modules/WORC/plotting/plot_SVR.html @@ -8,7 +8,7 @@ - WORC.plotting.plot_SVR — WORC 3.0.0 documentation + WORC.plotting.plot_SVR — WORC 3.1.0 documentation @@ -59,7 +59,7 @@
- 3.0.0 + 3.1.0
diff --git a/WORC/doc/_build/html/_modules/WORC/plotting/plot_barchart.html b/WORC/doc/_build/html/_modules/WORC/plotting/plot_barchart.html index 8e62d5f6..f757db9f 100644 --- a/WORC/doc/_build/html/_modules/WORC/plotting/plot_barchart.html +++ b/WORC/doc/_build/html/_modules/WORC/plotting/plot_barchart.html @@ -8,7 +8,7 @@ - WORC.plotting.plot_barchart — WORC 3.0.0 documentation + WORC.plotting.plot_barchart — WORC 3.1.0 documentation @@ -59,7 +59,7 @@
- 3.0.0 + 3.1.0
@@ -251,11 +251,11 @@

Source code for WORC.plotting.plot_barchart

 
     # Save the output
     if output_tex is not None:
-        print('Saving barchart to {}.').format(output_tex)
+        print(f'Saving barchart to {output_tex}.')
         tikz_save(output_tex)
 
     if output_png is not None:
-        print('Saving barchart to {}.').format(output_png)
+        print(f'Saving barchart to {output_png}.')
         fig.savefig(output_png, bbox_inches='tight', pad_inches=0, dpi=50)
@@ -358,7 +358,7 @@

Source code for WORC.plotting.plot_barchart

 
[docs]def count_parameters(parameters): # Count for every parameter how many times a setting occurs output = dict() - for setting, values in parameters.iteritems(): + for setting, values in parameters.items(): output[setting] = dict() c = Counter(values) for k, v in zip(c.keys(), c.values()): diff --git a/WORC/doc/_build/html/_modules/WORC/plotting/plot_boxplot.html b/WORC/doc/_build/html/_modules/WORC/plotting/plot_boxplot.html index 7cff8a7c..b142cf03 100644 --- a/WORC/doc/_build/html/_modules/WORC/plotting/plot_boxplot.html +++ b/WORC/doc/_build/html/_modules/WORC/plotting/plot_boxplot.html @@ -8,7 +8,7 @@ - WORC.plotting.plot_boxplot — WORC 3.0.0 documentation + WORC.plotting.plot_boxplot — WORC 3.1.0 documentation @@ -59,7 +59,7 @@
- 3.0.0 + 3.1.0
diff --git a/WORC/doc/_build/html/_modules/WORC/plotting/plot_images.html b/WORC/doc/_build/html/_modules/WORC/plotting/plot_images.html index 012c9d95..39cdc51a 100644 --- a/WORC/doc/_build/html/_modules/WORC/plotting/plot_images.html +++ b/WORC/doc/_build/html/_modules/WORC/plotting/plot_images.html @@ -8,7 +8,7 @@ - WORC.plotting.plot_images — WORC 3.0.0 documentation + WORC.plotting.plot_images — WORC 3.1.0 documentation @@ -59,7 +59,7 @@
- 3.0.0 + 3.1.0
@@ -183,8 +183,8 @@

Source code for WORC.plotting.plot_images

 import SimpleITK as sitk
 
 
-
[docs]def slicer(image, mask, output_name, output_name_zoom, thresholds=[-240, 160], - zoomfactor=4): +
[docs]def slicer(image, mask, output_name, output_name_zoom=None, thresholds=[-240, 160], + zoomfactor=4, dpi=500, normalize=False, expand=False): ''' image and mask should both be arrays ''' @@ -193,8 +193,6 @@

Source code for WORC.plotting.plot_images

     spacing = float(image.GetSpacing()[0])
     imsize = [float(image.GetSize()[0]), float(image.GetSize()[1])]
     figsize = (imsize[0]*spacing/100.0, imsize[1]*spacing/100.0)
-    # dpi = int(200/spacing)
-    dpi = 100.0
 
     # Convert images to numpy arrays
     image = sitk.GetArrayFromImage(image)
@@ -206,6 +204,29 @@ 

Source code for WORC.plotting.plot_images

     imslice = image[max_ind, :, :]
     maskslice = mask[max_ind, :, :]
 
+    if expand:
+        print('\t Expanding.')
+        imslice = sitk.GetImageFromArray(imslice)
+        maskslice = sitk.GetImageFromArray(maskslice)
+
+        newsize = (4, 4)
+        imslice = sitk.Expand(imslice, newsize)
+        maskslice = sitk.Expand(maskslice, newsize)
+
+        # Adjust the size
+        spacing = float(imslice.GetSpacing()[0])
+        imsize = [float(imslice.GetSize()[0]), float(imslice.GetSize()[1])]
+        figsize = (imsize[0]*spacing/100.0, imsize[1]*spacing/100.0)
+
+        imslice = sitk.GetArrayFromImage(imslice)
+        maskslice = sitk.GetArrayFromImage(maskslice)
+
+    if normalize:
+        print('\t Normalizing.')
+        imslice = sitk.GetImageFromArray(imslice)
+        imslice = sitk.Normalize(imslice)
+        imslice = sitk.GetArrayFromImage(imslice)
+
     # Threshold the image if desired
     if thresholds:
         imslice[imslice < thresholds[0]] = thresholds[0]
@@ -220,23 +241,25 @@ 

Source code for WORC.plotting.plot_images

     # Save some memory
     del fig
 
-    # Create a bounding box and save zoomed image
-    imslice, maskslice = bbox_2D(imslice, maskslice, padding=[20, 20])
-    imsize = [float(imslice.shape[0]), float(imslice.shape[1])]
+    if output_name_zoom is not None:
+        # Create a bounding box and save zoomed image
+        imslice, maskslice = bbox_2D(imslice, maskslice, padding=[20, 20])
+        imsize = [float(imslice.shape[0]), float(imslice.shape[1])]
 
-    # NOTE: As these zoomed images get small, we double the spacing
-    spacing = spacing * zoomfactor
-    figsize = (imsize[0]*spacing/100.0, imsize[1]*spacing/100.0)
-    fig = plot_im_and_overlay(imslice, maskslice, figsize=figsize)
-    fig.savefig(output_name_zoom, bbox_inches='tight', pad_inches=0, dpi=dpi)
-    plt.close('all')
+        # NOTE: As these zoomed images get small, we double the spacing
+        spacing = spacing * zoomfactor
+        figsize = (imsize[0]*spacing/100.0, imsize[1]*spacing/100.0)
+        fig = plot_im_and_overlay(imslice, maskslice, figsize=figsize)
+        fig.savefig(output_name_zoom, bbox_inches='tight', pad_inches=0, dpi=dpi)
+        plt.close('all')
+
+        # Save some memory
+        del fig, image, mask
 
-    # Save some memory
-    del fig, image, mask
     return imslice, maskslice
-
[docs]def plot_im_and_overlay(image, mask, figsize=(3, 3), alpha=0.15): +
[docs]def plot_im_and_overlay(image, mask, figsize=(3, 3), alpha=0.40): ''' Plot an image in a matplotlib figure and overlay with a mask. ''' diff --git a/WORC/doc/_build/html/_modules/WORC/plotting/plot_ranked_scores.html b/WORC/doc/_build/html/_modules/WORC/plotting/plot_ranked_scores.html index 4985a6e2..c200d309 100644 --- a/WORC/doc/_build/html/_modules/WORC/plotting/plot_ranked_scores.html +++ b/WORC/doc/_build/html/_modules/WORC/plotting/plot_ranked_scores.html @@ -8,7 +8,7 @@ - WORC.plotting.plot_ranked_scores — WORC 3.0.0 documentation + WORC.plotting.plot_ranked_scores — WORC 3.1.0 documentation @@ -59,7 +59,7 @@
- 3.0.0 + 3.1.0
@@ -181,7 +181,7 @@

Source code for WORC.plotting.plot_ranked_scores

import numpy as np import csv import os -import WORC.plotting.plot_images as pi +from WORC.plotting import plot_images as pi import SimpleITK as sitk from WORC.addexceptions import WORCKeyError import zipfile @@ -272,16 +272,16 @@

Source code for WORC.plotting.plot_ranked_scores

print('Determining score per patient.') stats = plot_SVM(prediction, pinfo, - label_type, + [label_type], show_plots=False, alpha=0.95, ensemble=ensemble, output='stats') percentages = stats['Percentages'] - ranking = np.argsort(percentages.values()) - ranked_percentages_temp = [percentages.values()[r] for r in ranking] - ranked_PIDs = [percentages.keys()[r] for r in ranking] + ranking = np.argsort(list(percentages.values())) + ranked_percentages_temp = [list(percentages.values())[r] for r in ranking] + ranked_PIDs = [list(percentages.keys())[r] for r in ranking] ranked_percentages = list() ranked_truths = list() @@ -294,7 +294,7 @@

Source code for WORC.plotting.plot_ranked_scores

if output_csv is not None: print("Writing output scores to CSV.") header = ['PatientID', 'TrueLabel', 'Percentage'] - with open(output_csv, 'wb') as csv_file: + with open(output_csv, 'w') as csv_file: writer = csv.writer(csv_file) writer.writerow(header) @@ -313,12 +313,12 @@

Source code for WORC.plotting.plot_ranked_scores

print(images) label_data, images =\ lp.findlabeldata(pinfo, - [[label_type]], + [label_type], images, images) _, segmentations =\ lp.findlabeldata(pinfo, - [[label_type]], + [label_type], segmentations, segmentations) @@ -362,7 +362,9 @@

Source code for WORC.plotting.plot_ranked_scores

im = sitk.ReadImage(images[idx]) seg = sitk.ReadImage(segmentations[idx]) pid = PIDs_images[idx] - fname = str(int(ranked_scores[idx])) + '_' + pid + '_TrueLabel_' + str(ranked_truths[idx]) + '_slice.png' + fname = str(abs(int(ranked_scores[idx]))) + '_' + pid + '_TrueLabel_' + str(ranked_truths[idx]) + '_slice.png' + if int(ranked_scores[idx]) < 0: + fname = 'min' + fname if output_zip is not None: output_name = os.path.join(os.path.dirname(output_zip), fname) @@ -401,7 +403,7 @@

Source code for WORC.plotting.plot_ranked_scores

y_truths, y_scores, y_predictions, PIDs_scores =\ plot_SVM(prediction, pinfo, - label_type, + [label_type], show_plots=False, alpha=0.95, ensemble=ensemble, @@ -429,8 +431,8 @@

Source code for WORC.plotting.plot_ranked_scores

if len(scores[pid]) > maxlen: maxlen = len(scores[pid]) - ranking = np.argsort(scores_means.values()) - ranked_PIDs = [scores_means.keys()[r] for r in ranking] + ranking = np.argsort(list(scores_means.values())) + ranked_PIDs = [list(scores_means.keys())[r] for r in ranking] ranked_mean_scores = [scores_means[r] for r in ranked_PIDs] ranked_scores = [scores[r] for r in ranked_PIDs] @@ -443,7 +445,7 @@

Source code for WORC.plotting.plot_ranked_scores

for i in range(0, maxlen): header.append('Score' + str(i+1)) - with open(output_csv, 'wb') as csv_file: + with open(output_csv, 'w') as csv_file: writer = csv.writer(csv_file) writer.writerow(header) diff --git a/WORC/doc/_build/html/_modules/WORC/plotting/scatterplot.html b/WORC/doc/_build/html/_modules/WORC/plotting/scatterplot.html new file mode 100644 index 00000000..2ec29007 --- /dev/null +++ b/WORC/doc/_build/html/_modules/WORC/plotting/scatterplot.html @@ -0,0 +1,317 @@ + + + + + + + + + + + WORC.plotting.scatterplot — WORC 3.1.0 documentation + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+ + + +
+ + + + + +
+ +
+ + + + + + + + + + + + + + + + + +
+ +
    + +
  • Docs »
  • + +
  • Module code »
  • + +
  • WORC.plotting.scatterplot
  • + + +
  • + +
  • + +
+ + +
+
+
+
+ +

Source code for WORC.plotting.scatterplot

+#!/usr/bin/env python
+
+# Copyright 2016-2019 Biomedical Imaging Group Rotterdam, Departments of
+# Medical Informatics and Radiology, Erasmus MC, Rotterdam, The Netherlands
+#
+# 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.
+
+try:
+    import matplotlib.pyplot as plt
+except ImportError:
+    print("[WORC Warning] Cannot use scatterplot function, as _tkinter is not installed")
+
+import pandas as pd
+import argparse
+import WORC.processing.label_processing as lp
+import os
+import glob
+from natsort import natsorted
+
+
+
[docs]def main(): + parser = argparse.ArgumentParser(description='Radiomics results') + parser.add_argument('-feat', '--feat', metavar='feat', + nargs='+', dest='feat', type=str, required=True, + help='List of patient feature files (HDF)') + parser.add_argument('-class', '--class', metavar='class', + nargs='+', dest='classs', type=str, required=True, + help='Classification of patients (text)') + parser.add_argument('-lab', '--lab', metavar='lab', + nargs='+', dest='lab', type=str, required=True, + help='Label of two features to plot') + parser.add_argument('-out', '--out', metavar='out', + nargs='+', dest='out', type=str, required=True, + help='Output png file') + args = parser.parse_args() + + if type(args.classs) is list: + args.classs = ''.join(args.classs) + + if type(args.out) is list: + args.out = ''.join(args.out) + + if type(args.feat) is list and len(args.feat) == 1: + args.feat = ''.join(args.feat) + + if os.path.isdir(args.feat): + args.feat = glob.glob(args.feat + '/features_*.hdf5') + args.feat = natsorted(args.feat) + + make_scatterplot(args.feat, args.classs, args.lab[0], args.lab[1], + args.out)
+ + +
[docs]def make_scatterplot(features, label_file, feature_label_1, feature_label_2, + output): + # Read and stack the features + featname = [feature_label_1, feature_label_2] + image_features_temp = list() + for i_feat in range(len(features)): + feat_temp = pd.read_hdf(features[i_feat]) + feat_temp = {k: v for k, v in zip(feat_temp.feature_labels, feat_temp.feature_values) if k in featname} + image_features_temp.append(feat_temp) + + # Get the mutation labels and patient IDs + mutation_type = [['MDM2']] + mutation_data, image_features = gp.findmutationdata(label_file, + mutation_type, + features, + image_features_temp) + + image_features = image_features.tolist() + # Select the two relevant features + feat1_c0 = list() + feat2_c0 = list() + feat1_c1 = list() + feat2_c1 = list() + mutation_label = mutation_data['label'].tolist()[0] + patient_IDs = mutation_data['patient_IDs'].tolist() + + for imfeat, label, pid in zip(image_features, mutation_label, patient_IDs): + if label[0] == 0: + feat1_c0.append(imfeat[feature_label_1]) + feat2_c0.append(imfeat[feature_label_2]) + else: + feat1_c1.append(imfeat[feature_label_1]) + feat2_c1.append(imfeat[feature_label_2]) + + # Make a scatter plot + f = plt.figure() + subplot = f.add_subplot(111) + subplot.plot(feat1_c0, feat2_c0, linestyle='', ms=12, marker='o', color='navy') + subplot.plot(feat1_c1, feat2_c1, linestyle='', ms=12, marker='x', color='red') + # NOTE: arbitrary limits! + # plt.xlim([0, 10]) + # plt.ylim([0, 10]) + plt.xlabel(feature_label_1) + plt.ylabel(feature_label_2) + plt.title('Feature scatter plot') + plt.legend() + # plt.show() + + f.savefig(output) + print(("Scatterplot saved as {} !").format(output))
+ + +if __name__ == '__main__': + main() +
+ +
+ +
+
+ + +
+ +
+

+ © Copyright 2016 -- 2019, Biomedical Imaging Group Rotterdam, Departments of Medical Informatics and Radiology, Erasmus MC, Rotterdam, The Netherlands + +

+
+ Built with Sphinx using a theme provided by Read the Docs. + +
+ +
+
+ +
+ +
+ + + + + + + + + + + + \ No newline at end of file diff --git a/WORC/doc/_build/html/_modules/WORC/processing/ExtractNLargestBlobsn.html b/WORC/doc/_build/html/_modules/WORC/processing/ExtractNLargestBlobsn.html index 7fa9e83f..c78f0d0a 100644 --- a/WORC/doc/_build/html/_modules/WORC/processing/ExtractNLargestBlobsn.html +++ b/WORC/doc/_build/html/_modules/WORC/processing/ExtractNLargestBlobsn.html @@ -8,7 +8,7 @@ - WORC.processing.ExtractNLargestBlobsn — WORC 3.0.0 documentation + WORC.processing.ExtractNLargestBlobsn — WORC 3.1.0 documentation @@ -59,7 +59,7 @@
- 3.0.0 + 3.1.0
diff --git a/WORC/doc/_build/html/_modules/WORC/processing/classes.html b/WORC/doc/_build/html/_modules/WORC/processing/classes.html index 0cf4b11d..fd8bd7f7 100644 --- a/WORC/doc/_build/html/_modules/WORC/processing/classes.html +++ b/WORC/doc/_build/html/_modules/WORC/processing/classes.html @@ -8,7 +8,7 @@ - WORC.processing.classes — WORC 3.0.0 documentation + WORC.processing.classes — WORC 3.1.0 documentation @@ -59,7 +59,7 @@
- 3.0.0 + 3.1.0
diff --git a/WORC/doc/_build/html/_modules/WORC/processing/label_processing.html b/WORC/doc/_build/html/_modules/WORC/processing/label_processing.html index ccc4d2bb..e3d2d890 100644 --- a/WORC/doc/_build/html/_modules/WORC/processing/label_processing.html +++ b/WORC/doc/_build/html/_modules/WORC/processing/label_processing.html @@ -8,7 +8,7 @@ - WORC.processing.label_processing — WORC 3.0.0 documentation + WORC.processing.label_processing — WORC 3.1.0 documentation @@ -59,7 +59,7 @@
- 3.0.0 + 3.1.0
@@ -195,6 +195,9 @@

Source code for WORC.processing.label_processing

dict: A dict containing 'patient_IDs', 'label' and 'label_type' """ + if not os.path.exists(label_file): + raise ae.WORCKeyError(f'File {label_file} does not exist!') + _, extension = os.path.splitext(label_file) if extension == '.txt': label_names, patient_IDs, label_status = load_label_txt( diff --git a/WORC/doc/_build/html/_modules/WORC/resources/fastr_tests/CalcFeatures_test.html b/WORC/doc/_build/html/_modules/WORC/resources/fastr_tests/CalcFeatures_test.html index 3c5f455b..08d9be76 100644 --- a/WORC/doc/_build/html/_modules/WORC/resources/fastr_tests/CalcFeatures_test.html +++ b/WORC/doc/_build/html/_modules/WORC/resources/fastr_tests/CalcFeatures_test.html @@ -8,7 +8,7 @@ - WORC.resources.fastr_tests.CalcFeatures_test — WORC 3.0.0 documentation + WORC.resources.fastr_tests.CalcFeatures_test — WORC 3.1.0 documentation @@ -59,7 +59,7 @@
- 3.0.0 + 3.1.0
diff --git a/WORC/doc/_build/html/_modules/WORC/resources/fastr_tests/elastix_test.html b/WORC/doc/_build/html/_modules/WORC/resources/fastr_tests/elastix_test.html index 346940f6..31f51e1d 100644 --- a/WORC/doc/_build/html/_modules/WORC/resources/fastr_tests/elastix_test.html +++ b/WORC/doc/_build/html/_modules/WORC/resources/fastr_tests/elastix_test.html @@ -8,7 +8,7 @@ - WORC.resources.fastr_tests.elastix_test — WORC 3.0.0 documentation + WORC.resources.fastr_tests.elastix_test — WORC 3.1.0 documentation @@ -59,7 +59,7 @@
- 3.0.0 + 3.1.0
diff --git a/WORC/doc/_build/html/_modules/WORC/resources/fastr_tests/segmentix_test.html b/WORC/doc/_build/html/_modules/WORC/resources/fastr_tests/segmentix_test.html index 02048499..4b87a655 100644 --- a/WORC/doc/_build/html/_modules/WORC/resources/fastr_tests/segmentix_test.html +++ b/WORC/doc/_build/html/_modules/WORC/resources/fastr_tests/segmentix_test.html @@ -8,7 +8,7 @@ - WORC.resources.fastr_tests.segmentix_test — WORC 3.0.0 documentation + WORC.resources.fastr_tests.segmentix_test — WORC 3.1.0 documentation @@ -59,7 +59,7 @@
- 3.0.0 + 3.1.0
diff --git a/WORC/doc/_build/html/_modules/WORC/tools/Elastix.html b/WORC/doc/_build/html/_modules/WORC/tools/Elastix.html index c17742a1..9fd6a680 100644 --- a/WORC/doc/_build/html/_modules/WORC/tools/Elastix.html +++ b/WORC/doc/_build/html/_modules/WORC/tools/Elastix.html @@ -8,7 +8,7 @@ - WORC.tools.Elastix — WORC 3.0.0 documentation + WORC.tools.Elastix — WORC 3.1.0 documentation @@ -59,7 +59,7 @@
- 3.0.0 + 3.1.0
@@ -175,6 +175,7 @@

Source code for WORC.tools.Elastix

 
 import SimpleITK as sitk
 import fastr
+from fastr.api import ResourceLimit
 import numpy as np
 import os
 import WORC.addexceptions as WORCexceptions
@@ -245,20 +246,20 @@ 

Source code for WORC.tools.Elastix

 
[docs] def create_network(self, nettype): if nettype == 'pairwise': # Create the network - self.network = fastr.Network(id_="elastix_pair") + self.network = fastr.create_network(id="elastix_pair") # Create Sources - self.FixedImageSource = self.network.create_source('ITKImageFile', id_='FixedImage') - self.FixedMaskSource = self.network.create_source('ITKImageFile', id_='FixedMask') - self.MovingImageSource = self.network.create_source('ITKImageFile', id_='MovingImage') - self.MovingMaskSource = self.network.create_source('ITKImageFile', id_='MovingMask') - self.ToTransformSource = self.network.create_source('ITKImageFile', id_='ToTransform') - self.ParameterMapSource = self.network.create_source('ElastixParameterFile', id_='ParameterMaps', nodegroup='par') + self.FixedImageSource = self.network.create_source('ITKImageFile', id='FixedImage') + self.FixedMaskSource = self.network.create_source('ITKImageFile', id='FixedMask') + self.MovingImageSource = self.network.create_source('ITKImageFile', id='MovingImage') + self.MovingMaskSource = self.network.create_source('ITKImageFile', id='MovingMask') + self.ToTransformSource = self.network.create_source('ITKImageFile', id='ToTransform') + self.ParameterMapSource = self.network.create_source('ElastixParameterFile', id='ParameterMaps', node_group='par') # Elastix requires the output folder as a sink # self.OutputFolderSource = self.network.create_sink('Directory', id_='Out') # Create Elastix node and links - self.elastix_node = self.network.create_node(self.elastix_toolname, id_='elastix') + self.elastix_node = self.network.create_node('self.elastix_toolname', tool_version='unknown', id='elastix') self.elastix_node.inputs['fixed_image'] = self.FixedImageSource.output self.elastix_node.inputs['fixed_mask'] = self.FixedMaskSource.output self.elastix_node.inputs['moving_image'] = self.MovingImageSource.output @@ -268,48 +269,48 @@

Source code for WORC.tools.Elastix

             self.link_param.collapse = 'par'
 
             # Create Sinks
-            self.outtrans = self.network.create_sink('ElastixTransformFile', id_='sink_trans')
-            self.outimage = self.network.create_sink('ITKImageFile', id_='sink_image')
-            self.outseg = self.network.create_sink('ITKImageFile', id_='sink_seg')
+            self.outtrans = self.network.create_sink('ElastixTransformFile', id='sink_trans')
+            self.outimage = self.network.create_sink('ITKImageFile', id='sink_image')
+            self.outseg = self.network.create_sink('ITKImageFile', id='sink_seg')
             self.outtrans.inputs['input'] = self.elastix_node.outputs['transform']
 
             # Transform output image
-            self.transformix_node = self.network.create_node(self.transformix_toolname, id_='transformix')
+            self.transformix_node = self.network.create_node('self.transformix_toolname', tool_version='unknown', id='transformix')
             self.transformix_node.inputs['image'] = self.MovingImageSource.output
             self.transformix_node.inputs['transform'] = self.elastix_node.outputs['transform'][-1]
             self.outimage.inputs['input'] = self.transformix_node.outputs['image']
 
             # First change the FinalBSplineInterpolationOrder to  0 for the segmentation
-            self.changeorder_node = self.network.create_node('EditElastixTransformFile', id_='editelpara')
+            self.changeorder_node = self.network.create_node('elastixtools/EditElastixTransformFile:0.1', tool_version='0.1', id='editelpara')
             self.link_trans = self.network.create_link(self.elastix_node.outputs['transform'][-1], self.changeorder_node.inputs['transform'])
             # self.link_trans.converge = 0
             # self.link_trans.collapse = 'FixedImage'
             # self.link_trans.expand = True
 
             # Co[y metadata from image to segmentation as Elastix uses this
-            self.copymetadata_node = self.network.create_node('CopyMetadata', id_='copymetadata')
+            self.copymetadata_node = self.network.create_node('itktools/0.3.2/CopyMetadata:1.0', tool_version='1.0', id='copymetadata')
             self.copymetadata_node.inputs['source'] = self.MovingImageSource.output
             self.copymetadata_node.inputs['destination'] = self.ToTransformSource.output
 
             # Then transform the segmentation
-            self.transformix_node_seg = self.network.create_node(self.transformix_toolname, id_='transformix_seg')
+            self.transformix_node_seg = self.network.create_node('self.transformix_toolname', tool_version='unknown', id='transformix_seg')
             self.transformix_node_seg.inputs['image'] = self.copymetadata_node.outputs['output']
             self.transformix_node_seg.inputs['transform'] = self.changeorder_node.outputs['transform'][-1]
             self.outseg.inputs['input'] = self.transformix_node_seg.outputs['image']
         else:
             # Create the network
-            self.network = fastr.Network(id_="elastix_group")
+            self.network = fastr.create_network(id="elastix_group")
 
             # Create Sources
-            self.FixedImageSource = self.network.create_source('ITKImageFile', id_='FixedImage')
-            self.FixedMaskSource = self.network.create_source('ITKImageFile', id_='FixedMask')
-            self.ToTransformSource = self.network.create_source('ITKImageFile', id_='ToTransform')
-            self.ParameterMapSource = self.network.create_source('ElastixParameterFile', id_='ParameterMaps', nodegroup='par')
+            self.FixedImageSource = self.network.create_source('ITKImageFile', id='FixedImage')
+            self.FixedMaskSource = self.network.create_source('ITKImageFile', id='FixedMask')
+            self.ToTransformSource = self.network.create_source('ITKImageFile', id='ToTransform')
+            self.ParameterMapSource = self.network.create_source('ElastixParameterFile', id='ParameterMaps', node_group='par')
             # Elastix requires the output folder as a sink
             # self.OutputFolderSource = self.network.create_sink('Directory', id_='Out')
 
             # Create Elastix node and links
-            self.elastix_node = self.network.create_node(self.elastix_toolname, id_='elastix')
+            self.elastix_node = self.network.create_node('self.elastix_toolname', tool_version='unknown', id='elastix')
             self.elastix_node.inputs['fixed_image'] = self.FixedImageSource.output
             self.elastix_node.inputs['fixed_mask'] = self.FixedMaskSource.output
             self.elastix_node.inputs['moving_image'] = self.FixedImageSource.output
@@ -319,19 +320,19 @@ 

Source code for WORC.tools.Elastix

             self.link_param.collapse = 'par'
 
             # Create Sinks
-            self.outtrans = self.network.create_sink('ElastixTransformFile', id_='sink_trans')
-            self.outimage = self.network.create_sink('ITKImageFile', id_='sink_image')
-            self.outseg = self.network.create_sink('ITKImageFile', id_='sink_seg')
+            self.outtrans = self.network.create_sink('ElastixTransformFile', id='sink_trans')
+            self.outimage = self.network.create_sink('ITKImageFile', id='sink_image')
+            self.outseg = self.network.create_sink('ITKImageFile', id='sink_seg')
             self.outtrans.inputs['input'] = self.elastix_node.outputs['transform']
 
             # Transform output image
-            self.transformix_node = self.network.create_node(self.transformix_toolname, id_='transformix')
+            self.transformix_node = self.network.create_node('self.transformix_toolname', tool_version='unknown', id='transformix')
             self.transformix_node.inputs['image'] = self.MovingImageSource.output
             self.transformix_node.inputs['transform'] = self.elastix_node.outputs['transform'][-1]
             self.outimage.inputs['input'] = self.transformix_node.outputs['image']
 
             # First change the FinalBSplineInterpolationOrder to  0 for the segmentation
-            self.changeorder_node = self.network.create_node('EditElastixTransformFile', id_='editelpara')
+            self.changeorder_node = self.network.create_node('elastixtools/EditElastixTransformFile:0.1', tool_version='0.1', id='editelpara')
             self.changeorder_node.inputs['set'] = ["FinalBSplineInterpolationOrder=0"]
             self.link_trans = self.network.create_link(self.elastix_node.outputs['transform'], self.changeorder_node.inputs['transform'][-1])
             # self.link_trans.converge = 0
@@ -339,12 +340,12 @@ 

Source code for WORC.tools.Elastix

             # self.link_trans.expand = True
 
             # Co[y metadata from image to segmentation as Elastix uses this
-            self.copymetadata_node = self.network.create_node('CopyMetadata', id_='copymetadata')
+            self.copymetadata_node = self.network.create_node('itktools/0.3.2/CopyMetadata:1.0', tool_version='1.0', id='copymetadata')
             self.copymetadata_node.inputs['source'] = self.MovingImageSource.output
             self.copymetadata_node.inputs['destination'] = self.ToTransformSource.output
 
             # Then transform the segmentation
-            self.transformix_node_seg = self.network.create_node(self.transformix_toolname, id_='transformix_seg')
+            self.transformix_node_seg = self.network.create_node('self.transformix_toolname', tool_version='unknown', id='transformix_seg')
             self.transformix_node_seg.inputs['image'] = self.copymetadata_node.outputs['output']
             self.transformix_node_seg.inputs['transform'] = self.changeorder_node.outputs['transform'][-1]
             self.outseg.inputs['input'] = self.transformix_node_seg.outputs['image']
@@ -463,7 +464,7 @@

Source code for WORC.tools.Elastix

         # print self.sink_data['Out']
 
         # Execute the network
-        self.network.draw_network('WORC_Elastix', img_format='svg', draw_dimension=True)
+        self.network.draw(file_path='WORC_Elastix.svg', img_format='svg')
         self.network.dumpf('{}.json'.format(self.network.id), indent=2)
         self.network.execute(self.source_data, self.sink_data, tmpdir=self.fastr_tmpdir)
diff --git a/WORC/doc/_build/html/_modules/WORC/tools/Evaluate.html b/WORC/doc/_build/html/_modules/WORC/tools/Evaluate.html index c50036b2..43dc2f59 100644 --- a/WORC/doc/_build/html/_modules/WORC/tools/Evaluate.html +++ b/WORC/doc/_build/html/_modules/WORC/tools/Evaluate.html @@ -8,7 +8,7 @@ - WORC.tools.Evaluate — WORC 3.0.0 documentation + WORC.tools.Evaluate — WORC 3.1.0 documentation @@ -59,7 +59,7 @@
- 3.0.0 + 3.1.0
@@ -175,15 +175,17 @@

Source code for WORC.tools.Evaluate

 
 import WORC.addexceptions as WORCexceptions
 import fastr
+from fastr.api import ResourceLimit
 import os
+import graphviz
 
 # NOTE: Very important to give images and segmentations as dict with patient names!
 
 
 
[docs]class Evaluate(object):
[docs] def __init__(self, label_type, ensemble=50, scores='percentages', - network=None, features=None, - fastr_plugin='ProcessPoolExecution', + parent=None, features=None, + fastr_plugin='LinearExecution', name='Example'): ''' Build a network that evaluates the performance of an estimator. @@ -196,23 +198,26 @@

Source code for WORC.tools.Evaluate

                 to the existing network.
 
         '''
-        if network is not None:
-            self.network = network
+        if parent is not None:
+            self.parent = parent
+            self.network = parent.network
             self.mode = 'WORC'
+            self.name = parent.network.id
+            self.ensemble = parent.configs[0]['Ensemble']['Use']
         else:
             self.mode = 'StandAlone'
             self.fastr_plugin = fastr_plugin
             self.name = 'WORC_Evaluate_' + name
-            self.network = fastr.Network(id_=self.name)
+            self.network = fastr.create_network(id=self.name)
             self.fastr_tmpdir = os.path.join(fastr.config.mounts['tmp'], self.name)
+            self.ensemble = ensemble
 
         if features is None and self.mode == 'StandAlone':
-            raise WORCexceptions.IOError('Either features as input or a WORC network is required for the Evaluate network.')
+            raise WORCexceptions.WORCIOError('Either features as input or a WORC network is required for the Evaluate network.')
 
         self.features = features
 
         self.label_type = label_type
-        self.ensemble = ensemble
 
         self.create_network()
@@ -222,141 +227,200 @@

Source code for WORC.tools.Evaluate

         '''
 
         # Create all nodes
-        self.network.node_ROC =\
-            self.network.create_node('PlotROC', memory='20G', id_='plot_ROC')
-        self.network.node_SVM =\
-            self.network.create_node('PlotSVM', memory='20G', id_='plot_SVM')
-        self.network.node_Barchart =\
-            self.network.create_node('PlotBarchart', memory='4G', id_='plot_Barchart')
-        self.network.node_STest =\
-            self.network.create_node('StatisticalTestFeatures', memory='4G', id_='statistical_test_features')
-        self.network.node_Ranked_Percentages =\
-            self.network.create_node('PlotRankedScores', memory='20G', id_='plot_ranked_percentages')
-        self.network.node_Ranked_Posteriors =\
-            self.network.create_node('PlotRankedScores', memory='20G', id_='plot_ranked_posteriors')
+        self.node_ROC =\
+            self.network.create_node('worc/PlotROC:1.0', tool_version='1.0', id='plot_ROC', resources=ResourceLimit(memory='20G'))
+        self.node_SVM =\
+            self.network.create_node('worc/PlotSVM:1.0', tool_version='1.0', id='plot_SVM', resources=ResourceLimit(memory='20G'))
+        self.node_Barchart =\
+            self.network.create_node('worc/PlotBarchart:1.0', tool_version='1.0', id='plot_Barchart', resources=ResourceLimit(memory='4G'))
+        self.node_STest =\
+            self.network.create_node('worc/StatisticalTestFeatures:1.0', tool_version='1.0', id='statistical_test_features', resources=ResourceLimit(memory='4G'))
+        self.node_Ranked_Percentages =\
+            self.network.create_node('worc/PlotRankedScores:1.0', tool_version='1.0', id='plot_ranked_percentages', resources=ResourceLimit(memory='20G'))
+        self.node_Ranked_Posteriors =\
+            self.network.create_node('worc/PlotRankedScores:1.0', tool_version='1.0', id='plot_ranked_posteriors', resources=ResourceLimit(memory='20G'))
 
         # Create sinks
-        self.network.sink_ROC_PNG =\
-            self.network.create_sink('PNGFile', id_='ROC_PNG')
-        self.network.sink_ROC_Tex =\
-            self.network.create_sink('TexFile', id_='ROC_Tex')
-        self.network.sink_ROC_CSV =\
-            self.network.create_sink('CSVFile', id_='ROC_CSV')
-
-        self.network.sink_SVM_Json =\
-            self.network.create_sink('JsonFile', id_='SVM_Json')
-
-        self.network.sink_Barchart_PNG =\
-            self.network.create_sink('PNGFile', id_='Barchart_PNG')
-        self.network.sink_Barchart_Tex =\
-            self.network.create_sink('TexFile', id_='Barchart_Tex')
-
-        self.network.sink_STest_CSV =\
-            self.network.create_sink('CSVFile', id_='StatisticalTestFeatures_CSV')
-
-        self.network.sink_Ranked_Percentages_Zip =\
-            self.network.create_sink('ZipFile', id_='RankedPercentages_Zip')
-        self.network.sink_Ranked_Percentages_CSV =\
-            self.network.create_sink('CSVFile', id_='RankedPercentages_CSV')
-
-        self.network.sink_Ranked_Posteriors_Zip =\
-            self.network.create_sink('ZipFile', id_='RankedPosteriors_Zip')
-        self.network.sink_Ranked_Posteriors_CSV =\
-            self.network.create_sink('CSVFile', id_='RankedPosteriors_CSV')
+        self.sink_ROC_PNG =\
+            self.network.create_sink('PNGFile', id='ROC_PNG')
+        self.sink_ROC_Tex =\
+            self.network.create_sink('TexFile', id='ROC_Tex')
+        self.sink_ROC_CSV =\
+            self.network.create_sink('CSVFile', id='ROC_CSV')
+
+        self.sink_SVM_Json =\
+            self.network.create_sink('JsonFile', id='SVM_Json')
+
+        self.sink_Barchart_PNG =\
+            self.network.create_sink('PNGFile', id='Barchart_PNG')
+        self.sink_Barchart_Tex =\
+            self.network.create_sink('TexFile', id='Barchart_Tex')
+
+        self.sink_STest_CSV =\
+            self.network.create_sink('CSVFile', id='StatisticalTestFeatures_CSV')
+
+        self.sink_Ranked_Percentages_Zip =\
+            self.network.create_sink('ZipFile', id='RankedPercentages_Zip')
+        self.sink_Ranked_Percentages_CSV =\
+            self.network.create_sink('CSVFile', id='RankedPercentages_CSV')
+
+        self.sink_Ranked_Posteriors_Zip =\
+            self.network.create_sink('ZipFile', id='RankedPosteriors_Zip')
+        self.sink_Ranked_Posteriors_CSV =\
+            self.network.create_sink('CSVFile', id='RankedPosteriors_CSV')
 
         # Create links to sinks
-        self.network.sink_ROC_PNG.input = self.network.node_ROC.outputs['output_png']
-        self.network.sink_ROC_Tex.input = self.network.node_ROC.outputs['output_tex']
-        self.network.sink_ROC_CSV.input = self.network.node_ROC.outputs['output_csv']
+        self.sink_ROC_PNG.input = self.node_ROC.outputs['output_png']
+        self.sink_ROC_Tex.input = self.node_ROC.outputs['output_tex']
+        self.sink_ROC_CSV.input = self.node_ROC.outputs['output_csv']
 
-        self.network.sink_SVM_Json.input = self.network.node_SVM.outputs['output_json']
+        self.sink_SVM_Json.input = self.node_SVM.outputs['output_json']
 
-        self.network.sink_Barchart_PNG.input = self.network.node_Barchart.outputs['output_png']
-        self.network.sink_Barchart_Tex.input = self.network.node_Barchart.outputs['output_tex']
+        self.sink_Barchart_PNG.input = self.node_Barchart.outputs['output_png']
+        self.sink_Barchart_Tex.input = self.node_Barchart.outputs['output_tex']
 
-        self.network.sink_STest_CSV.input = self.network.node_STest.outputs['performance']
+        self.sink_STest_CSV.input = self.node_STest.outputs['performance']
 
-        self.network.sink_Ranked_Percentages_Zip.input = self.network.node_Ranked_Percentages.outputs['output_zip']
-        self.network.sink_Ranked_Percentages_CSV.input = self.network.node_Ranked_Percentages.outputs['output_csv']
+        self.sink_Ranked_Percentages_Zip.input = self.node_Ranked_Percentages.outputs['output_zip']
+        self.sink_Ranked_Percentages_CSV.input = self.node_Ranked_Percentages.outputs['output_csv']
 
-        self.network.sink_Ranked_Posteriors_Zip.input = self.network.node_Ranked_Posteriors.outputs['output_zip']
-        self.network.sink_Ranked_Posteriors_CSV.input = self.network.node_Ranked_Posteriors.outputs['output_csv']
+        self.sink_Ranked_Posteriors_Zip.input = self.node_Ranked_Posteriors.outputs['output_zip']
+        self.sink_Ranked_Posteriors_CSV.input = self.node_Ranked_Posteriors.outputs['output_csv']
 
         # Create two constant nodes
-        self.network.node_Ranked_Percentages.inputs['scores'] = ['percentages']
-        self.network.node_Ranked_Posteriors.inputs['scores'] = ['posteriors']
+        self.node_Ranked_Percentages.inputs['scores'] = ['percentages']
+        self.node_Ranked_Posteriors.inputs['scores'] = ['posteriors']
 
         # Create sources that are not in WORC and set them
-        self.network.source_LabelType = self.network.create_source('String', id_='LabelType')
-        self.network.source_Ensemble = self.network.create_source('String', id_='Ensemble')
-        self.network.source_LabelType.input = [self.label_type]
-        self.network.source_Ensemble.input = [self.ensemble]
+        # self.source_LabelType = self.network.create_source('String', id='LabelType')
+        # self.source_Ensemble = self.network.create_source('String', id='Ensemble')
+        # self.source_LabelType.input = [self.label_type]
+        # self.source_Ensemble.input = [self.ensemble]
+
+        self.source_LabelType = self.network.create_constant('String', [self.label_type], id='LabelType')
+        self.source_Ensemble = self.network.create_constant('String', [self.ensemble], id='Ensemble')
 
         # Create sources if not supplied by a WORC network
         if self.mode == 'StandAlone':
-            self.network.source_Estimator = self.network.create_source('HDF5', id_='Estimator')
-            self.network.source_PatientInfo = self.network.create_source('PatientInfoFile', id_='PatientInfo')
-            self.network.source_Images = self.network.create_source('ITKImageFile', id_='Images', nodegroup='patients')
-            self.network.source_Segmentations = self.network.create_source('ITKImageFile', id_='Segmentations', nodegroup='patients')
-            self.network.source_Config = self.network.create_source('ParameterFile', id_='Config')
+            self.source_Estimator = self.network.create_source('HDF5', id='Estimator')
+            self.source_PatientInfo = self.network.create_source('PatientInfoFile', id='PatientInfo')
+            self.source_Images = self.network.create_source('ITKImageFile', id='Images', node_group='patients')
+            self.source_Segmentations = self.network.create_source('ITKImageFile', id='Segmentations', node_group='patients')
+            self.source_Config = self.network.create_source('ParameterFile', id='Config')
 
             self.labels = list()
-            self.network.source_Features = list()
+            self.source_Features = list()
             for idx in range(0, len(self.features)):
                 label = 'Features_' + str(idx)
                 self.labels.append(label)
-                self.network.source_Features.append(self.network.create_source('HDF5', id_=label, nodegroup='features'))
+                self.source_Features.append(self.network.create_source('HDF5', id=label, node_group='features'))
 
         # Create links to sources that are not supplied by a WORC network
-        self.network.node_ROC.inputs['ensemble'] = self.network.source_Ensemble.output
-        self.network.node_ROC.inputs['label_type'] = self.network.source_LabelType.output
+        self.node_ROC.inputs['ensemble'] = self.source_Ensemble.output
+        self.node_ROC.inputs['label_type'] = self.source_LabelType.output
 
-        self.network.node_SVM.inputs['ensemble'] = self.network.source_Ensemble.output
-        self.network.node_SVM.inputs['label_type'] = self.network.source_LabelType.output
+        self.node_SVM.inputs['ensemble'] = self.source_Ensemble.output
+        self.node_SVM.inputs['label_type'] = self.source_LabelType.output
 
-        self.network.node_Barchart.inputs['estimators'] = self.network.source_Ensemble.output
-        self.network.node_Barchart.inputs['label_type'] = self.network.source_LabelType.output
+        self.node_Barchart.inputs['estimators'] = self.source_Ensemble.output
+        self.node_Barchart.inputs['label_type'] = self.source_LabelType.output
 
-        self.network.node_Ranked_Percentages.inputs['ensemble'] = self.network.source_Ensemble.output
-        self.network.node_Ranked_Percentages.inputs['label_type'] = self.network.source_LabelType.output
+        self.node_Ranked_Percentages.inputs['ensemble'] = self.source_Ensemble.output
+        self.node_Ranked_Percentages.inputs['label_type'] = self.source_LabelType.output
 
-        self.network.node_Ranked_Posteriors.inputs['ensemble'] = self.network.source_Ensemble.output
-        self.network.node_Ranked_Posteriors.inputs['label_type'] = self.network.source_LabelType.output
+        self.node_Ranked_Posteriors.inputs['ensemble'] = self.source_Ensemble.output
+        self.node_Ranked_Posteriors.inputs['label_type'] = self.source_LabelType.output
 
         # Create links to the sources that could be in a WORC network
         if self.mode == 'StandAlone':
+            self.create_links_Standalone()
+        else:
+            self.create_links_Addon()
+ + + + + prediction = self.parent.classify.outputs['classification'] + if self.parent.labels_test: + pinfo = self.parent.source_patientclass_test.output + else: + pinfo = self.parent.source_patientclass_train.output + + config = self.parent.source_class_config.output + + if self.parent.sources_images_train: + # NOTE: Use images of first modality to depict tumor + label = self.parent.modlabels[0] + images = self.parent.sources_images_train[label].output + segmentations = self.parent.sources_segmentations_train[label].output + + self.node_ROC.inputs['prediction'] = prediction + self.node_ROC.inputs['pinfo'] = pinfo + + self.node_SVM.inputs['prediction'] = prediction + self.node_SVM.inputs['pinfo'] = pinfo + + self.node_Barchart.inputs['prediction'] = prediction + + self.links_STest_Features = dict() + for idx, label in enumerate(self.parent.modlabels): + # NOTE: Currently statistical testing is only done within the training set + if self.parent.sources_images_train: + # Features are computed within the network + self.links_STest_Features[label] = self.node_STest.inputs['features'][str(label)] << self.parent.calcfeatures_train[label].outputs['features'] + else: + # Feature are precomputed and given as sources + self.links_STest_Features[label] = self.node_STest.inputs['features'][str(label)] << self.parent.sources_features_train[label].output + self.links_STest_Features[label].collapse = 'train' + + self.node_STest.inputs['patientclass'] = pinfo + self.node_STest.inputs['config'] = config + + self.node_Ranked_Percentages.inputs['estimator'] = prediction + self.node_Ranked_Percentages.inputs['pinfo'] = pinfo + self.node_Ranked_Posteriors.inputs['estimator'] = prediction + self.node_Ranked_Posteriors.inputs['pinfo'] = pinfo + + if self.parent.sources_images_train: + self.link_images_perc = self.network.create_link(images, self.node_Ranked_Percentages.inputs['images']) + self.link_images_perc.collapse = 'train' + self.link_segmentations_perc = self.network.create_link(segmentations, self.node_Ranked_Percentages.inputs['segmentations']) + self.link_segmentations_perc.collapse = 'train' + + self.link_images_post = self.network.create_link(images, self.node_Ranked_Posteriors.inputs['images']) + self.link_images_post.collapse = 'train' + self.link_segmentations_post = self.network.create_link(segmentations, self.node_Ranked_Posteriors.inputs['segmentations']) + self.link_segmentations_post.collapse = 'train'
[docs] def set(self, estimator=None, pinfo=None, images=None, segmentations=None, config=None, features=None, @@ -378,42 +442,44 @@

Source code for WORC.tools.Evaluate

 
             for feature, label in zip(features, self.labels):
                 self.source_data[label] = feature
+        else:
+            self.sink_data = self.parent.sink_data
 
-            if 'ROC_PNG' not in sink_data.keys():
-                self.sink_data['ROC_PNG'] = ("vfs://output/{}/ROC_{{sample_id}}_{{cardinality}}{{ext}}").format(self.name)
-            if 'ROC_Tex' not in sink_data.keys():
-                self.sink_data['ROC_Tex'] = ("vfs://output/{}/ROC_{{sample_id}}_{{cardinality}}{{ext}}").format(self.name)
-            if 'ROC_CSV' not in sink_data.keys():
-                self.sink_data['ROC_CSV'] = ("vfs://output/{}/ROC_{{sample_id}}_{{cardinality}}{{ext}}").format(self.name)
-
-            if 'SVM_Json' not in sink_data.keys():
-                self.sink_data['SVM_Json'] = ("vfs://output/{}/performance_{{sample_id}}_{{cardinality}}{{ext}}").format(self.name)
+        if 'ROC_PNG' not in sink_data.keys():
+            self.sink_data['ROC_PNG'] = ("vfs://output/{}/ROC_{{sample_id}}_{{cardinality}}{{ext}}").format(self.name)
+        if 'ROC_Tex' not in sink_data.keys():
+            self.sink_data['ROC_Tex'] = ("vfs://output/{}/ROC_{{sample_id}}_{{cardinality}}{{ext}}").format(self.name)
+        if 'ROC_CSV' not in sink_data.keys():
+            self.sink_data['ROC_CSV'] = ("vfs://output/{}/ROC_{{sample_id}}_{{cardinality}}{{ext}}").format(self.name)
 
-            if 'Barchart_PNG' not in sink_data.keys():
-                self.sink_data['Barchart_PNG'] = ("vfs://output/{}/Barchart_{{sample_id}}_{{cardinality}}{{ext}}").format(self.name)
-            if 'Barchart_Tex' not in sink_data.keys():
-                self.sink_data['Barchart_Tex'] = ("vfs://output/{}/Barchart_{{sample_id}}_{{cardinality}}{{ext}}").format(self.name)
+        if 'SVM_Json' not in sink_data.keys():
+            self.sink_data['SVM_Json'] = ("vfs://output/{}/performance_{{sample_id}}_{{cardinality}}{{ext}}").format(self.name)
 
-            if 'StatisticalTestFeatures_CSV' not in sink_data.keys():
-                self.sink_data['StatisticalTestFeatures_CSV'] = ("vfs://output/{}/StatisticalTestFeatures_{{sample_id}}_{{cardinality}}{{ext}}").format(self.name)
+        if 'Barchart_PNG' not in sink_data.keys():
+            self.sink_data['Barchart_PNG'] = ("vfs://output/{}/Barchart_{{sample_id}}_{{cardinality}}{{ext}}").format(self.name)
+        if 'Barchart_Tex' not in sink_data.keys():
+            self.sink_data['Barchart_Tex'] = ("vfs://output/{}/Barchart_{{sample_id}}_{{cardinality}}{{ext}}").format(self.name)
 
-            if 'RankedPercentages_Zip' not in sink_data.keys():
-                self.sink_data['RankedPercentages_Zip'] = ("vfs://output/{}/RankedPercentages_{{sample_id}}_{{cardinality}}{{ext}}").format(self.name)
-            if 'RankedPercentages_CSV' not in sink_data.keys():
-                self.sink_data['RankedPercentages_CSV'] = ("vfs://output/{}/RankedPercentages_{{sample_id}}_{{cardinality}}{{ext}}").format(self.name)
+        if 'StatisticalTestFeatures_CSV' not in sink_data.keys():
+            self.sink_data['StatisticalTestFeatures_CSV'] = ("vfs://output/{}/StatisticalTestFeatures_{{sample_id}}_{{cardinality}}{{ext}}").format(self.name)
 
-            if 'RankedPosteriors_Zip' not in sink_data.keys():
-                self.sink_data['RankedPosteriors_Zip'] = ("vfs://output/{}/RankedPosteriors_{{sample_id}}_{{cardinality}}{{ext}}").format(self.name)
-            if 'RankedPosteriors_CSV' not in sink_data.keys():
-                self.sink_data['RankedPosteriors_CSV'] = ("vfs://output/{}/RankedPosteriors_{{sample_id}}_{{cardinality}}{{ext}}").format(self.name)
+        if 'RankedPercentages_Zip' not in sink_data.keys():
+            self.sink_data['RankedPercentages_Zip'] = ("vfs://output/{}/RankedPercentages_{{sample_id}}_{{cardinality}}{{ext}}").format(self.name)
+        if 'RankedPercentages_CSV' not in sink_data.keys():
+            self.sink_data['RankedPercentages_CSV'] = ("vfs://output/{}/RankedPercentages_{{sample_id}}_{{cardinality}}{{ext}}").format(self.name)
 
-        else:
-            print('[WORC Warning] Evaluate set attribute not needed when WORC network is provided!')
+ if 'RankedPosteriors_Zip' not in sink_data.keys(): + self.sink_data['RankedPosteriors_Zip'] = ("vfs://output/{}/RankedPosteriors_{{sample_id}}_{{cardinality}}{{ext}}").format(self.name) + if 'RankedPosteriors_CSV' not in sink_data.keys(): + self.sink_data['RankedPosteriors_CSV'] = ("vfs://output/{}/RankedPosteriors_{{sample_id}}_{{cardinality}}{{ext}}").format(self.name)
[docs] def execute(self): """ Execute the network through the fastr.network.execute command. """ # Draw and execute nwtwork - self.network.draw_network(self.network.id, draw_dimension=True) + try: + self.network.draw(file_path=self.network.id + '.svg', draw_dimensions=True) + except graphviz.backend.ExecutableNotFound: + print('[WORC WARNING] Graphviz executable not found: not drawing network diagram. MAke sure the Graphviz executables are on your systems PATH.') self.network.execute(self.source_data, self.sink_data, execution_plugin=self.fastr_plugin, tmpdir=self.fastr_tmpdir)
diff --git a/WORC/doc/_build/html/_modules/WORC/tools/Slicer.html b/WORC/doc/_build/html/_modules/WORC/tools/Slicer.html index 16ce175e..86f9525f 100644 --- a/WORC/doc/_build/html/_modules/WORC/tools/Slicer.html +++ b/WORC/doc/_build/html/_modules/WORC/tools/Slicer.html @@ -8,7 +8,7 @@ - WORC.tools.Slicer — WORC 3.0.0 documentation + WORC.tools.Slicer — WORC 3.1.0 documentation @@ -59,7 +59,7 @@
- 3.0.0 + 3.1.0
@@ -175,6 +175,7 @@

Source code for WORC.tools.Slicer

 
 import WORC.addexceptions as WORCexceptions
 import fastr
+from fastr.api import ResourceLimit
 import os
 
 
@@ -201,15 +202,15 @@ 

Source code for WORC.tools.Slicer

             self.mode = 'StandAlone'
             self.fastr_plugin = fastr_plugin
             self.name = 'WORC_Slicer_' + name
-            self.network = fastr.Network(id_=self.name)
+            self.network = fastr.create_network(id=self.name)
             self.fastr_tmpdir = os.path.join(fastr.config.mounts['tmp'], self.name)
 
         if images is None and self.mode == 'StandAlone':
             message = 'Either images and segmentations as input or a WORC' +\
              'network is required for the Evaluate network.'
-            raise WORCexceptions.IOError(message)
+            raise WORCexceptions.WORCIOError(message)
 
-        self.image = images
+        self.images = images
         self.segmentations = segmentations
 
         self.create_network()
@@ -220,23 +221,23 @@

Source code for WORC.tools.Slicer

         '''
 
         # Create all nodes
-        self.network.node_slicer =\
-            self.network.create_node('Slicer', memory='20G', id_='Slicer')
+        self.node_slicer =\
+            self.network.create_node('worc/Slicer:1.0', tool_version='1.0', id='Slicer', resources=ResourceLimit(memory='20G'))
 
         # Create sinks
-        self.network.sink_PNG =\
-            self.network.create_sink('PNGFile', id_='PNG')
-        self.network.sink_PNGZoomed =\
-            self.network.create_sink('PNGFile', id_='PNGZoomed')
+        self.sink_PNG =\
+            self.network.create_sink('PNGFile', id='PNG')
+        self.sink_PNGZoomed =\
+            self.network.create_sink('PNGFile', id='PNGZoomed')
 
         # Create links to sinks
-        self.network.sink_PNG.input = self.network.node_slicer.outputs['out']
-        self.network.sink_PNGZoomed.input = self.network.node_slicer.outputs['outzoom']
+        self.sink_PNG.input = self.node_slicer.outputs['out']
+        self.sink_PNGZoomed.input = self.node_slicer.outputs['outzoom']
 
         # Create sources if not supplied by a WORC network
         if self.mode == 'StandAlone':
-            self.network.source_images = self.network.create_source('ITKImage', id_='Images')
-            self.network.source_segmentations = self.network.create_source('ITKImage', id_='Segmentations')
+            self.source_images = self.network.create_source('ITKImageFile', id='Images')
+            self.source_segmentations = self.network.create_source('ITKImageFile', id='Segmentations')
 
         # Create links to sources that are not supplied by a WORC network
         # Not needed in this network
@@ -244,8 +245,8 @@ 

Source code for WORC.tools.Slicer

         # Create links to the sources that could be in a WORC network
         if self.mode == 'StandAlone':
             # Sources from the Evaluate network are used
-            self.network.node_slicer.inputs['image'] = self.network.source_images.output
-            self.network.node_slicer.inputs['segmentation'] = self.network.source_segmentations.output
+            self.node_slicer.inputs['image'] = self.source_images.output
+            self.node_slicer.inputs['segmentation'] = self.source_segmentations.output
         else:
             # Sources from the WORC network are used
             print('WIP')
@@ -258,8 +259,8 @@

Source code for WORC.tools.Slicer

             self.source_data = dict()
             self.sink_data = dict()
 
-            self.source_data['Images'] = images
-            self.source_data['Segmentations'] = segmentations
+            self.source_data['Images'] = self.images
+            self.source_data['Segmentations'] = self.segmentations
 
             if 'PNG' not in sink_data.keys():
                 self.sink_data['PNG'] = ("vfs://output/{}/Slice_{{sample_id}}_{{cardinality}}{{ext}}").format(self.name)
@@ -272,7 +273,7 @@ 

Source code for WORC.tools.Slicer

 
[docs] def execute(self): """ Execute the network through the fastr.network.execute command. """ # Draw and execute nwtwork - self.network.draw_network(self.network.id, draw_dimension=True) + self.network.draw(file_path=self.network.id + '.svg', draw_dimensions=True) self.network.execute(self.source_data, self.sink_data, execution_plugin=self.fastr_plugin, tmpdir=self.fastr_tmpdir)
diff --git a/WORC/doc/_build/html/_modules/WORC/tools/Transformix.html b/WORC/doc/_build/html/_modules/WORC/tools/Transformix.html index 012fb4e9..da161325 100644 --- a/WORC/doc/_build/html/_modules/WORC/tools/Transformix.html +++ b/WORC/doc/_build/html/_modules/WORC/tools/Transformix.html @@ -8,7 +8,7 @@ - WORC.tools.Transformix — WORC 3.0.0 documentation + WORC.tools.Transformix — WORC 3.1.0 documentation @@ -59,7 +59,7 @@
- 3.0.0 + 3.1.0
@@ -175,6 +175,7 @@

Source code for WORC.tools.Transformix

 
 import SimpleITK as sitk
 import fastr
+from fastr.api import ResourceLimit
 import numpy as np
 import os
 import WORC.addexceptions as WORCexceptions
@@ -188,19 +189,19 @@ 

Source code for WORC.tools.Transformix

         self.TransformParameterMap = None
[docs] def create_network(self): - self.network = fastr.Network(id_="transformix") + self.network = fastr.create_network(id="transformix") - self.MovingImageSource = self.network.create_source('ITKImageFile', id_='MovingImage') - self.ParameterMapSource = self.network.create_source('ElastixTransformFile', id_='ParameterFile') + self.MovingImageSource = self.network.create_source('ITKImageFile', id='MovingImage') + self.ParameterMapSource = self.network.create_source('ElastixTransformFile', id='ParameterFile') - self.transformix_node = self.network.create_node('transformix_dev', id_='transformix') + self.transformix_node = self.network.create_node('elastix_dev/transformix_dev:4.9-dev-wyke', tool_version='0.2', id='transformix') self.transformix_node.inputs['image'] = self.MovingImageSource.output self.transformix_node.inputs['transform'] = self.ParameterMapSource.output - self.outimage = self.network.create_sink('ITKImageFile', id_='sink_image') + self.outimage = self.network.create_sink('ITKImageFile', id='sink_image') self.outimage.inputs['input'] = self.transformix_node.outputs['image'] - self.network.draw_network(img_format='svg') + self.network.draw(file_path='transformix.svg') self.network.dumpf('{}.json'.format(self.network.id), indent=2)
[docs] def execute(self): diff --git a/WORC/doc/_build/html/_modules/WORC/tools/createfixedsplits.html b/WORC/doc/_build/html/_modules/WORC/tools/createfixedsplits.html new file mode 100644 index 00000000..a7a37ed3 --- /dev/null +++ b/WORC/doc/_build/html/_modules/WORC/tools/createfixedsplits.html @@ -0,0 +1,327 @@ + + + + + + + + + + + WORC.tools.createfixedsplits — WORC 3.1.0 documentation + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+ + + +
+ + + + + +
+ +
+ + + + + + + + + + + + + + + + + +
+ +
    + +
  • Docs »
  • + +
  • Module code »
  • + +
  • WORC.tools.createfixedsplits
  • + + +
  • + +
  • + +
+ + +
+
+
+
+ +

Source code for WORC.tools.createfixedsplits

+#!/usr/bin/env python
+
+# Copyright 2016-2019 Biomedical Imaging Group Rotterdam, Departments of
+# Medical Informatics and Radiology, Erasmus MC, Rotterdam, The Netherlands
+#
+# 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 numpy as np
+from sklearn.model_selection import train_test_split
+import WORC.addexceptions as ae
+from WORC.processing.label_processing import load_labels
+import pandas as pd
+
+
+
[docs]def createfixedsplits(label_file=None, label_type=None, patient_IDs=None, + test_size=0.2, N_iterations=1, regression=False, + stratify=None, modus='singlelabel', output=None): + ''' + Create fixed splits for a cross validation. + ''' + # Check whether input is valid + if patient_IDs is None: + if label_file is not None and label_type is not None: + # Read the label file + label_data = load_labels(label_file, label_type) + patient_IDs = label_data['patient_IDs'] + + # Create the stratification object + if modus == 'singlelabel': + stratify = label_data['label'] + elif modus == 'multilabel': + # Create a stratification object from the labels + # Label = 0 means no label equals one + # Other label numbers refer to the label name that is 1 + stratify = list() + labels = label_data['label'] + for pnum in range(0, len(labels[0])): + plabel = 0 + for lnum, slabel in enumerate(labels): + if slabel[pnum] == 1: + plabel = lnum + 1 + stratify.append(plabel) + + else: + raise ae.WORCKeyError('{} is not a valid modus!').format(modus) + else: + raise ae.WORCIOError('Either a label file and label type or patient_IDs need to be provided!') + + pd_dict = dict() + for i in range(N_iterations): + print(f'Splitting iteration {i + 1} / {N_iterations}') + # Create a random seed for the splitting + random_seed = np.random.randint(5000) + + # Define stratification + unique_patient_IDs, unique_indices =\ + np.unique(np.asarray(patient_IDs), return_index=True) + if regression: + unique_stratify = None + else: + unique_stratify = [stratify[i] for i in unique_indices] + + # Split, throw error when dataset is too small for split ratio's + try: + unique_PID_train, indices_PID_test\ + = train_test_split(unique_patient_IDs, + test_size=test_size, + random_state=random_seed, + stratify=unique_stratify) + except ValueError as e: + e = str(e) + ' Increase the size of your test set.' + raise ae.WORCValueError(e) + + # Check for all IDs if they are in test or training + indices_train = list() + indices_test = list() + patient_ID_train = list() + patient_ID_test = list() + for num, pid in enumerate(patient_IDs): + if pid in unique_PID_train: + indices_train.append(num) + + # Make sure we get a unique ID + if pid in patient_ID_train: + n = 1 + while str(pid + '_' + str(n)) in patient_ID_train: + n += 1 + pid = str(pid + '_' + str(n)) + patient_ID_train.append(pid) + else: + indices_test.append(num) + + # Make sure we get a unique ID + if pid in patient_ID_test: + n = 1 + while str(pid + '_' + str(n)) in patient_ID_test: + n += 1 + pid = str(pid + '_' + str(n)) + patient_ID_test.append(pid) + + # Add to train object + pd_dict[str(i) + '_train'] = patient_ID_train + + # Test object has to be same length as training object + extras = [""]*(len(patient_ID_train) - len(patient_ID_test)) + patient_ID_test.extend(extras) + pd_dict[str(i) + '_test'] = patient_ID_test + + # Convert into pandas dataframe for easy use and conversion + df = pd.DataFrame(pd_dict) + + # Write output if required + if output is not None: + print("Writing Output.") + df.to_csv(output) + + return df
+
+ +
+ +
+
+ + +
+ +
+

+ © Copyright 2016 -- 2019, Biomedical Imaging Group Rotterdam, Departments of Medical Informatics and Radiology, Erasmus MC, Rotterdam, The Netherlands + +

+
+ Built with Sphinx using a theme provided by Read the Docs. + +
+ +
+
+ +
+ +
+ + + + + + + + + + + + \ No newline at end of file diff --git a/WORC/doc/_build/html/_modules/fastr/api.html b/WORC/doc/_build/html/_modules/fastr/api.html index b1adf136..a42f4fe9 100644 --- a/WORC/doc/_build/html/_modules/fastr/api.html +++ b/WORC/doc/_build/html/_modules/fastr/api.html @@ -8,7 +8,7 @@ - fastr.api — WORC 3.0.0 documentation + fastr.api — WORC 3.1.0 documentation @@ -59,7 +59,7 @@
- 3.0.0 + 3.1.0
diff --git a/WORC/doc/_build/html/_modules/index.html b/WORC/doc/_build/html/_modules/index.html index 99525561..ae8a688c 100644 --- a/WORC/doc/_build/html/_modules/index.html +++ b/WORC/doc/_build/html/_modules/index.html @@ -8,7 +8,7 @@ - Overview: module code — WORC 3.0.0 documentation + Overview: module code — WORC 3.1.0 documentation @@ -59,7 +59,7 @@
- 3.0.0 + 3.1.0
@@ -162,19 +162,30 @@

All modules for which code is available

  • WORC.WORC
  • WORC.addexceptions
  • WORC.classification.AdvancedSampler
  • +
  • WORC.classification.ObjectSampler
  • WORC.classification.RankedSVM
  • WORC.classification.SearchCV
  • WORC.classification.construct_classifier
  • +
  • WORC.classification.createfixedsplits
  • WORC.classification.crossval
  • WORC.classification.estimators
  • WORC.classification.fitandscore
  • WORC.classification.metrics
  • WORC.classification.parameter_optimization
  • WORC.classification.trainclassifier
  • +
  • WORC.detectors.detectors
  • +
  • WORC.exampledata.datadownloader
  • +
  • WORC.facade.intermediatefacade.configbuilder
  • +
  • WORC.facade.intermediatefacade.exceptions
  • +
  • WORC.facade.intermediatefacade.intermediatefacade
  • +
  • WORC.facade.simpleworc.configbuilder
  • +
  • WORC.facade.simpleworc.exceptions
  • +
  • WORC.facade.simpleworc.simpleworc
  • WORC.featureprocessing.Imputer
  • WORC.featureprocessing.Relief
  • WORC.featureprocessing.SelectGroups
  • WORC.featureprocessing.SelectIndividuals
  • +
  • WORC.featureprocessing.StatisticalTestFeatures
  • WORC.featureprocessing.StatisticalTestThreshold
  • WORC.featureprocessing.VarianceThreshold
  • WORC.plotting.compute_CI
  • @@ -186,6 +197,8 @@

    All modules for which code is available

  • WORC.plotting.plot_boxplot
  • WORC.plotting.plot_images
  • WORC.plotting.plot_ranked_scores
  • +
  • WORC.plotting.plotminmaxresponse
  • +
  • WORC.plotting.scatterplot
  • WORC.processing.ExtractNLargestBlobsn
  • WORC.processing.classes
  • WORC.processing.label_processing
  • @@ -196,6 +209,7 @@

    All modules for which code is available

  • WORC.tools.Evaluate
  • WORC.tools.Slicer
  • WORC.tools.Transformix
  • +
  • WORC.tools.createfixedsplits
  • fastr.api
  • diff --git a/WORC/doc/_build/html/_sources/WORC.config.rst.txt b/WORC/doc/_build/html/_sources/WORC.config.rst.txt new file mode 100644 index 00000000..ead619d3 --- /dev/null +++ b/WORC/doc/_build/html/_sources/WORC.config.rst.txt @@ -0,0 +1,126 @@ +================= ======================== ============================================================================================================================================================================================================================================================== ========================================== ================================================================================================================================================================= +Key Subkey Description Default Options +================= ======================== ============================================================================================================================================================================================================================================================== ========================================== ================================================================================================================================================================= +General cross_validation Determine whether a cross validation will be performed or not. Obsolete, will be removed. True True, False + Segmentix Determine whether to use Segmentix tool for segmentation preprocessing. False True, False + FeatureCalculator Specifies which feature calculation tool should be used. predict/CalcFeatures:1.0 predict/CalcFeatures:1.0, pyradiomics/CF_pyradiomics:1.0, your own tool reference + Preprocessing Specifies which tool will be used for image preprocessing. worc/PreProcess:1.0 worc/PreProcess:1.0, your own tool reference + RegistrationNode Specifies which tool will be used for image registration. 'elastix4.8/Elastix:4.8' 'elastix4.8/Elastix:4.8', your own tool reference + TransformationNode Specifies which tool will be used for applying image transformations. 'elastix4.8/Transformix:4.8' 'elastix4.8/Transformix:4.8', your own tool reference + Joblib_ncores Number of cores to be used by joblib for multicore processing. 4 Integer > 0 + Joblib_backend Type of backend to be used by joblib for multicore processing. multiprocessing multiprocessing, threading + tempsave Determines whether after every cross validation iteration the result will be saved, in addition to the result after all iterations. Especially useful for debugging. False True, False +Segmentix mask If a mask is supplied, should the mask be subtracted from the contour or multiplied. subtract subtract, multiply + segtype If Ring, then a ring around the segmentation will be used as contour. None None, Ring + segradius Define the radius of the ring used if segtype is Ring. 5 Integer > 0 + N_blobs How many of the largest blobs are extracted from the segmentation. If None, no blob extraction is used. 1 Integer > 0 + fillholes Determines whether hole filling will be used. False True, False +Normalize ROI If a mask is supplied and this is set to True, normalize image based on supplied ROI. Otherwise, the full image is used for normalization using the SimpleITK Normalize function. Lastly, setting this to False will result in no normalization being applied. Full True, False, Full + Method Method used for normalization if ROI is supplied. Currently, z-scoring or using the minimum and median of the ROI can be used. z_score z_score, minmed +ImageFeatures shape Determine whether orientation features are computed or not. True True, False + histogram Determine whether histogram features are computed or not. True True, False + orientation Determine whether orientation features are computed or not. True True, False + texture_Gabor Determine whether Gabor texture features are computed or not. False True, False + texture_LBP Determine whether LBP texture features are computed or not. True True, False + texture_GLCM Determine whether GLCM texture features are computed or not. True True, False + texture_GLCMMS Determine whether GLCM Multislice texture features are computed or not. True True, False + texture_GLRLM Determine whether GLRLM texture features are computed or not. True True, False + texture_GLSZM Determine whether GLSZM texture features are computed or not. True True, False + texture_NGTDM Determine whether NGTDM texture features are computed or not. True True, False + coliage Determine whether coliage features are computed or not. False True, False + vessel Determine whether vessel features are computed or not. False True, False + log Determine whether LoG features are computed or not. False True, False + phase Determine whether local phase features are computed or not. False True, False + image_type Modality of images supplied. Determines how the image is loaded. CT CT + gabor_frequencies Frequencies of Gabor filters used: can be a single float or a list. 0.05, 0.2, 0.5 Float(s) + gabor_angles Angles of Gabor filters in degrees: can be a single integer or a list. 0, 45, 90, 135 Integer(s) + GLCM_angles Angles used in GLCM computation in radians: can be a single float or a list. 0, 0.79, 1.57, 2.36 Float(s) + GLCM_levels Number of grayscale levels used in discretization before GLCM computation. 16 Integer > 0 + GLCM_distances Distance(s) used in GLCM computation in pixels: can be a single integer or a list. 1, 3 Integer(s) > 0 + LBP_radius Radii used for LBP computation: can be a single integer or a list. 3, 8, 15 Integer(s) > 0 + LBP_npoints Number(s) of points used in LBP computation: can be a single integer or a list. 12, 24, 36 Integer(s) > 0 + phase_minwavelength Minimal wavelength in pixels used for phase features. 3 Integer > 0 + phase_nscale Number of scales used in phase feature computation. 5 Integer > 0 + log_sigma Standard deviation(s) in pixels used in log feature computation: can be a single integer or a list. 1, 5, 10 Integer(s) + vessel_scale_range Scale in pixels used for Frangi vessel filter. Given as a minimum and a maximum. 1, 10 Two integers: min and max. + vessel_scale_step Step size used to go from minimum to maximum scale on Frangi vessel filter. 2 Integer > 0 + vessel_radius Radius to determine boundary of between inner part and edge in Frangi vessel filter. 5 Integer > 0 +Featsel Variance If True, exclude features which have a variance < 0.01. Based on ` sklearn `_. True Boolean(s) + GroupwiseSearch Randomly select which feature groups to use. Parameters determined by the SelectFeatGroup config part, see below. True Boolean(s) + SelectFromModel Select features by first training a LASSO model. The alpha for the LASSO model is randomly generated. See also `sklearn `_. False Boolean(s) + UsePCA If True, Use Principle Component Analysis (PCA) to select features. False Boolean(s) + PCAType Method to select number of components using PCA: Either the number of components that explains 95% of the variance, or use a fixed number of components.95variance 95variance Inteteger(s), 95variance + StatisticalTestUse If True, use statistical test to select features. False Boolean(s) + StatisticalTestMetric Define the type of statistical test to be used. ttest, Welch, Wilcoxon, MannWhitneyU ttest, Welch, Wilcoxon, MannWhitneyU + StatisticalTestThreshold Specify a threshold for the p-value threshold used in the statistical test to select features. The first element defines the lower boundary, the other the upper boundary. Random sampling will occur between the boundaries. -2, 1.5 Two Integers: loc and scale + ReliefUse If True, use Relief to select features. False Boolean(s) + ReliefNN Min and max of number of nearest neighbors search range in Relief. 2, 4 Two Integers: loc and scale + ReliefSampleSize Min and max of sample size search range in Relief. 1, 1 Two Integers: loc and scale + ReliefDistanceP Min and max of positive distance search range in Relief. 1, 3 Two Integers: loc and scale + ReliefNumFeatures Min and max of number of features that is selected search range in Relief. 25, 200 Two Integers: loc and scale +SelectFeatGroup shape_features If True, use shape features in model. True, False Boolean(s) + histogram_features If True, use histogram features in model. True, False Boolean(s) + orientation_features If True, use orientation features in model. True, False Boolean(s) + texture_Gabor_features If True, use Gabor texture features in model. False Boolean(s) + texture_GLCM_features If True, use GLCM texture features in model. True, False Boolean(s) + texture_GLCMMS_features If True, use GLCM Multislice texture features in model. True, False Boolean(s) + texture_GLRLM_features If True, use GLRLM texture features in model. True, False Boolean(s) + texture_GLSZM_features If True, use GLSZM texture features in model. True, False Boolean(s) + texture_NGTDM_features If True, use NGTDM texture features in model. True, False Boolean(s) + texture_LBP_features If True, use LBP texture features in model. True, False Boolean(s) + patient_features If True, use patient features in model. False Boolean(s) + semantic_features If True, use semantic features in model. False Boolean(s) + coliage_features If True, use coliage features in model. False Boolean(s) + log_features If True, use log features in model. False Boolean(s) + vessel_features If True, use vessel features in model. False Boolean(s) + phase_features If True, use phase features in model. False Boolean(s) +Imputation use If True, use feature imputation methods to replace NaN values. If False, all NaN features will be set to zero. False Boolean(s) + strategy Method to be used for imputation. mean, median, most_frequent, constant, knn mean, median, most_frequent, constant, knn + n_neighbors When using k-Nearest Neighbors (kNN) for feature imputation, determines the number of neighbors used for imputation. Can be a single integer or a list. 5, 5 Two Integers: loc and scale +Classification fastr Use fastr for the optimization gridsearch (recommended on clusters, default) or if set to False , joblib (recommended for PCs but not on Windows). True True, False + fastr_plugin Name of execution plugin to be used. Default use the same as the self.fastr_plugin for the WORC object. LinearExecution Any `fastr execution plugin `_ . + classifiers Select the estimator(s) to use. Most are implemented using `sklearn `_. For abbreviations, see above. SVM SVM , SVR, SGD, SGDR, RF, LDA, QDA, ComplementND, GaussianNB, LR, RFR, Lasso, ElasticNet. All are estimators from `sklearn `_ + max_iter Maximum number of iterations to use in training an estimator. Only for specific estimators, see `sklearn `_. 100000 Integer + SVMKernel When using a SVM, specify the kernel type. poly poly, linear, rbf + SVMC Range of the SVM slack parameter. We sample on a uniform log scale: the parameters specify the range of the exponent (a, a + b). 0, 6 Two Integers: loc and scale + SVMdegree Range of the SVM polynomial degree when using a polynomial kernel. We sample on a uniform scale: the parameters specify the range (a, a + b). 1, 6 Two Integers: loc and scale + SVMcoef0 Range of SVM homogeneity parameter. We sample on a uniform scale: the parameters specify the range (a, a + b). 0, 1 Two Integers: loc and scale + SVMgamma Range of the SVM gamma parameter. We sample on a uniform log scale: the parameters specify the range of the exponent (a, a + b) -5, 5 Two Integers: loc and scale + RFn_estimators Range of number of trees in a RF. We sample on a uniform scale: the parameters specify the range (a, a + b). 10, 90 Two Integers: loc and scale + RFmin_samples_split Range of minimum number of samples required to split a branch in a RF. We sample on a uniform scale: the parameters specify the range (a, a + b). 2, 3 Two Integers: loc and scale + RFmax_depth Range of maximum depth of a RF. We sample on a uniform scale: the parameters specify the range (a, a + b). 5, 5 Two Integers: loc and scale + LRpenalty Penalty term used in LR. l2, l1 none, l2, l1 + LRC Range of regularization strength in LR. We sample on a uniform scale: the parameters specify the range (a, a + b). 0.01, 1.0 Two Integers: loc and scale + LDA_solver Solver used in LDA. svd, lsqr, eigen svd, lsqr, eigen + LDA_shrinkage Range of the LDA shrinkage parameter. We sample on a uniform log scale: the parameters specify the range of the exponent (a, a + b). -5, 5 Two Integers: loc and scale + QDA_reg_param Range of the QDA regularization parameter. We sample on a uniform log scale: the parameters specify the range of the exponent (a, a + b). -5, 5 Two Integers: loc and scale + ElasticNet_alpha Range of the ElasticNet penalty parameter. We sample on a uniform log scale: the parameters specify the range of the exponent (a, a + b). -5, 5 Two Integers: loc and scale + ElasticNet_l1_ratio Range of l1 ratio in LR. We sample on a uniform scale: the parameters specify the range (a, a + b). 0, 1 Two Integers: loc and scale + SGD_alpha Range of the SGD penalty parameter. We sample on a uniform log scale: the parameters specify the range of the exponent (a, a + b). -5, 5 Two Integers: loc and scale + SGD_l1_ratio Range of l1 ratio in SGD. We sample on a uniform scale: the parameters specify the range (a, a + b). 0, 1 Two Integers: loc and scale + SGD_loss hinge, Loss function of SG hinge, squared_hinge, modified_huber hinge, squared_hinge, modified_huber + SGD_penalty Penalty term in SGD. none, l2, l1 none, l2, l1 + CNB_alpha Regularization strenght in ComplementNB. We sample on a uniform scale: the parameters specify the range (a, a + b) 0, 1 Two Integers: loc and scale +CrossValidation N_iterations Number of times the data is split in training and test in the outer cross-validation. 100 Integer + test_size The percentage of data to be used for testing. 0.2 Float +Labels label_names The labels used from your label file for classification. Label1, Label2 String(s) + modus Determine whether multilabel or singlelabel classification or regression will be performed. singlelabel singlelabel, multilabel + url WIP WIP Not Supported Yet + projectID WIP WIP Not Supported Yet +HyperOptimization scoring_method Specify the optimization metric for your hyperparameter search. f1_weighted Any `sklearn metric `_ + test_size Size of test set in the hyperoptimization cross validation, given as a percentage of the whole dataset. 0.15 Float + n_splits 5 5 + N_iterations Number of iterations used in the hyperparameter optimization. This corresponds to the number of samples drawn from the parameter grid. 10000 Integer + n_jobspercore Number of jobs assigned to a single core. Only used if fastr is set to true in the classfication. 2000 Integer + maxlen 100 100 + ranking_score test_score test_score +FeatureScaling scale_features Determine whether to use feature scaling is. True Boolean(s) + scaling_method Determine the scaling method. z_score z_score, minmax +SampleProcessing SMOTE Determine whether to use SMOTE oversampling, see also ` imbalanced learn `_. True Boolean(s) + SMOTE_ratio Determine the ratio of oversampling. If 1, the minority class will be oversampled to the same size as the majority class. We sample on a uniform scale: the parameters specify the range (a, a + b). 1, 0 Two Integers: loc and scale + SMOTE_neighbors Number of neighbors used in SMOTE. This should be much smaller than the number of objects/patients you supply. We sample on a uniform scale: the parameters specify the range (a, a + b). 5, 15 Two Integers: loc and scale + Oversampling Determine whether to random oversampling. False Boolean(s) +Ensemble Use Determine whether to use ensembling or not. Either provide an integer to state how many estimators to include, or True, which will use the default ensembling method. 1 Boolean or Integer +Bootstrap Use False False + N_iterations 1000 1000 +================= ======================== ============================================================================================================================================================================================================================================================== ========================================== ================================================================================================================================================================= \ No newline at end of file diff --git a/WORC/doc/_build/html/_sources/autogen/WORC.classification.rst.txt b/WORC/doc/_build/html/_sources/autogen/WORC.classification.rst.txt index 3e0ac848..7a49a362 100644 --- a/WORC/doc/_build/html/_sources/autogen/WORC.classification.rst.txt +++ b/WORC/doc/_build/html/_sources/autogen/WORC.classification.rst.txt @@ -1,6 +1,15 @@ classification Package ====================== +:mod:`classification` Package +----------------------------- + +.. automodule:: WORC.classification + :members: + :undoc-members: + :show-inheritance: + :special-members: + :mod:`AdvancedSampler` Module ----------------------------- @@ -10,6 +19,15 @@ classification Package :show-inheritance: :special-members: +:mod:`ObjectSampler` Module +--------------------------- + +.. automodule:: WORC.classification.ObjectSampler + :members: + :undoc-members: + :show-inheritance: + :special-members: + :mod:`RankedSVM` Module ----------------------- @@ -37,6 +55,15 @@ classification Package :show-inheritance: :special-members: +:mod:`createfixedsplits` Module +------------------------------- + +.. automodule:: WORC.classification.createfixedsplits + :members: + :undoc-members: + :show-inheritance: + :special-members: + :mod:`crossval` Module ---------------------- @@ -82,6 +109,15 @@ classification Package :show-inheritance: :special-members: +:mod:`regressors` Module +------------------------ + +.. automodule:: WORC.classification.regressors + :members: + :undoc-members: + :show-inheritance: + :special-members: + :mod:`trainclassifier` Module ----------------------------- diff --git a/WORC/doc/_build/html/_sources/autogen/WORC.config.rst.txt b/WORC/doc/_build/html/_sources/autogen/WORC.config.rst.txt new file mode 100644 index 00000000..c77d23f6 --- /dev/null +++ b/WORC/doc/_build/html/_sources/autogen/WORC.config.rst.txt @@ -0,0 +1,19 @@ +================= =================================================== +Key Reference +================= =================================================== +Bootstrap :ref:`Bootstrap ` +Classification :ref:`Classification ` +CrossValidation :ref:`CrossValidation ` +Ensemble :ref:`Ensemble ` +Featsel :ref:`Featsel ` +FeatureScaling :ref:`FeatureScaling ` +General :ref:`General ` +HyperOptimization :ref:`HyperOptimization ` +ImageFeatures :ref:`ImageFeatures ` +Imputation :ref:`Imputation ` +Labels :ref:`Labels ` +Normalize :ref:`Normalize ` +SampleProcessing :ref:`SampleProcessing ` +Segmentix :ref:`Segmentix ` +SelectFeatGroup :ref:`SelectFeatGroup ` +================= =================================================== \ No newline at end of file diff --git a/WORC/doc/_build/html/_sources/autogen/WORC.detectors.rst.txt b/WORC/doc/_build/html/_sources/autogen/WORC.detectors.rst.txt new file mode 100644 index 00000000..77c54f1b --- /dev/null +++ b/WORC/doc/_build/html/_sources/autogen/WORC.detectors.rst.txt @@ -0,0 +1,12 @@ +detectors Package +================= + +:mod:`detectors` Module +----------------------- + +.. automodule:: WORC.detectors.detectors + :members: + :undoc-members: + :show-inheritance: + :special-members: + diff --git a/WORC/doc/_build/html/_sources/autogen/WORC.exampledata.rst.txt b/WORC/doc/_build/html/_sources/autogen/WORC.exampledata.rst.txt new file mode 100644 index 00000000..edd6d5b0 --- /dev/null +++ b/WORC/doc/_build/html/_sources/autogen/WORC.exampledata.rst.txt @@ -0,0 +1,12 @@ +exampledata Package +=================== + +:mod:`datadownloader` Module +---------------------------- + +.. automodule:: WORC.exampledata.datadownloader + :members: + :undoc-members: + :show-inheritance: + :special-members: + diff --git a/WORC/doc/_build/html/_sources/autogen/WORC.facade.intermediatefacade.rst.txt b/WORC/doc/_build/html/_sources/autogen/WORC.facade.intermediatefacade.rst.txt new file mode 100644 index 00000000..878fd941 --- /dev/null +++ b/WORC/doc/_build/html/_sources/autogen/WORC.facade.intermediatefacade.rst.txt @@ -0,0 +1,30 @@ +intermediatefacade Package +========================== + +:mod:`configbuilder` Module +--------------------------- + +.. automodule:: WORC.facade.intermediatefacade.configbuilder + :members: + :undoc-members: + :show-inheritance: + :special-members: + +:mod:`exceptions` Module +------------------------ + +.. automodule:: WORC.facade.intermediatefacade.exceptions + :members: + :undoc-members: + :show-inheritance: + :special-members: + +:mod:`intermediatefacade` Module +-------------------------------- + +.. automodule:: WORC.facade.intermediatefacade.intermediatefacade + :members: + :undoc-members: + :show-inheritance: + :special-members: + diff --git a/WORC/doc/_build/html/_sources/autogen/WORC.facade.rst.txt b/WORC/doc/_build/html/_sources/autogen/WORC.facade.rst.txt new file mode 100644 index 00000000..fec9f4e2 --- /dev/null +++ b/WORC/doc/_build/html/_sources/autogen/WORC.facade.rst.txt @@ -0,0 +1,19 @@ +facade Package +============== + +:mod:`facade` Package +--------------------- + +.. automodule:: WORC.facade + :members: + :undoc-members: + :show-inheritance: + :special-members: + +Subpackages +----------- + +.. toctree:: + + WORC.facade.simpleworc + diff --git a/WORC/doc/_build/html/_sources/autogen/WORC.featureprocessing.rst.txt b/WORC/doc/_build/html/_sources/autogen/WORC.featureprocessing.rst.txt index 29ce3960..eb57f40b 100644 --- a/WORC/doc/_build/html/_sources/autogen/WORC.featureprocessing.rst.txt +++ b/WORC/doc/_build/html/_sources/autogen/WORC.featureprocessing.rst.txt @@ -10,6 +10,15 @@ featureprocessing Package :show-inheritance: :special-members: +:mod:`Decomposition` Module +--------------------------- + +.. automodule:: WORC.featureprocessing.Decomposition + :members: + :undoc-members: + :show-inheritance: + :special-members: + :mod:`Imputer` Module --------------------- diff --git a/WORC/doc/_build/html/_sources/autogen/WORC.plotting.rst.txt b/WORC/doc/_build/html/_sources/autogen/WORC.plotting.rst.txt index 8cec5656..1f866572 100644 --- a/WORC/doc/_build/html/_sources/autogen/WORC.plotting.rst.txt +++ b/WORC/doc/_build/html/_sources/autogen/WORC.plotting.rst.txt @@ -1,6 +1,15 @@ plotting Package ================ +:mod:`plotting` Package +----------------------- + +.. automodule:: WORC.plotting + :members: + :undoc-members: + :show-inheritance: + :special-members: + :mod:`compute_CI` Module ------------------------ @@ -37,15 +46,6 @@ plotting Package :show-inheritance: :special-members: -:mod:`plot_SVR` Module ----------------------- - -.. automodule:: WORC.plotting.plot_SVR - :members: - :undoc-members: - :show-inheritance: - :special-members: - :mod:`plot_barchart` Module --------------------------- diff --git a/WORC/doc/_build/html/_sources/autogen/WORC.resources.fastr_tools.rst.txt b/WORC/doc/_build/html/_sources/autogen/WORC.resources.fastr_tools.rst.txt new file mode 100644 index 00000000..b42ed940 --- /dev/null +++ b/WORC/doc/_build/html/_sources/autogen/WORC.resources.fastr_tools.rst.txt @@ -0,0 +1,12 @@ +fastr_tools Package +=================== + +:mod:`fastr_tools` Package +-------------------------- + +.. automodule:: WORC.resources.fastr_tools + :members: + :undoc-members: + :show-inheritance: + :special-members: + diff --git a/WORC/doc/_build/html/_sources/autogen/WORC.resources.rst.txt b/WORC/doc/_build/html/_sources/autogen/WORC.resources.rst.txt new file mode 100644 index 00000000..c46f113f --- /dev/null +++ b/WORC/doc/_build/html/_sources/autogen/WORC.resources.rst.txt @@ -0,0 +1,11 @@ +resources Package +================= + +Subpackages +----------- + +.. toctree:: + + WORC.resources.fastr_tests + WORC.resources.fastr_tools + diff --git a/WORC/doc/_build/html/_sources/autogen/WORC.rst.txt b/WORC/doc/_build/html/_sources/autogen/WORC.rst.txt index 7a6d477b..ae8eff11 100644 --- a/WORC/doc/_build/html/_sources/autogen/WORC.rst.txt +++ b/WORC/doc/_build/html/_sources/autogen/WORC.rst.txt @@ -35,8 +35,12 @@ Subpackages WORC.IOparser WORC.classification + WORC.detectors + WORC.exampledata + WORC.facade WORC.featureprocessing WORC.plotting WORC.processing + WORC.resources WORC.tools diff --git a/WORC/doc/_build/html/_sources/autogen/WORC.tools.rst.txt b/WORC/doc/_build/html/_sources/autogen/WORC.tools.rst.txt index 7649a737..e2645f5e 100644 --- a/WORC/doc/_build/html/_sources/autogen/WORC.tools.rst.txt +++ b/WORC/doc/_build/html/_sources/autogen/WORC.tools.rst.txt @@ -37,3 +37,12 @@ tools Package :show-inheritance: :special-members: +:mod:`createfixedsplits` Module +------------------------------- + +.. automodule:: WORC.tools.createfixedsplits + :members: + :undoc-members: + :show-inheritance: + :special-members: + diff --git a/WORC/doc/_build/html/_sources/index.rst.txt b/WORC/doc/_build/html/_sources/index.rst.txt index 155c3206..a3569d4c 100644 --- a/WORC/doc/_build/html/_sources/index.rst.txt +++ b/WORC/doc/_build/html/_sources/index.rst.txt @@ -53,7 +53,7 @@ WORC has been used in the following studies: `Jose M. Castillo T., Martijn P. A. Starmans, Ivo Schoots, Wiro J. Niessen, Stefan Klein, Jifke F. Veenland. "CLASSIFICATION OF PROSTATE CANCER: HIGH GRADE VERSUS LOW GRADE USING A RADIOMICS APPROACH." IEEE International Symposium on Biomedical Imaging (ISBI) 2019. `_ -WORC is made possible by contributions from the following people: Martijn Starmans, and Stefan Klein +WORC is made possible by contributions from the following people: Martijn Starmans, Thomas Phil, and Stefan Klein WORC Documentation diff --git a/WORC/doc/_build/html/_sources/static/configuration.rst.txt b/WORC/doc/_build/html/_sources/static/configuration.rst.txt index a46085ab..48d71936 100644 --- a/WORC/doc/_build/html/_sources/static/configuration.rst.txt +++ b/WORC/doc/_build/html/_sources/static/configuration.rst.txt @@ -3,7 +3,23 @@ Configuration ============= +Introduction +------------ +WORC has defaults for all settings so it can be run out of the box to test the examples. +However, you may want to alter the fastr configuration to your system settings, e.g. +to locate your input and output folders and how much you want to parallelize the execution. + +Fastr will search for a config file named ``config.py`` in the ``$FASTRHOME`` directory +(which defaults to ``~/.fastr/`` if it is not set). So if ``$FASTRHOME`` is set the ``~/.fastr/`` +will be ignored. Additionally, .py files from the ``$FASTRHOME/config.d`` folder will be parsed +as well. You will see that upon installation, WORC has already put a ``WORC_config.py`` file in the +``config.d`` folder. + +For a sample configuration file and a complete overview of the options in ``config.py`` see +the :ref:`configuration-chapter` section. + +% Note: Above was originally from quick start As ``WORC`` and the default tools used are mostly Python based, we've chosen to put our configuration in a ``configparser`` object. This has several advantages: @@ -12,6 +28,10 @@ advantages: 2. Second, each tool can be set to parse only specific parts of the configuration, enabling us to supply one file to all tools instead of needing many parameter files. + +Creation and interaction +------------------------- + The default configuration is generated through the :py:meth:`WORC.defaultconfig() ` function. You can then change things as you would in a dictionary and @@ -52,48 +72,87 @@ means that the SVM is 2x more likely to be tested in the model selection than LR list can be created by using commas for separation, e.g. :py:meth:`Network.create_source <'value1, value2, ... ')>`. +Contents +-------- +The config object can be indexed as ``config[key][subkey] = value``. The various keys, subkeys, and the values +(description, defaults and options) can be found below. -General -------- +.. include:: ../autogen/WORC.config.rst +Details on each section of the config can be found below. -PREDICTGeneral --------------- -These fields contain general settings for when using PREDICT. +.. _config-General: + +General +~~~~~~~ +These fields contain general settings for when using WORC. For more info on the Joblib settings, which are used in the Joblib Parallel function, see `here `__. When you run WORC on a cluster with nodes supporting only a single core to be used per node, e.g. the BIGR cluster, use only 1 core and threading as a backend. +**Description:** +.. include:: ../autogen/config/WORC.config_General_description.rst +**Defaults and Options:** + +.. include:: ../autogen/config/WORC.config_General_defopts.rst + + +.. _config-Segmentix: Segmentix ---------- +~~~~~~~~~ These fields are only important if you specified using the segmentix tool in the general configuration. +**Description:** + +.. include:: ../autogen/config/WORC.config_Segmentix_description.rst -Preprocessing -------------- +**Defaults and Options:** + +.. include:: ../autogen/config/WORC.config_Segmentix_defopts.rst + + +.. _config-Normalize: +Normalize +~~~~~~~~~~~~~ The preprocessing node acts before the feature extraction on the image. Currently, only normalization is included: hence the dictionary name is *Normalize*. Additionally, scans with image type CT (see later in the tutorial) provided as DICOM are scaled to Hounsfield Units. +**Description:** + +.. include:: ../autogen/config/WORC.config_Normalize_description.rst -Imagefeatures -------------- +**Defaults and Options:** +.. include:: ../autogen/config/WORC.config_Normalize_defopts.rst + + +.. _config-ImageFeatures: +ImageFeatures +~~~~~~~~~~~~~ If using the PREDICT toolbox, you can specify some settings for the feature computation here. Also, you can select if the certain features are computed or not. +**Description:** -Featsel -------- +.. include:: ../autogen/config/WORC.config_ImageFeatures_description.rst + +**Defaults and Options:** + +.. include:: ../autogen/config/WORC.config_ImageFeatures_defopts.rst + +.. _config-Featsel: +Featsel +~~~~~~~ When using the PREDICT toolbox for classification, these settings can be used for feature selection methods. Note that these settings are actually used in the hyperparameter optimization. Hence you can provide @@ -102,9 +161,18 @@ which finally the best setting in combination with the other hyperparameters is selected. Again, these should be formatted as string containing the actual values, e.g. value1, value2. +**Description:** + +.. include:: ../autogen/config/WORC.config_Featsel_description.rst + +**Defaults and Options:** +.. include:: ../autogen/config/WORC.config_Featsel_defopts.rst + + +.. _config-SelectFeatGroup: SelectFeatGroup ---------------- +~~~~~~~~~~~~~~~ If the PREDICT feature computation and classification tools are used, then you can do a gridsearch among the various feature groups for the optimal combination. If you do not want this, set all fields to a single @@ -114,8 +182,18 @@ Previously, there was a single parameter for the texture features, selecting all, none or a single group. This is still supported, but not recommended, and looks as follows: +**Description:** + +.. include:: ../autogen/config/WORC.config_SelectFeatGroup_description.rst + +**Defaults and Options:** + +.. include:: ../autogen/config/WORC.config_SelectFeatGroup_defopts.rst + + +.. _config-Imputation: Imputation ----------------- +~~~~~~~~~~~~~~~~ When using the PREDICT toolbox for classification, these settings are used for feature imputation.Note that these settings are actually used in the hyperparameter optimization. Hence you can provide multiple @@ -123,22 +201,50 @@ values per field, of which random samples will be drawn of which finally the best setting in combination with the other hyperparameters is selected. +**Description:** + +.. include:: ../autogen/config/WORC.config_Imputation_description.rst +**Defaults and Options:** + +.. include:: ../autogen/config/WORC.config_Imputation_defopts.rst + + +.. _config-Classification: Classification --------------- +~~~~~~~~~~~~~~ When using the PREDICT toolbox for classification, you can specify the following settings. Almost all of these are used in CASH. Most of the classifiers are implemented using sklearn; hence descriptions of the hyperparameters can also be found there. +**Description:** + +.. include:: ../autogen/config/WORC.config_Classification_description.rst + +**Defaults and Options:** +.. include:: ../autogen/config/WORC.config_Classification_defopts.rst + + +.. _config-CrossValidation: CrossValidation ---------------- +~~~~~~~~~~~~~~~ When using the PREDICT toolbox for classification and you specified using cross validation, specify the following settings. +**Description:** + +.. include:: ../autogen/config/WORC.config_CrossValidation_description.rst + +**Defaults and Options:** + +.. include:: ../autogen/config/WORC.config_CrossValidation_defopts.rst + + +.. _config-Labels: Labels --------- +~~~~~~~~ When using the PREDICT toolbox for classification, you have to set the label used for classification. @@ -162,8 +268,6 @@ You can supply a single label or multiple labels split by commas, for each of which an estimator will be fit. For example, suppose you simply want to use Label1 for classification, then set: - - .. code-block:: python config['Labels']['label_names'] = 'Label1' @@ -173,44 +277,86 @@ If you want to first train a classifier on Label1 and then Label2, set: ``config[Genetics][label_names] = Label1, Label2`` +**Description:** + +.. include:: ../autogen/config/WORC.config_Labels_description.rst + +**Defaults and Options:** +.. include:: ../autogen/config/WORC.config_Labels_defopts.rst + +.. _config-HyperOptimization: Hyperoptimization ------------------ +~~~~~~~~~~~~~~~~~ When using the PREDICT toolbox for classification, you have to supply your hyperparameter optimization procedure here. +**Description:** + +.. include:: ../autogen/config/WORC.config_HyperOptimization_description.rst + +**Defaults and Options:** + +.. include:: ../autogen/config/WORC.config_HyperOptimization_defopts.rst + +.. _config-FeatureScaling: FeatureScaling --------------- +~~~~~~~~~~~~~~ Determines which method is applied to scale each feature. +**Description:** + +.. include:: ../autogen/config/WORC.config_FeatureScaling_description.rst + +**Defaults and Options:** + +.. include:: ../autogen/config/WORC.config_FeatureScaling_defopts.rst + +.. _config-SampleProcessing: SampleProcessing ----------------- +~~~~~~~~~~~~~~~~ Before performing the hyperoptimization, you can use SMOTE: Synthetic Minority Over-sampling Technique to oversample your data. +**Description:** + +.. include:: ../autogen/config/WORC.config_SampleProcessing_description.rst +**Defaults and Options:** +.. include:: ../autogen/config/WORC.config_SampleProcessing_defopts.rst +.. _config-Ensemble: Ensemble --------- +~~~~~~~~ WORC supports ensembling of workflows. This is not a default approach in radiomics, hence the default is to not use it and select only the best performing workflow. +**Description:** + +.. include:: ../autogen/config/WORC.config_Ensemble_description.rst + +**Defaults and Options:** + +.. include:: ../autogen/config/WORC.config_Ensemble_defopts.rst + + +.. _config-Bootstrap: +Bootstrap +~~~~~~~~~ +Besides cross validation, WORC supports bootstrapping on the test set for performance evaluation. +**Description:** +.. include:: ../autogen/config/WORC.config_Bootstrap_description.rst -FASTR_bugs ----------- -Currently, when using XNAT as a source, FASTR can only retrieve DICOM -directories. We made a workaround for this for the images and -segmentations, but this only works if all your files have the same name -and extension. These are provided in this configuration part. +**Defaults and Options:** +.. include:: ../autogen/config/WORC.config_Bootstrap_defopts.rst -.. include:: ../autogen/WORC.config.rst \ No newline at end of file diff --git a/WORC/doc/_build/html/_sources/static/quick_start.rst.txt b/WORC/doc/_build/html/_sources/static/quick_start.rst.txt index 47be8c5a..4a5b8106 100644 --- a/WORC/doc/_build/html/_sources/static/quick_start.rst.txt +++ b/WORC/doc/_build/html/_sources/static/quick_start.rst.txt @@ -10,6 +10,9 @@ Installation You can install WORC either using pip, or from the source code. +.. note:: The version of PyRadiomics which WORC currently uses requires numpy to be installed beforehand. Make sure you do so, e.g. ``pip install numpy``. + + Installing via pip `````````````````` @@ -47,35 +50,226 @@ library. For Ubuntu this is in the ``/usr/local/lib/python3.x/dist-packages/`` f .. note:: If you want to develop WORC, you might want to use ``pip install -e .`` to get an editable install -.. note:: You might want to consider installing ``WORC`` in a `virtualenv `_ - - -Configuration -------------- +.. note:: You might want to consider installing ``WORC`` in a + `virtualenv `_ -WORC has defaults for all settings so it can be run out of the box to test the examples. -However, you may want to alter the fastr configuration to your system settings, e.g. -to locate your input and output folders and how much you want to parallelize the execution. +Windows installation +```````````````````` -Fastr will search for a config file named ``config.py`` in the ``$FASTRHOME`` directory -(which defaults to ``~/.fastr/`` if it is not set). So if ``$FASTRHOME`` is set the ``~/.fastr/`` -will be ignored. Additionally, .py files from the ``$FASTRHOME/config.d`` folder will be parsed -as well. You will see that upon installation, WORC has already put a ``WORC_config.py`` file in the -``config.d`` folder. +On Windows, we strongly recommend to install python through the +`Anaconda distribution `_. -For a sample configuration file and a complete overview of the options in ``config.py`` see -the :ref:`Config file ` section. +Regardless of your installation, you will need `Microsoft Visual Studio `_: the Community +edition can be downloaded and installed for free. +If you still get an error similar to error: ``Microsoft Visual C++ 14.0 is required. Get it with`` +`Microsoft Visual C++ Build Tools `_ +, please follow the respective link and install the requirements. -Tutorial --------- -To start out using WORC, we recommend you to follow the tutorial located in the -[WORCTutorial Github](https://github.com/MStarmans91/WORCTutorial). Besides some more advanced tutorials, -the main tutorial can be found in the WORCTutorial.ipynb Jupyter notebook. Instructions on how -to use the notebook can be found in the Github. +Tutorials +--------- +To start out using WORC, we recommend you to follow the tutorials located in the +`WORCTutorial Github `_. This repository +contains tutorials for an introduction to WORC, as well as more advanced workflows. If you run into any issue, you can first debug your network using `the fastr trace tool `_. If you're stuck, feel free to post an issue on the `WORC Github `_. + +Hello World +------------ + +Below is the same script as found in the SimpleWORC tutorial found in the `WORCTutorial Github `_. + +Import packages +``````````````` + +First, import WORC and some additional python packages. + +.. code-block:: python + + from WORC import SimpleWORC + import os + + # These packages are only used in analysing the results + import pandas as pd + import json + import fastr + import glob + + # If you don't want to use your own data, we use the following example set, + # see also the next code block in this example. + from WORC.exampledata.datadownloader import download_HeadAndNeck + + # Define the folder this script is in, so we can easily find the example data + script_path = os.path.dirname(os.path.abspath(__file__)) + +Input +````` +The minimal inputs to WORC are: + + 1. Images + 2. Segmentations + 3. Labels + +In SimpleWORC, we assume you have a folder "datadir", in which there is a +folder for each patient, where in each folder there is a image.nii.gz and a mask.nii.gz: + + * Datadir + + * Patient_001 + + * image.nii.gz + * mask.nii.gz + + * Patient_002 + + * image.nii.gz + * mask.nii.gz + + * ... + +In the example, we will use open source data from the online +`BMIA XNAT platform `_ +This dataset consists of CT scans of patients with Head and Neck tumors. We will download +a subset of 20 patients in this folder. You can change this settings if you like. + +.. code-block:: python + + nsubjects = 20 # use "all" to download all patients + data_path = os.path.join(script_path, 'Data') + download_HeadAndNeck(datafolder=data_path, nsubjects=nsubjects) + +.. note:: You can skip this code block if you use your own data. + +Identify our data structure: change the fields below accordingly if you use your own dataset. + +.. code-block:: python + + imagedatadir = os.path.join(data_path, 'stwstrategyhn1') + image_file_name = 'image.nii.gz' + segmentation_file_name = 'mask.nii.gz' + + # File in which the labels (i.e. outcome you want to predict) is stated + # Again, change this accordingly if you use your own data. + label_file = os.path.join(data_path, 'Examplefiles', 'pinfo_HN.csv') + + # Name of the label you want to predict + label_name = 'imaginary_label_1' + + # Determine whether we want to do a coarse quick experiment, or a full lengthy + # one. Again, change this accordingly if you use your own data. + coarse = True + + # Give your experiment a name + experiment_name = 'Example_STWStrategyHN4' + + # Instead of the default tempdir, let's but the temporary output in a subfolder + # in the same folder as this script + tmpdir = os.path.join(script_path, 'WORC_' + experiment_name) + +The actual experiment +````````````````````` + +After defining the inputs, the following code can be used to run your first experiment. + +.. code-block:: python + + # Create a Simple WORC object + network = SimpleWORC(experiment_name) + + # Set the input data according to the variables we defined earlier + network.images_from_this_directory(imagedatadir, + image_file_name=image_file_name) + network.segmentations_from_this_directory(imagedatadir, + segmentation_file_name=segmentation_file_name) + network.labels_from_this_file(label_file) + network.predict_labels([label_name]) + + # Use the standard workflow for binary classification + network.binary_classification(coarse=coarse) + + # Set the temporary directory + experiment.set_tmpdir(tmpdir) + + # Run the experiment! + network.execute() + +.. note:: Precomputed features can be used instead of images and masks by instead using ``network.features_from_this_directory()`` in a similar fashion. + +Analysis of the results +``````````````````````` +There are two main outputs: the features for each patient/object, and the overall +performance. These are stored as .hdf5 and .json files, respectively. By +default, they are saved in the so-called "fastr output mount", in a subfolder +named after your experiment name. + +.. code-block:: python + + # Locate output folder + outputfolder = fastr.config.mounts['output'] + experiment_folder = os.path.join(outputfolder, 'WORC_' + experiment_name) + + print(f"Your output is stored in {experiment_folder}.") + + # Read the features for the first patient + # NOTE: we use the glob package for scanning a folder to find specific files + feature_files = glob.glob(os.path.join(experiment_folder, + 'Features', + 'features_*.hdf5')) + featurefile_p1 = feature_files[0] + features_p1 = pd.read_hdf(featurefile_p1) + + # Read the overall peformance + performance_file = os.path.join(experiment_folder, 'performance_all_0.json') + with open(performance_file, 'r') as fp: + performance = json.load(fp) + + # Print the feature values and names + print("Feature values:") + for v, l in zip(features_p1.feature_values, features_p1.feature_labels): + print(f"\t {l} : {v}.") + + # Print the output performance + print("\n Performance:") + stats = performance['Statistics'] + del stats['Percentages'] # Omitted for brevity + for k, v in stats.items(): + print(f"\t {k} {v}.") + +.. note:: the performance is probably horrible, which is expected as we ran the experiment on coarse settings. These settings are recommended to only use for testing: see also below. + + +Tips and Tricks +``````````````` + +For tips and tricks on running a full experiment instead of this simple +example, adding more evaluation options, debugging a crashed network etcetera, +please go to :ref:`usermanual-chapter` or follow the intermediate +or advanced tutorials on `WORCTutorial Github `_. + +Some things we would advice to always do: + +* Run actual experiments on the full settings (coarse=False): + +.. code-block:: python + + coarse = False + network.binary_classification(coarse=coarse) + +.. note:: This will result in more computation time. We therefore recommmend + to run this script on either a cluster or high performance PC. If so, + you may change the execution to use multiple cores to speed up computation + just before before ``experiment.execute()``: + + .. code-block:: python + + experiment.set_multicore_execution() + +* Add extensive evaluation: ``network.add_evaluation()`` before ``network.execute()``: + +.. code-block:: python + + network.add_evaluation() \ No newline at end of file diff --git a/WORC/doc/_build/html/_sources/static/user_manual.rst.txt b/WORC/doc/_build/html/_sources/static/user_manual.rst.txt index 1a5494bc..f84191ff 100644 --- a/WORC/doc/_build/html/_sources/static/user_manual.rst.txt +++ b/WORC/doc/_build/html/_sources/static/user_manual.rst.txt @@ -1,3 +1,5 @@ +.. usermanual-chapter: + User Manual =========== @@ -22,14 +24,12 @@ The WORC toolbox consists of one main object, the WORC object: It's attributes are split in a couple of categories. We will not discuss the WORC.defaultconfig() function here, which generates the default -configuration, as it is listed in a separate page, see the :ref:`config file section `. +configuration, as it is listed in a separate page, see the :doc:`config file section `. Attributes: Sources -------------------- - - +~~~~~~~~~~~~~~~~~~~ There are numerous WORC attributes which serve as source nodes for the FASTR network. These are: @@ -97,42 +97,8 @@ appending procedure can be used. did not supply a segmentation. **WORC will always align these sequences with no segmentations to the first sequence, i.e. the first object in the images_train list.** Hence make sure you supply the sequence for which you have a ROI as the first object. - - -Attributes: Settings --------------------- - - -There are several attributes in WORC which define how your pipeline is -executed: - - - -- fastr_plugin -- fastr_tmpdir -- Tools: additional workflows are stored here. Currently only includes - a pipeline for image registration without any Radiomics. -- CopyMetadata: Whether to automatically copy the metadata info - (e.g. direction of cosines) from the images to the segmentations - before applying transformix. - -An explanation of the FASTR settings is given below. - - - -Attributes: Functions ---------------------- - -The WORC.configs() attribute contains the configparser files, which you -can easily edit. The WORC.set() function saves these objects in a -temporary folder and converts the filename into as FASTR source, which -is then put in the WORC.fastrconfigs() objects. Hence you do not need to -edit the fastrconfigs object manually. - - - Images and segmentations -~~~~~~~~~~~~~~~~~~~~~~~~ +^^^^^^^^^^^^^^^^^^^^^^^^ @@ -148,7 +114,7 @@ image formats such as DICOM, NIFTI, TIFF, NRRD and MHD. Semantics -~~~~~~~~~ +^^^^^^^^^ Semantic features are used in the PREDICT CalcFeatures tool. You can supply these as a .csv listing your features per patient. The first @@ -183,7 +149,7 @@ case, your sources should look as following: Labels -~~~~~~ +^^^^^^ The labels are used in classification. For PREDICT, these should be supplied as a .txt file. Similar to the semantics, the first column @@ -193,7 +159,7 @@ semantics file. Masks ------------ +^^^^^ WORC contains a segmentation preprocessing tool, called segmentix. This tool is still under development. The idea is that you can manipulate @@ -204,7 +170,7 @@ radius around your ROI and mask it. Features --------- +^^^^^^^^ If you already computed your features, e.g. from a previous run, you can directly supply the features instead of the images and segmentations and @@ -213,7 +179,7 @@ matching the PREDICT CalcFeatures format. Metadata --------- +^^^^^^^^ This source can be used if you want to use tags from the DICOM header as features, e.g. patient age and sex. In this case, this source should @@ -224,7 +190,7 @@ implemented tags. Elastix_Para ------------- +^^^^^^^^^^^^ If you have multiple images for each patient, e.g. T1 and T2, but only a single segmentation, you can use image registration to align and @@ -237,9 +203,39 @@ is made on the first WORC.images source you supply. The segmentation will be alingned to all other image sources.** +Attributes: Settings +~~~~~~~~~~~~~~~~~~~~ + + +There are several attributes in WORC which define how your pipeline is +executed: + + + +- fastr_plugin +- fastr_tmpdir +- Tools: additional workflows are stored here. Currently only includes + a pipeline for image registration without any Radiomics. +- CopyMetadata: Whether to automatically copy the metadata info + (e.g. direction of cosines) from the images to the segmentations + before applying transformix. + +An explanation of the FASTR settings is given below. + + + +Attributes: Functions +~~~~~~~~~~~~~~~~~~~~~ + +The WORC.configs() attribute contains the configparser files, which you +can easily edit. The WORC.set() function saves these objects in a +temporary folder and converts the filename into as FASTR source, which +is then put in the WORC.fastrconfigs() objects. Hence you do not need to +edit the fastrconfigs object manually. + FASTR settings --------------- +~~~~~~~~~~~~~~ There are two WORC attributes which contain settings on running FASTR. In WORC.fastr_plugin, you can specify which Execution Plugin should be @@ -250,10 +246,8 @@ The default is the ProcessPollExecution plugin. The WORC.fastr_tempdir sets the temporary directory used in your run. - Construction and execution commands ------------------------------------ - +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ After supplying your sources, you need to build the FASTR network. This @@ -273,3 +267,101 @@ WORC.source_data_data and WORC.sink objects. Finally, after completing above steps, you can execute the network through the WORC.execute() command. + + +Evaluation of your network +-------------------------- + +In WORC, there are two options for testing your fitted models: + +1. Single dataset: cross-validation (currently only random-split) +2. Separate train and test dataset: bootstrapping on test dataset + +Within these evaluation settings, the following performance evaluation methods are used: + +1. Confidence intervals on several metrics: + + For classification: + + a) Area under the curve (AUC) of the receiver operating characteristic (ROC) curve. In a multiclass setting, weuse the multiclass AUC from the `TADPOLE Challenge `_. + b) Accuracy. + c) Balanced classification accuracy as defined by the `TADPOLE Challenge `_. + d) F1-score + e) Sensitivity, aka recall or true positive rate + f) Specificity, aka true negative rate + g) Negative predictive value (NPV) + h) Precision, aka Positive predictive value (PPV) + + For regression: + + a) R2-score + b) Mean Squared Error (MSE) + c) Intraclass Correlation Coefficient (ICC) + d) Pearson correlation coefficient and p-value + e) Spearmand correlation coefficient and p-value + + For survival, in addition to the regression scores: + a) Concordance index + b) Cox regression coefficient and p-value + + In cross-validation, by default, 95% confidence intervals for the mean performance measures are constructed using + the corrected resampled t-test base on all cross-validation iterations, thereby taking into account that the samples + in the cross-validation splits are not statistically independent. See als + `Nadeau C, Bengio Y. Inference for the generalization error. In Advances in Neural Information Processing Systems, 2000; 307–313.` + + In bootstrapping, 95% confidence intervals are created using the ''standard'' method according to a normal distribution: see Table 6, method 1 in `Efron B., Tibshirani R. Bootstrap Methods for Standard Errors, + Confidence Intervals, and Other Measures of Statistical Accuracy, Statistical Science Vol.1, No,1, 54-77, 1986`. + +2. ROC curve with 95% confidence intervals using the fixed-width bands method, see `Macskassy S. A., Provost F., Rosset S. ROC Confidence Bands: An Empirical Evaluation. In: Proceedings of the 22nd international conference on Machine learning. 2005.` + +3. Univariate statistical testing of the features using: + + a) A student t-test + b) A Welch test + c) A Wilcoxon test + d) A Mann-Whitney U test + + The uncorrected p-values for all these tests are reported in a single excel sheet. Pick the right test and significance + level based on your assumptions. Normally, we make use of the Mann-Whitney U test, as our features do not have to be normally + distributed, it's nonparametric, and assumes independent samples. + +4. Ranking patients from typical to atypical as determined by the model, based on either: + + a) The percentage of times a patient was classified correctly when occuring in the test set. Patients always correctly classified + can be seen as typical examples; patients always classified incorrectly as atypical. + b) The mean posterior of the patient when occuring in the test set. + + These measures can only be used in classification. Besides an Excel with the rankings, snapshots of the middle slice + of the image + segmentation are saved with the ground truth label and the percentage/posterior in the filename. In + this way, one can scroll through the patients from typical to atypical to distinguish a pattern. + +5. A barchart of how often certain features groups were selected in the optimal methods. Only useful when using + groupwise feature selection. + +By default, only the first evaluation method, e.g. metric computation, is used. The other methods can simply be added +to WORC by using the ``add_evaluation()`` function, either directly in WORC or through the facade: + + +.. code-block:: python + + import WORC + network = WORC.WORC('somename') + label_type = 'name_of_label_predicted_for_evaluation' + ... + network.add_evaluation(label_type) + +.. code-block:: python + + import WORC + from WORC import IntermediateFacade + I = IntermediateFacade('somename') + ... + I.add_evaluation() + +Debugging +--------- + +As WORC is based on fastr, debugging is similar to debugging a fastr pipeline: see therefore also +`the fastr debugging guidelines `_. + +If you run into any issue, please create an issue on the `WORC Github `_. \ No newline at end of file diff --git a/WORC/doc/_build/html/_static/documentation_options.js b/WORC/doc/_build/html/_static/documentation_options.js index ef965269..12a2ee43 100644 --- a/WORC/doc/_build/html/_static/documentation_options.js +++ b/WORC/doc/_build/html/_static/documentation_options.js @@ -1,6 +1,6 @@ var DOCUMENTATION_OPTIONS = { URL_ROOT: document.getElementById("documentation_options").getAttribute('data-url_root'), - VERSION: '3.0.0', + VERSION: '3.1.0', LANGUAGE: 'None', COLLAPSE_INDEX: false, FILE_SUFFIX: '.html', diff --git a/WORC/doc/_build/html/autogen/WORC.IOparser.html b/WORC/doc/_build/html/autogen/WORC.IOparser.html index 64ae7bc1..946a5d06 100644 --- a/WORC/doc/_build/html/autogen/WORC.IOparser.html +++ b/WORC/doc/_build/html/autogen/WORC.IOparser.html @@ -8,7 +8,7 @@ - IOparser Package — WORC 3.0.0 documentation + IOparser Package — WORC 3.1.0 documentation @@ -61,7 +61,7 @@
    - 3.0.0 + 3.1.0
    @@ -108,9 +108,13 @@
  • classification Package
  • +
  • detectors Package
  • +
  • exampledata Package
  • +
  • facade Package
  • featureprocessing Package
  • plotting Package
  • processing Package
  • +
  • resources Package
  • tools Package
  • diff --git a/WORC/doc/_build/html/autogen/WORC.classification.html b/WORC/doc/_build/html/autogen/WORC.classification.html index e1063f76..1ae268dd 100644 --- a/WORC/doc/_build/html/autogen/WORC.classification.html +++ b/WORC/doc/_build/html/autogen/WORC.classification.html @@ -8,7 +8,7 @@ - classification Package — WORC 3.0.0 documentation + classification Package — WORC 3.1.0 documentation @@ -36,7 +36,7 @@ - + @@ -61,7 +61,7 @@
    - 3.0.0 + 3.1.0
    @@ -101,21 +101,29 @@
  • Subpackages
  • @@ -189,6 +197,9 @@

    classification Package¶

    +
    +

    classification Package¶

    +

    AdvancedSampler Module¶

    @@ -377,6 +388,66 @@

    classification Package

    +
    +
    +

    ObjectSampler Module¶

    +
    +
    +class WORC.classification.ObjectSampler.ObjectSampler(method, sampling_strategy='auto', SMOTE_ratio=1, SMOTE_neighbors=5, n_jobs=1, n_neighbors=3)[source]¶
    +

    Bases: object

    +

    Samples objects for learning based on various under-, over- and combined sampling methods.

    +

    The choice of included methods is largely based on:

    +

    He, Haibo, and Edwardo A. Garcia. “Learning from imbalanced data.†+IEEE Transactions on Knowledge & Data Engineering 9 (2008): 1263-1284.

    +
    +
    +__dict__ = mappingproxy({'__module__': 'WORC.classification.ObjectSampler', '__doc__': '\n Samples objects for learning based on various under-, over- and combined sampling methods.\n\n The choice of included methods is largely based on:\n\n He, Haibo, and Edwardo A. Garcia. "Learning from imbalanced data."\n IEEE Transactions on Knowledge & Data Engineering 9 (2008): 1263-1284.\n\n\n ', '__init__': <function ObjectSampler.__init__>, 'init_RandomUnderSampling': <function ObjectSampler.init_RandomUnderSampling>, 'init_NearMiss': <function ObjectSampler.init_NearMiss>, 'init_RandomOverSampling': <function ObjectSampler.init_RandomOverSampling>, 'init_SMOTE': <function ObjectSampler.init_SMOTE>, 'fit': <function ObjectSampler.fit>, '__dict__': <attribute '__dict__' of 'ObjectSampler' objects>, '__weakref__': <attribute '__weakref__' of 'ObjectSampler' objects>})¶
    +
    + +
    +
    +__init__(method, sampling_strategy='auto', SMOTE_ratio=1, SMOTE_neighbors=5, n_jobs=1, n_neighbors=3)[source]¶
    +

    Initialize self. See help(type(self)) for accurate signature.

    +
    + +
    +
    +__module__ = 'WORC.classification.ObjectSampler'¶
    +
    + +
    +
    +__weakref__¶
    +

    list of weak references to the object (if defined)

    +
    + +
    +
    +fit(**kwargs)[source]¶
    +
    + +
    +
    +init_NearMiss(sampling_strategy, n_neighbors, n_jobs)[source]¶
    +
    + +
    +
    +init_RandomOverSampling(sampling_strategy)[source]¶
    +
    + +
    +
    +init_RandomUnderSampling(sampling_strategy)[source]¶
    +
    + +
    +
    +init_SMOTE()[source]¶
    +
    + +
    +

    RankedSVM Module¶

    @@ -385,70 +456,1434 @@

    classification PackageWORC.classification.RankedSVM.RankSVM_test(test_data, num_class, Weights, Bias, SVs, svm='Poly', gamma=0.05, coefficient=0.05, degree=3)[source]¶
    -
    -
    -WORC.classification.RankedSVM.RankSVM_test_original(test_data, test_target, Weights, Bias, SVs, svm='Poly', gamma=0.05, coefficient=0.05, degree=3)[source]¶
    -
    +
    +
    +WORC.classification.RankedSVM.RankSVM_test_original(test_data, test_target, Weights, Bias, SVs, svm='Poly', gamma=0.05, coefficient=0.05, degree=3)[source]¶
    +
    + +
    +
    +WORC.classification.RankedSVM.RankSVM_train(train_data, train_target, cost=1, lambda_tol=1e-06, norm_tol=0.0001, max_iter=500, svm='Poly', gamma=0.05, coefficient=0.05, degree=3)[source]¶
    +
    + +
    +
    +WORC.classification.RankedSVM.RankSVM_train_old(train_data, train_target, cost=1, lambda_tol=1e-06, norm_tol=0.0001, max_iter=500, svm='Poly', gamma=0.05, coefficient=0.05, degree=3)[source]¶
    +
    +

    Weights,Bias,SVs = RankSVM_train(train_data,train_target,cost,lambda_tol,norm_tol,max_iter,svm,gamma,coefficient,degree)

    +
    +

    Description

    +
    +
    +
    +
    RankSVM_train takes,

    train_data - An MxN array, the ith instance of training instance is stored in train_data[i,:] +train_target - A QxM array, if the ith training instance belongs to the jth class, then train_target[j,i] equals +1, otherwise train_target(j,i) equals -1

    +
    +
    +
    svm - svm gives the type of svm used in training, which can take the value of ‘RBF’, ‘Poly’ or ‘Linear’; svm.para gives the corresponding parameters used for the svm:
    +
      +
    1. if svm is ‘RBF’, then gamma gives the value of gamma, where the kernel is exp(-Gamma*|x[i]-x[j]|^2)

    2. +
    +
    +
      +
    1. if svm is ‘Poly’, then three values are used gamma, coefficient, and degree respectively, where the kernel is (gamma*<x[i],x[j]>+coefficient)^degree.

    2. +
    3. if svm is ‘Linear’, then svm is [].

    4. +
    +
    +
    +
    +

    cost - The value of ‘C’ used in the SVM, default=1 +lambda_tol - The tolerance value for lambda described in the appendix of [1]; default value is 1e-6 +norm_tol - The tolerance value for difference between alpha(p+1) and alpha(p) described in the appendix of [1]; default value is 1e-4 +max_iter - The maximum number of iterations for RankSVM, default=500

    +
    +
    and returns,

    Weights - The value for beta[ki] as described in the appendix of [1] is stored in Weights[k,i] +Bias - The value for b[i] as described in the appendix of [1] is stored in Bias[1,i] +SVs - The ith support vector is stored in SVs[:,i]

    +
    +
    +
    +

    For more details,please refer to [1] and [2].

    +
    +
    + +
    +
    +WORC.classification.RankedSVM.is_empty(any_structure)[source]¶
    +
    + +
    +
    +WORC.classification.RankedSVM.neg_dual_func(Lambda, Alpha_old, Alpha_new, c_value, kernel, num_training, num_class, Label, not_Label, Label_size, size_alpha)[source]¶
    +
    + +

    +
    +

    SearchCV Module¶

    +
    +
    +class WORC.classification.SearchCV.BaseSearchCV(param_distributions={}, n_iter=10, scoring=None, fit_params=None, n_jobs=1, iid=True, refit=True, cv=None, verbose=0, pre_dispatch='2*n_jobs', random_state=None, error_score='raise', return_train_score=True, n_jobspercore=100, maxlen=100, fastr_plugin=None, ranking_score='test_score')[source]¶
    +

    Bases: abc.NewBase

    +

    Base class for hyper parameter search with cross-validation.

    +
    +
    +__abstractmethods__ = frozenset({'__init__'})¶
    +
    + +
    +
    +__init__(param_distributions={}, n_iter=10, scoring=None, fit_params=None, n_jobs=1, iid=True, refit=True, cv=None, verbose=0, pre_dispatch='2*n_jobs', random_state=None, error_score='raise', return_train_score=True, n_jobspercore=100, maxlen=100, fastr_plugin=None, ranking_score='test_score')[source]¶
    +

    Initialize self. See help(type(self)) for accurate signature.

    +
    + +
    +
    +__module__ = 'WORC.classification.SearchCV'¶
    +
    + +
    +
    +best_params_¶
    +
    + +
    +
    +best_score_¶
    +
    + +
    +
    +create_ensemble(X_train, Y_train, verbose=None, initialize=True, scoring=None, method=50)[source]¶
    +

    Create an (optimal) ensemble of a combination of hyperparameter settings +and the associated groupsels, PCAs, estimators etc.

    +

    Based on Caruana et al. 2004, but a little different:

    +
      +
    1. Recreate the training/validation splits for a n-fold cross validation.

    2. +
    3. +
      For each fold:
        +
      1. Start with an empty ensemble

      2. +
      3. Create starting ensemble by adding N individually best performing +models on the validation set. N is tuned on the validation set.

      4. +
      5. Add model that improves ensemble performance on validation set the most, with replacement.

      6. +
      7. Repeat (c) untill performance does not increase

      8. +
      +
      +
      +
    4. +
    +

    The performance metric is the same as for the original hyperparameter +search, i.e. probably the F1-score for classification and r2-score +for regression. However, we recommend using the SAR score, as this is +more universal.

    +

    Method: top50 or Caruana

    +
    + +
    +
    +decision_function(X)[source]¶
    +

    Call decision_function on the estimator with the best found parameters.

    +

    Only available if refit=True and the underlying estimator supports +decision_function.

    +
    +
    Xindexable, length n_samples

    Must fulfill the input assumptions of the +underlying estimator.

    +
    +
    +
    + +
    +
    +inverse_transform(Xt)[source]¶
    +

    Call inverse_transform on the estimator with the best found params.

    +

    Only available if the underlying estimator implements +inverse_transform and refit=True.

    +
    +
    Xtindexable, length n_samples

    Must fulfill the input assumptions of the +underlying estimator.

    +
    +
    +
    + +
    +
    +predict(X)[source]¶
    +

    Call predict on the estimator with the best found parameters.

    +

    Only available if refit=True and the underlying estimator supports +predict.

    +
    +
    Xindexable, length n_samples

    Must fulfill the input assumptions of the +underlying estimator.

    +
    +
    +
    + +
    +
    +predict_log_proba(X)[source]¶
    +

    Call predict_log_proba on the estimator with the best found parameters.

    +

    Only available if refit=True and the underlying estimator supports +predict_log_proba.

    +
    +
    Xindexable, length n_samples

    Must fulfill the input assumptions of the +underlying estimator.

    +
    +
    +
    + +
    +
    +predict_proba(X)[source]¶
    +

    Call predict_proba on the estimator with the best found parameters.

    +

    Only available if refit=True and the underlying estimator supports +predict_proba.

    +
    +
    Xindexable, length n_samples

    Must fulfill the input assumptions of the +underlying estimator.

    +
    +
    +
    + +
    +
    +preprocess(X, y=None)[source]¶
    +

    Apply the available preprocssing methods to the features

    +
    + +
    +
    +process_fit(n_splits, parameters_est, parameters_all, test_sample_counts, test_scores, train_scores, fit_time, score_time, cv_iter, X, y)[source]¶
    +

    Process the outcomes of a SearchCV fit and find the best settings +over all cross validations from all hyperparameters tested

    +
    + +
    +
    +refit_and_score(X, y, parameters_all, parameters_est, train, test, verbose=None)[source]¶
    +

    Refit the base estimator and attributes such as GroupSel

    +
    +
    X: array, mandatory

    Array containingfor each object (rows) the feature values +(1st Column) and the associated feature label (2nd Column).

    +
    +
    y: list(?), mandatory

    List containing the labels of the objects.

    +
    +
    parameters_all: dictionary, mandatory

    Contains the settings used for the all preprocessing functions +and the fitting. TODO: Create a default object and show the +fields.

    +
    +
    parameters_est: dictionary, mandatory

    Contains the settings used for the base estimator

    +
    +
    train: list, mandatory

    Indices of the objects to be used as training set.

    +
    +
    test: list, mandatory

    Indices of the objects to be used as testing set.

    +
    +
    +
    + +
    +
    +score(X, y=None)[source]¶
    +

    Returns the score on the given data, if the estimator has been refit.

    +

    This uses the score defined by scoring where provided, and the +best_estimator_.score method otherwise.

    +
    +
    Xarray-like, shape = [n_samples, n_features]

    Input data, where n_samples is the number of samples and +n_features is the number of features.

    +
    +
    yarray-like, shape = [n_samples] or [n_samples, n_output], optional

    Target relative to X for classification or regression; +None for unsupervised learning.

    +
    +
    +

    score : float

    +
    + +
    +
    +transform(X)[source]¶
    +

    Call transform on the estimator with the best found parameters.

    +

    Only available if the underlying estimator supports transform and +refit=True.

    +
    +
    Xindexable, length n_samples

    Must fulfill the input assumptions of the +underlying estimator.

    +
    +
    +
    + +
    + +
    +
    +class WORC.classification.SearchCV.BaseSearchCVJoblib(param_distributions={}, n_iter=10, scoring=None, fit_params=None, n_jobs=1, iid=True, refit=True, cv=None, verbose=0, pre_dispatch='2*n_jobs', random_state=None, error_score='raise', return_train_score=True, n_jobspercore=100, maxlen=100, fastr_plugin=None, ranking_score='test_score')[source]¶
    +

    Bases: WORC.classification.SearchCV.BaseSearchCV

    +

    Base class for hyper parameter search with cross-validation.

    +
    +
    +__abstractmethods__ = frozenset({'__init__'})¶
    +
    + +
    +
    +__module__ = 'WORC.classification.SearchCV'¶
    +
    + +
    + +
    +
    +class WORC.classification.SearchCV.BaseSearchCVfastr(param_distributions={}, n_iter=10, scoring=None, fit_params=None, n_jobs=1, iid=True, refit=True, cv=None, verbose=0, pre_dispatch='2*n_jobs', random_state=None, error_score='raise', return_train_score=True, n_jobspercore=100, maxlen=100, fastr_plugin=None, ranking_score='test_score')[source]¶
    +

    Bases: WORC.classification.SearchCV.BaseSearchCV

    +

    Base class for hyper parameter search with cross-validation.

    +
    +
    +__abstractmethods__ = frozenset({'__init__'})¶
    +
    + +
    +
    +__module__ = 'WORC.classification.SearchCV'¶
    +
    + +
    + +
    +
    +class WORC.classification.SearchCV.Ensemble(estimators)[source]¶
    +

    Bases: abc.NewBase

    +

    Ensemble of BaseSearchCV Estimators.

    +
    +
    +__abstractmethods__ = frozenset({})¶
    +
    + +
    +
    +__init__(estimators)[source]¶
    +

    Initialize self. See help(type(self)) for accurate signature.

    +
    + +
    +
    +__module__ = 'WORC.classification.SearchCV'¶
    +
    + +
    +
    +decision_function(X)[source]¶
    +

    Call decision_function on the estimator with the best found parameters.

    +

    Only available if refit=True and the underlying estimator supports +decision_function.

    +
    +
    Xindexable, length n_samples

    Must fulfill the input assumptions of the +underlying estimator.

    +
    +
    +
    + +
    +
    +inverse_transform(Xt)[source]¶
    +

    Call inverse_transform on the estimator with the best found params.

    +

    Only available if the underlying estimator implements +inverse_transform and refit=True.

    +
    +
    Xtindexable, length n_samples

    Must fulfill the input assumptions of the +underlying estimator.

    +
    +
    +
    + +
    +
    +predict(X)[source]¶
    +

    Call predict on the estimator with the best found parameters.

    +

    Only available if refit=True and the underlying estimator supports +predict.

    +
    +
    Xindexable, length n_samples

    Must fulfill the input assumptions of the +underlying estimator.

    +
    +
    +
    + +
    +
    +predict_log_proba(X)[source]¶
    +

    Call predict_log_proba on the estimator with the best found parameters.

    +

    Only available if refit=True and the underlying estimator supports +predict_log_proba.

    +
    +
    Xindexable, length n_samples

    Must fulfill the input assumptions of the +underlying estimator.

    +
    +
    +
    + +
    +
    +predict_proba(X)[source]¶
    +

    Call predict_proba on the estimator with the best found parameters.

    +

    Only available if refit=True and the underlying estimator supports +predict_proba.

    +
    +
    Xindexable, length n_samples

    Must fulfill the input assumptions of the +underlying estimator.

    +
    +
    +
    + +
    +
    +transform(X)[source]¶
    +

    Call transform on the estimator with the best found parameters.

    +

    Only available if the underlying estimator supports transform and +refit=True.

    +
    +
    Xindexable, length n_samples

    Must fulfill the input assumptions of the +underlying estimator.

    +
    +
    +
    + +
    + +
    +
    +class WORC.classification.SearchCV.GridSearchCVJoblib(estimator, param_grid, scoring=None, fit_params=None, n_jobs=1, iid=True, refit=True, cv=None, verbose=0, pre_dispatch='2*n_jobs', error_score='raise', return_train_score=True)[source]¶
    +

    Bases: WORC.classification.SearchCV.BaseSearchCVJoblib

    +

    Exhaustive search over specified parameter values for an estimator.

    +

    Important members are fit, predict.

    +

    GridSearchCV implements a “fit†and a “score†method. +It also implements “predictâ€, “predict_probaâ€, “decision_functionâ€, +“transform†and “inverse_transform†if they are implemented in the +estimator used.

    +

    The parameters of the estimator used to apply these methods are optimized +by cross-validated grid-search over a parameter grid.

    +

    Read more in the User Guide.

    +
    +
    estimatorestimator object.

    This is assumed to implement the scikit-learn estimator interface. +Either estimator needs to provide a score function, +or scoring must be passed.

    +
    +
    param_griddict or list of dictionaries

    Dictionary with parameters names (string) as keys and lists of +parameter settings to try as values, or a list of such +dictionaries, in which case the grids spanned by each dictionary +in the list are explored. This enables searching over any sequence +of parameter settings.

    +
    +
    scoringstring, callable or None, default=None

    A string (see model evaluation documentation) or +a scorer callable object / function with signature +scorer(estimator, X, y). +If None, the score method of the estimator is used.

    +
    +
    fit_paramsdict, optional

    Parameters to pass to the fit method.

    +
    +
    n_jobsint, default=1

    Number of jobs to run in parallel.

    +
    +
    pre_dispatchint, or string, optional

    Controls the number of jobs that get dispatched during parallel +execution. Reducing this number can be useful to avoid an +explosion of memory consumption when more jobs get dispatched +than CPUs can process. This parameter can be:

    +
    +
      +
    • None, in which case all the jobs are immediately +created and spawned. Use this for lightweight and +fast-running jobs, to avoid delays due to on-demand +spawning of the jobs

    • +
    • An int, giving the exact number of total jobs that are +spawned

    • +
    • A string, giving an expression as a function of n_jobs, +as in ‘2*n_jobs’

    • +
    +
    +
    +
    iidboolean, default=True

    If True, the data is assumed to be identically distributed across +the folds, and the loss minimized is the total loss per sample, +and not the mean loss across the folds.

    +
    +
    cvint, cross-validation generator or an iterable, optional

    Determines the cross-validation splitting strategy. +Possible inputs for cv are:

    +
    +
      +
    • None, to use the default 3-fold cross validation,

    • +
    • integer, to specify the number of folds in a (Stratified)KFold,

    • +
    • An object to be used as a cross-validation generator.

    • +
    • An iterable yielding train, test splits.

    • +
    +
    +

    For integer/None inputs, if the estimator is a classifier and y is +either binary or multiclass, StratifiedKFold is used. In all +other cases, KFold is used.

    +

    Refer User Guide for the various +cross-validation strategies that can be used here.

    +
    +
    refitboolean, default=True

    Refit the best estimator with the entire dataset. +If “Falseâ€, it is impossible to make predictions using +this GridSearchCV instance after fitting.

    +
    +
    verboseinteger

    Controls the verbosity: the higher, the more messages.

    +
    +
    error_score‘raise’ (default) or numeric

    Value to assign to the score if an error occurs in estimator fitting. +If set to ‘raise’, the error is raised. If a numeric value is given, +FitFailedWarning is raised. This parameter does not affect the refit +step, which will always raise the error.

    +
    +
    return_train_scoreboolean, default=True

    If 'False', the cv_results_ attribute will not include training +scores.

    +
    +
    +
    >>> from sklearn import svm, datasets
    +>>> from sklearn.model_selection import GridSearchCV
    +>>> iris = datasets.load_iris()
    +>>> parameters = {'kernel':('linear', 'rbf'), 'C':[1, 10]}
    +>>> svr = svm.SVC()
    +>>> clf = GridSearchCV(svr, parameters)
    +>>> clf.fit(iris.data, iris.target)
    +...                             # doctest: +NORMALIZE_WHITESPACE +ELLIPSIS
    +GridSearchCV(cv=None, error_score=...,
    +       estimator=SVC(C=1.0, cache_size=..., class_weight=..., coef0=...,
    +                     decision_function_shape=None, degree=..., gamma=...,
    +                     kernel='rbf', max_iter=-1, probability=False,
    +                     random_state=None, shrinking=True, tol=...,
    +                     verbose=False),
    +       fit_params={}, iid=..., n_jobs=1,
    +       param_grid=..., pre_dispatch=..., refit=..., return_train_score=...,
    +       scoring=..., verbose=...)
    +>>> sorted(clf.cv_results_.keys())
    +...                             # doctest: +NORMALIZE_WHITESPACE +ELLIPSIS
    +['mean_fit_time', 'mean_score_time', 'mean_test_score',...
    + 'mean_train_score', 'param_C', 'param_kernel', 'params',...
    + 'rank_test_score', 'split0_test_score',...
    + 'split0_train_score', 'split1_test_score', 'split1_train_score',...
    + 'split2_test_score', 'split2_train_score',...
    + 'std_fit_time', 'std_score_time', 'std_test_score', 'std_train_score'...]
    +
    +
    +
    +
    cv_results_dict of numpy (masked) ndarrays

    A dict with keys as column headers and values as columns, that can be +imported into a pandas DataFrame.

    +

    For instance the below given table

    + ++++++++ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +

    param_kernel

    param_gamma

    param_degree

    split0_test_score

    …

    rank_….

    ‘poly’

    –

    2

    0.8

    …

    2

    ‘poly’

    –

    3

    0.7

    …

    4

    ‘rbf’

    0.1

    –

    0.8

    …

    3

    ‘rbf’

    0.2

    –

    0.9

    …

    1

    +

    will be represented by a cv_results_ dict of:

    +
    {
    +'param_kernel': masked_array(data = ['poly', 'poly', 'rbf', 'rbf'],
    +                             mask = [False False False False]...)
    +'param_gamma': masked_array(data = [-- -- 0.1 0.2],
    +                            mask = [ True  True False False]...),
    +'param_degree': masked_array(data = [2.0 3.0 -- --],
    +                             mask = [False False  True  True]...),
    +'split0_test_score'  : [0.8, 0.7, 0.8, 0.9],
    +'split1_test_score'  : [0.82, 0.5, 0.7, 0.78],
    +'mean_test_score'    : [0.81, 0.60, 0.75, 0.82],
    +'std_test_score'     : [0.02, 0.01, 0.03, 0.03],
    +'rank_test_score'    : [2, 4, 3, 1],
    +'split0_train_score' : [0.8, 0.9, 0.7],
    +'split1_train_score' : [0.82, 0.5, 0.7],
    +'mean_train_score'   : [0.81, 0.7, 0.7],
    +'std_train_score'    : [0.03, 0.03, 0.04],
    +'mean_fit_time'      : [0.73, 0.63, 0.43, 0.49],
    +'std_fit_time'       : [0.01, 0.02, 0.01, 0.01],
    +'mean_score_time'    : [0.007, 0.06, 0.04, 0.04],
    +'std_score_time'     : [0.001, 0.002, 0.003, 0.005],
    +'params'             : [{'kernel': 'poly', 'degree': 2}, ...],
    +}
    +
    +
    +

    NOTE that the key 'params' is used to store a list of parameter +settings dict for all the parameter candidates.

    +

    The mean_fit_time, std_fit_time, mean_score_time and +std_score_time are all in seconds.

    +
    +
    best_estimator_estimator

    Estimator that was chosen by the search, i.e. estimator +which gave highest score (or smallest loss if specified) +on the left out data. Not available if refit=False.

    +
    +
    best_score_float

    Score of best_estimator on the left out data.

    +
    +
    best_params_dict

    Parameter setting that gave the best results on the hold out data.

    +
    +
    best_index_int

    The index (of the cv_results_ arrays) which corresponds to the best +candidate parameter setting.

    +

    The dict at search.cv_results_['params'][search.best_index_] gives +the parameter setting for the best model, that gives the highest +mean score (search.best_score_).

    +
    +
    scorer_function

    Scorer function used on the held out data to choose the best +parameters for the model.

    +
    +
    n_splits_int

    The number of cross-validation splits (folds/iterations).

    +
    +
    +

    The parameters selected are those that maximize the score of the left out +data, unless an explicit score is passed in which case it is used instead.

    +

    If n_jobs was set to a value higher than one, the data is copied for each +point in the grid (and not n_jobs times). This is done for efficiency +reasons if individual jobs take very little time, but may raise errors if +the dataset is large and not enough memory is available. A workaround in +this case is to set pre_dispatch. Then, the memory is copied only +pre_dispatch many times. A reasonable value for pre_dispatch is 2 * +n_jobs.

    +
    +
    ParameterGrid:

    generates all the combinations of a hyperparameter grid.

    +
    +
    sklearn.model_selection.train_test_split():

    utility function to split the data into a development set usable +for fitting a GridSearchCV instance and an evaluation set for +its final evaluation.

    +
    +
    sklearn.metrics.make_scorer():

    Make a scorer from a performance metric or loss function.

    +
    +
    +
    +
    +__abstractmethods__ = frozenset({})¶
    +
    + +
    +
    +__init__(estimator, param_grid, scoring=None, fit_params=None, n_jobs=1, iid=True, refit=True, cv=None, verbose=0, pre_dispatch='2*n_jobs', error_score='raise', return_train_score=True)[source]¶
    +

    Initialize self. See help(type(self)) for accurate signature.

    +
    + +
    +
    +__module__ = 'WORC.classification.SearchCV'¶
    +
    + +
    +
    +fit(X, y=None, groups=None)[source]¶
    +

    Run fit with all sets of parameters.

    +
    +
    Xarray-like, shape = [n_samples, n_features]

    Training vector, where n_samples is the number of samples and +n_features is the number of features.

    +
    +
    yarray-like, shape = [n_samples] or [n_samples, n_output], optional

    Target relative to X for classification or regression; +None for unsupervised learning.

    +
    +
    groupsarray-like, with shape (n_samples,), optional

    Group labels for the samples used while splitting the dataset into +train/test set.

    +
    +
    +
    + +
    + +
    +
    +class WORC.classification.SearchCV.GridSearchCVfastr(estimator, param_grid, scoring=None, fit_params=None, n_jobs=1, iid=True, refit=True, cv=None, verbose=0, pre_dispatch='2*n_jobs', error_score='raise', return_train_score=True)[source]¶
    +

    Bases: WORC.classification.SearchCV.BaseSearchCVfastr

    +

    Exhaustive search over specified parameter values for an estimator.

    +

    Important members are fit, predict.

    +

    GridSearchCV implements a “fit†and a “score†method. +It also implements “predictâ€, “predict_probaâ€, “decision_functionâ€, +“transform†and “inverse_transform†if they are implemented in the +estimator used.

    +

    The parameters of the estimator used to apply these methods are optimized +by cross-validated grid-search over a parameter grid.

    +

    Read more in the User Guide.

    +
    +
    estimatorestimator object.

    This is assumed to implement the scikit-learn estimator interface. +Either estimator needs to provide a score function, +or scoring must be passed.

    +
    +
    param_griddict or list of dictionaries

    Dictionary with parameters names (string) as keys and lists of +parameter settings to try as values, or a list of such +dictionaries, in which case the grids spanned by each dictionary +in the list are explored. This enables searching over any sequence +of parameter settings.

    +
    +
    scoringstring, callable or None, default=None

    A string (see model evaluation documentation) or +a scorer callable object / function with signature +scorer(estimator, X, y). +If None, the score method of the estimator is used.

    +
    +
    fit_paramsdict, optional

    Parameters to pass to the fit method.

    +
    +
    n_jobsint, default=1

    Number of jobs to run in parallel.

    +
    +
    pre_dispatchint, or string, optional

    Controls the number of jobs that get dispatched during parallel +execution. Reducing this number can be useful to avoid an +explosion of memory consumption when more jobs get dispatched +than CPUs can process. This parameter can be:

    +
    +
      +
    • None, in which case all the jobs are immediately +created and spawned. Use this for lightweight and +fast-running jobs, to avoid delays due to on-demand +spawning of the jobs

    • +
    • An int, giving the exact number of total jobs that are +spawned

    • +
    • A string, giving an expression as a function of n_jobs, +as in ‘2*n_jobs’

    • +
    +
    +
    +
    iidboolean, default=True

    If True, the data is assumed to be identically distributed across +the folds, and the loss minimized is the total loss per sample, +and not the mean loss across the folds.

    +
    +
    cvint, cross-validation generator or an iterable, optional

    Determines the cross-validation splitting strategy. +Possible inputs for cv are:

    +
    +
      +
    • None, to use the default 3-fold cross validation,

    • +
    • integer, to specify the number of folds in a (Stratified)KFold,

    • +
    • An object to be used as a cross-validation generator.

    • +
    • An iterable yielding train, test splits.

    • +
    +
    +

    For integer/None inputs, if the estimator is a classifier and y is +either binary or multiclass, StratifiedKFold is used. In all +other cases, KFold is used.

    +

    Refer User Guide for the various +cross-validation strategies that can be used here.

    +
    +
    refitboolean, default=True

    Refit the best estimator with the entire dataset. +If “Falseâ€, it is impossible to make predictions using +this GridSearchCV instance after fitting.

    +
    +
    verboseinteger

    Controls the verbosity: the higher, the more messages.

    +
    +
    error_score‘raise’ (default) or numeric

    Value to assign to the score if an error occurs in estimator fitting. +If set to ‘raise’, the error is raised. If a numeric value is given, +FitFailedWarning is raised. This parameter does not affect the refit +step, which will always raise the error.

    +
    +
    return_train_scoreboolean, default=True

    If 'False', the cv_results_ attribute will not include training +scores.

    +
    +
    +
    >>> from sklearn import svm, datasets
    +>>> from sklearn.model_selection import GridSearchCV
    +>>> iris = datasets.load_iris()
    +>>> parameters = {'kernel':('linear', 'rbf'), 'C':[1, 10]}
    +>>> svr = svm.SVC()
    +>>> clf = GridSearchCV(svr, parameters)
    +>>> clf.fit(iris.data, iris.target)
    +...                             # doctest: +NORMALIZE_WHITESPACE +ELLIPSIS
    +GridSearchCV(cv=None, error_score=...,
    +       estimator=SVC(C=1.0, cache_size=..., class_weight=..., coef0=...,
    +                     decision_function_shape=None, degree=..., gamma=...,
    +                     kernel='rbf', max_iter=-1, probability=False,
    +                     random_state=None, shrinking=True, tol=...,
    +                     verbose=False),
    +       fit_params={}, iid=..., n_jobs=1,
    +       param_grid=..., pre_dispatch=..., refit=..., return_train_score=...,
    +       scoring=..., verbose=...)
    +>>> sorted(clf.cv_results_.keys())
    +...                             # doctest: +NORMALIZE_WHITESPACE +ELLIPSIS
    +['mean_fit_time', 'mean_score_time', 'mean_test_score',...
    + 'mean_train_score', 'param_C', 'param_kernel', 'params',...
    + 'rank_test_score', 'split0_test_score',...
    + 'split0_train_score', 'split1_test_score', 'split1_train_score',...
    + 'split2_test_score', 'split2_train_score',...
    + 'std_fit_time', 'std_score_time', 'std_test_score', 'std_train_score'...]
    +
    +
    +
    +
    cv_results_dict of numpy (masked) ndarrays

    A dict with keys as column headers and values as columns, that can be +imported into a pandas DataFrame.

    +

    For instance the below given table

    + ++++++++ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +

    param_kernel

    param_gamma

    param_degree

    split0_test_score

    …

    rank_….

    ‘poly’

    –

    2

    0.8

    …

    2

    ‘poly’

    –

    3

    0.7

    …

    4

    ‘rbf’

    0.1

    –

    0.8

    …

    3

    ‘rbf’

    0.2

    –

    0.9

    …

    1

    +

    will be represented by a cv_results_ dict of:

    +
    {
    +'param_kernel': masked_array(data = ['poly', 'poly', 'rbf', 'rbf'],
    +                             mask = [False False False False]...)
    +'param_gamma': masked_array(data = [-- -- 0.1 0.2],
    +                            mask = [ True  True False False]...),
    +'param_degree': masked_array(data = [2.0 3.0 -- --],
    +                             mask = [False False  True  True]...),
    +'split0_test_score'  : [0.8, 0.7, 0.8, 0.9],
    +'split1_test_score'  : [0.82, 0.5, 0.7, 0.78],
    +'mean_test_score'    : [0.81, 0.60, 0.75, 0.82],
    +'std_test_score'     : [0.02, 0.01, 0.03, 0.03],
    +'rank_test_score'    : [2, 4, 3, 1],
    +'split0_train_score' : [0.8, 0.9, 0.7],
    +'split1_train_score' : [0.82, 0.5, 0.7],
    +'mean_train_score'   : [0.81, 0.7, 0.7],
    +'std_train_score'    : [0.03, 0.03, 0.04],
    +'mean_fit_time'      : [0.73, 0.63, 0.43, 0.49],
    +'std_fit_time'       : [0.01, 0.02, 0.01, 0.01],
    +'mean_score_time'    : [0.007, 0.06, 0.04, 0.04],
    +'std_score_time'     : [0.001, 0.002, 0.003, 0.005],
    +'params'             : [{'kernel': 'poly', 'degree': 2}, ...],
    +}
    +
    +
    +

    NOTE that the key 'params' is used to store a list of parameter +settings dict for all the parameter candidates.

    +

    The mean_fit_time, std_fit_time, mean_score_time and +std_score_time are all in seconds.

    +
    +
    best_estimator_estimator

    Estimator that was chosen by the search, i.e. estimator +which gave highest score (or smallest loss if specified) +on the left out data. Not available if refit=False.

    +
    +
    best_score_float

    Score of best_estimator on the left out data.

    +
    +
    best_params_dict

    Parameter setting that gave the best results on the hold out data.

    +
    +
    best_index_int

    The index (of the cv_results_ arrays) which corresponds to the best +candidate parameter setting.

    +

    The dict at search.cv_results_['params'][search.best_index_] gives +the parameter setting for the best model, that gives the highest +mean score (search.best_score_).

    +
    +
    scorer_function

    Scorer function used on the held out data to choose the best +parameters for the model.

    +
    +
    n_splits_int

    The number of cross-validation splits (folds/iterations).

    +
    +
    +

    The parameters selected are those that maximize the score of the left out +data, unless an explicit score is passed in which case it is used instead.

    +

    If n_jobs was set to a value higher than one, the data is copied for each +point in the grid (and not n_jobs times). This is done for efficiency +reasons if individual jobs take very little time, but may raise errors if +the dataset is large and not enough memory is available. A workaround in +this case is to set pre_dispatch. Then, the memory is copied only +pre_dispatch many times. A reasonable value for pre_dispatch is 2 * +n_jobs.

    +
    +
    ParameterGrid:

    generates all the combinations of a hyperparameter grid.

    +
    +
    sklearn.model_selection.train_test_split():

    utility function to split the data into a development set usable +for fitting a GridSearchCV instance and an evaluation set for +its final evaluation.

    +
    +
    sklearn.metrics.make_scorer():

    Make a scorer from a performance metric or loss function.

    +
    +
    +
    +
    +__abstractmethods__ = frozenset({})¶
    +
    + +
    +
    +__init__(estimator, param_grid, scoring=None, fit_params=None, n_jobs=1, iid=True, refit=True, cv=None, verbose=0, pre_dispatch='2*n_jobs', error_score='raise', return_train_score=True)[source]¶
    +

    Initialize self. See help(type(self)) for accurate signature.

    +
    + +
    +
    +__module__ = 'WORC.classification.SearchCV'¶
    +
    + +
    +
    +fit(X, y=None, groups=None)[source]¶
    +

    Run fit with all sets of parameters.

    +
    +
    Xarray-like, shape = [n_samples, n_features]

    Training vector, where n_samples is the number of samples and +n_features is the number of features.

    +
    +
    yarray-like, shape = [n_samples] or [n_samples, n_output], optional

    Target relative to X for classification or regression; +None for unsupervised learning.

    +
    +
    groupsarray-like, with shape (n_samples,), optional

    Group labels for the samples used while splitting the dataset into +train/test set.

    +
    +
    +
    + +
    + +
    +
    +class WORC.classification.SearchCV.RandomizedSearchCVJoblib(param_distributions={}, n_iter=10, scoring=None, fit_params=None, n_jobs=1, iid=True, refit=True, cv=None, verbose=0, pre_dispatch='2*n_jobs', random_state=None, error_score='raise', return_train_score=True, n_jobspercore=100, maxlen=100, ranking_score='test_score')[source]¶
    +

    Bases: WORC.classification.SearchCV.BaseSearchCVJoblib

    +

    Randomized search on hyper parameters.

    +

    RandomizedSearchCV implements a “fit†and a “score†method. +It also implements “predictâ€, “predict_probaâ€, “decision_functionâ€, +“transform†and “inverse_transform†if they are implemented in the +estimator used.

    +

    The parameters of the estimator used to apply these methods are optimized +by cross-validated search over parameter settings.

    +

    In contrast to GridSearchCV, not all parameter values are tried out, but +rather a fixed number of parameter settings is sampled from the specified +distributions. The number of parameter settings that are tried is +given by n_iter.

    +

    If all parameters are presented as a list, +sampling without replacement is performed. If at least one parameter +is given as a distribution, sampling with replacement is used. +It is highly recommended to use continuous distributions for continuous +parameters.

    +

    Read more in the User Guide.

    +
    +
    estimatorestimator object.

    A object of that type is instantiated for each grid point. +This is assumed to implement the scikit-learn estimator interface. +Either estimator needs to provide a score function, +or scoring must be passed.

    +
    +
    param_distributionsdict

    Dictionary with parameters names (string) as keys and distributions +or lists of parameters to try. Distributions must provide a rvs +method for sampling (such as those from scipy.stats.distributions). +If a list is given, it is sampled uniformly.

    +
    +
    n_iterint, default=10

    Number of parameter settings that are sampled. n_iter trades +off runtime vs quality of the solution.

    +
    +
    scoringstring, callable or None, default=None

    A string (see model evaluation documentation) or +a scorer callable object / function with signature +scorer(estimator, X, y). +If None, the score method of the estimator is used.

    +
    +
    fit_paramsdict, optional

    Parameters to pass to the fit method.

    +
    +
    n_jobsint, default=1

    Number of jobs to run in parallel.

    +
    +
    pre_dispatchint, or string, optional

    Controls the number of jobs that get dispatched during parallel +execution. Reducing this number can be useful to avoid an +explosion of memory consumption when more jobs get dispatched +than CPUs can process. This parameter can be:

    +
    +
      +
    • None, in which case all the jobs are immediately +created and spawned. Use this for lightweight and +fast-running jobs, to avoid delays due to on-demand +spawning of the jobs

    • +
    • An int, giving the exact number of total jobs that are +spawned

    • +
    • A string, giving an expression as a function of n_jobs, +as in ‘2*n_jobs’

    • +
    +
    +
    +
    iidboolean, default=True

    If True, the data is assumed to be identically distributed across +the folds, and the loss minimized is the total loss per sample, +and not the mean loss across the folds.

    +
    +
    cvint, cross-validation generator or an iterable, optional

    Determines the cross-validation splitting strategy. +Possible inputs for cv are:

    +
    +
      +
    • None, to use the default 3-fold cross validation,

    • +
    • integer, to specify the number of folds in a (Stratified)KFold,

    • +
    • An object to be used as a cross-validation generator.

    • +
    • An iterable yielding train, test splits.

    • +
    +
    +

    For integer/None inputs, if the estimator is a classifier and y is +either binary or multiclass, StratifiedKFold is used. In all +other cases, KFold is used.

    +

    Refer User Guide for the various +cross-validation strategies that can be used here.

    +
    +
    refitboolean, default=True

    Refit the best estimator with the entire dataset. +If “Falseâ€, it is impossible to make predictions using +this RandomizedSearchCV instance after fitting.

    +
    +
    verboseinteger

    Controls the verbosity: the higher, the more messages.

    +
    +
    random_stateint or RandomState

    Pseudo random number generator state used for random uniform sampling +from lists of possible values instead of scipy.stats distributions.

    +
    +
    error_score‘raise’ (default) or numeric

    Value to assign to the score if an error occurs in estimator fitting. +If set to ‘raise’, the error is raised. If a numeric value is given, +FitFailedWarning is raised. This parameter does not affect the refit +step, which will always raise the error.

    +
    +
    return_train_scoreboolean, default=True

    If 'False', the cv_results_ attribute will not include training +scores.

    +
    +
    +
    +
    cv_results_dict of numpy (masked) ndarrays

    A dict with keys as column headers and values as columns, that can be +imported into a pandas DataFrame.

    +

    For instance the below given table

    + +++++++ + + + + + + + + + + + + + + + + + + + + + + + + + + + + +

    param_kernel

    param_gamma

    split0_test_score

    …

    rank_test_score

    ‘rbf’

    0.1

    0.8

    …

    2

    ‘rbf’

    0.2

    0.9

    …

    1

    ‘rbf’

    0.3

    0.7

    …

    1

    +

    will be represented by a cv_results_ dict of:

    +
    {
    +'param_kernel' : masked_array(data = ['rbf', 'rbf', 'rbf'],
    +                              mask = False),
    +'param_gamma'  : masked_array(data = [0.1 0.2 0.3], mask = False),
    +'split0_test_score'  : [0.8, 0.9, 0.7],
    +'split1_test_score'  : [0.82, 0.5, 0.7],
    +'mean_test_score'    : [0.81, 0.7, 0.7],
    +'std_test_score'     : [0.02, 0.2, 0.],
    +'rank_test_score'    : [3, 1, 1],
    +'split0_train_score' : [0.8, 0.9, 0.7],
    +'split1_train_score' : [0.82, 0.5, 0.7],
    +'mean_train_score'   : [0.81, 0.7, 0.7],
    +'std_train_score'    : [0.03, 0.03, 0.04],
    +'mean_fit_time'      : [0.73, 0.63, 0.43, 0.49],
    +'std_fit_time'       : [0.01, 0.02, 0.01, 0.01],
    +'mean_score_time'    : [0.007, 0.06, 0.04, 0.04],
    +'std_score_time'     : [0.001, 0.002, 0.003, 0.005],
    +'params' : [{'kernel' : 'rbf', 'gamma' : 0.1}, ...],
    +}
    +
    +
    +

    NOTE that the key 'params' is used to store a list of parameter +settings dict for all the parameter candidates.

    +

    The mean_fit_time, std_fit_time, mean_score_time and +std_score_time are all in seconds.

    +
    +
    best_estimator_estimator

    Estimator that was chosen by the search, i.e. estimator +which gave highest score (or smallest loss if specified) +on the left out data. Not available if refit=False.

    +
    +
    best_score_float

    Score of best_estimator on the left out data.

    +
    +
    best_params_dict

    Parameter setting that gave the best results on the hold out data.

    +
    +
    best_index_int

    The index (of the cv_results_ arrays) which corresponds to the best +candidate parameter setting.

    +

    The dict at search.cv_results_['params'][search.best_index_] gives +the parameter setting for the best model, that gives the highest +mean score (search.best_score_).

    +
    +
    scorer_function

    Scorer function used on the held out data to choose the best +parameters for the model.

    +
    +
    n_splits_int

    The number of cross-validation splits (folds/iterations).

    +
    +
    +

    The parameters selected are those that maximize the score of the held-out +data, according to the scoring parameter.

    +

    If n_jobs was set to a value higher than one, the data is copied for each +parameter setting(and not n_jobs times). This is done for efficiency +reasons if individual jobs take very little time, but may raise errors if +the dataset is large and not enough memory is available. A workaround in +this case is to set pre_dispatch. Then, the memory is copied only +pre_dispatch many times. A reasonable value for pre_dispatch is 2 * +n_jobs.

    +
    +
    GridSearchCV:

    Does exhaustive search over a grid of parameters.

    +
    +
    ParameterSampler:

    A generator over parameter settins, constructed from +param_distributions.

    +
    +
    +
    +
    +__abstractmethods__ = frozenset({})¶
    +
    + +
    +
    +__init__(param_distributions={}, n_iter=10, scoring=None, fit_params=None, n_jobs=1, iid=True, refit=True, cv=None, verbose=0, pre_dispatch='2*n_jobs', random_state=None, error_score='raise', return_train_score=True, n_jobspercore=100, maxlen=100, ranking_score='test_score')[source]¶
    +

    Initialize self. See help(type(self)) for accurate signature.

    +
    -
    -
    -WORC.classification.RankedSVM.RankSVM_train(train_data, train_target, cost=1, lambda_tol=1e-06, norm_tol=0.0001, max_iter=500, svm='Poly', gamma=0.05, coefficient=0.05, degree=3)[source]¶
    +
    +
    +__module__ = 'WORC.classification.SearchCV'¶
    -
    -
    -WORC.classification.RankedSVM.RankSVM_train_old(train_data, train_target, cost=1, lambda_tol=1e-06, norm_tol=0.0001, max_iter=500, svm='Poly', gamma=0.05, coefficient=0.05, degree=3)[source]¶
    -
    -

    Weights,Bias,SVs = RankSVM_train(train_data,train_target,cost,lambda_tol,norm_tol,max_iter,svm,gamma,coefficient,degree)

    -
    -

    Description

    +
    +
    +fit(X, y=None, groups=None)[source]¶
    +

    Run fit on the estimator with randomly drawn parameters.

    +
    +
    Xarray-like, shape = [n_samples, n_features]

    Training vector, where n_samples in the number of samples and +n_features is the number of features.

    +
    +
    yarray-like, shape = [n_samples] or [n_samples, n_output], optional

    Target relative to X for classification or regression; +None for unsupervised learning.

    +
    +
    groupsarray-like, with shape (n_samples,), optional

    Group labels for the samples used while splitting the dataset into +train/test set.

    +
    +
    +
    + +
    + +
    +
    +class WORC.classification.SearchCV.RandomizedSearchCVfastr(param_distributions={}, n_iter=10, scoring=None, fit_params=None, n_jobs=1, iid=True, refit=True, cv=None, verbose=0, pre_dispatch='2*n_jobs', random_state=None, error_score='raise', return_train_score=True, n_jobspercore=100, fastr_plugin=None, maxlen=100, ranking_score='test_score')[source]¶
    +

    Bases: WORC.classification.SearchCV.BaseSearchCVfastr

    +

    Randomized search on hyper parameters.

    +

    RandomizedSearchCV implements a “fit†and a “score†method. +It also implements “predictâ€, “predict_probaâ€, “decision_functionâ€, +“transform†and “inverse_transform†if they are implemented in the +estimator used.

    +

    The parameters of the estimator used to apply these methods are optimized +by cross-validated search over parameter settings.

    +

    In contrast to GridSearchCV, not all parameter values are tried out, but +rather a fixed number of parameter settings is sampled from the specified +distributions. The number of parameter settings that are tried is +given by n_iter.

    +

    If all parameters are presented as a list, +sampling without replacement is performed. If at least one parameter +is given as a distribution, sampling with replacement is used. +It is highly recommended to use continuous distributions for continuous +parameters.

    +

    Read more in the User Guide.

    +
    +
    estimatorestimator object.

    A object of that type is instantiated for each grid point. +This is assumed to implement the scikit-learn estimator interface. +Either estimator needs to provide a score function, +or scoring must be passed.

    +
    +
    param_distributionsdict

    Dictionary with parameters names (string) as keys and distributions +or lists of parameters to try. Distributions must provide a rvs +method for sampling (such as those from scipy.stats.distributions). +If a list is given, it is sampled uniformly.

    +
    +
    n_iterint, default=10

    Number of parameter settings that are sampled. n_iter trades +off runtime vs quality of the solution.

    +
    +
    scoringstring, callable or None, default=None

    A string (see model evaluation documentation) or +a scorer callable object / function with signature +scorer(estimator, X, y). +If None, the score method of the estimator is used.

    +
    +
    fit_paramsdict, optional

    Parameters to pass to the fit method.

    +
    +
    n_jobsint, default=1

    Number of jobs to run in parallel.

    +
    +
    pre_dispatchint, or string, optional

    Controls the number of jobs that get dispatched during parallel +execution. Reducing this number can be useful to avoid an +explosion of memory consumption when more jobs get dispatched +than CPUs can process. This parameter can be:

    -
    -
    -
    RankSVM_train takes,

    train_data - An MxN array, the ith instance of training instance is stored in train_data[i,:] -train_target - A QxM array, if the ith training instance belongs to the jth class, then train_target[j,i] equals +1, otherwise train_target(j,i) equals -1

    +
      +
    • None, in which case all the jobs are immediately +created and spawned. Use this for lightweight and +fast-running jobs, to avoid delays due to on-demand +spawning of the jobs

    • +
    • An int, giving the exact number of total jobs that are +spawned

    • +
    • A string, giving an expression as a function of n_jobs, +as in ‘2*n_jobs’

    • +
    +
    +
    +
    iidboolean, default=True

    If True, the data is assumed to be identically distributed across +the folds, and the loss minimized is the total loss per sample, +and not the mean loss across the folds.

    +
    +
    cvint, cross-validation generator or an iterable, optional

    Determines the cross-validation splitting strategy. +Possible inputs for cv are:

    -
    -
    svm - svm gives the type of svm used in training, which can take the value of ‘RBF’, ‘Poly’ or ‘Linear’; svm.para gives the corresponding parameters used for the svm:
    -
      -
    1. if svm is ‘RBF’, then gamma gives the value of gamma, where the kernel is exp(-Gamma*|x[i]-x[j]|^2)

    2. -
    +
      +
    • None, to use the default 3-fold cross validation,

    • +
    • integer, to specify the number of folds in a (Stratified)KFold,

    • +
    • An object to be used as a cross-validation generator.

    • +
    • An iterable yielding train, test splits.

    • +
    -
      -
    1. if svm is ‘Poly’, then three values are used gamma, coefficient, and degree respectively, where the kernel is (gamma*<x[i],x[j]>+coefficient)^degree.

    2. -
    3. if svm is ‘Linear’, then svm is [].

    4. -
    +

    For integer/None inputs, if the estimator is a classifier and y is +either binary or multiclass, StratifiedKFold is used. In all +other cases, KFold is used.

    +

    Refer User Guide for the various +cross-validation strategies that can be used here.

    +
    +
    refitboolean, default=True

    Refit the best estimator with the entire dataset. +If “Falseâ€, it is impossible to make predictions using +this RandomizedSearchCV instance after fitting.

    +
    +
    verboseinteger

    Controls the verbosity: the higher, the more messages.

    +
    +
    random_stateint or RandomState

    Pseudo random number generator state used for random uniform sampling +from lists of possible values instead of scipy.stats distributions.

    +
    +
    error_score‘raise’ (default) or numeric

    Value to assign to the score if an error occurs in estimator fitting. +If set to ‘raise’, the error is raised. If a numeric value is given, +FitFailedWarning is raised. This parameter does not affect the refit +step, which will always raise the error.

    +
    +
    return_train_scoreboolean, default=True

    If 'False', the cv_results_ attribute will not include training +scores.

    -
    -

    cost - The value of ‘C’ used in the SVM, default=1 -lambda_tol - The tolerance value for lambda described in the appendix of [1]; default value is 1e-6 -norm_tol - The tolerance value for difference between alpha(p+1) and alpha(p) described in the appendix of [1]; default value is 1e-4 -max_iter - The maximum number of iterations for RankSVM, default=500

    +
    +
    cv_results_dict of numpy (masked) ndarrays

    A dict with keys as column headers and values as columns, that can be +imported into a pandas DataFrame.

    +

    For instance the below given table

    + +++++++ + + + + + + + + + + + + + + + + + + + + + + + + + + + + +

    param_kernel

    param_gamma

    split0_test_score

    …

    rank_test_score

    ‘rbf’

    0.1

    0.8

    …

    2

    ‘rbf’

    0.2

    0.9

    …

    1

    ‘rbf’

    0.3

    0.7

    …

    1

    +

    will be represented by a cv_results_ dict of:

    +
    {
    +'param_kernel' : masked_array(data = ['rbf', 'rbf', 'rbf'],
    +                              mask = False),
    +'param_gamma'  : masked_array(data = [0.1 0.2 0.3], mask = False),
    +'split0_test_score'  : [0.8, 0.9, 0.7],
    +'split1_test_score'  : [0.82, 0.5, 0.7],
    +'mean_test_score'    : [0.81, 0.7, 0.7],
    +'std_test_score'     : [0.02, 0.2, 0.],
    +'rank_test_score'    : [3, 1, 1],
    +'split0_train_score' : [0.8, 0.9, 0.7],
    +'split1_train_score' : [0.82, 0.5, 0.7],
    +'mean_train_score'   : [0.81, 0.7, 0.7],
    +'std_train_score'    : [0.03, 0.03, 0.04],
    +'mean_fit_time'      : [0.73, 0.63, 0.43, 0.49],
    +'std_fit_time'       : [0.01, 0.02, 0.01, 0.01],
    +'mean_score_time'    : [0.007, 0.06, 0.04, 0.04],
    +'std_score_time'     : [0.001, 0.002, 0.003, 0.005],
    +'params' : [{'kernel' : 'rbf', 'gamma' : 0.1}, ...],
    +}
    +
    +
    +

    NOTE that the key 'params' is used to store a list of parameter +settings dict for all the parameter candidates.

    +

    The mean_fit_time, std_fit_time, mean_score_time and +std_score_time are all in seconds.

    -
    and returns,

    Weights - The value for beta[ki] as described in the appendix of [1] is stored in Weights[k,i] -Bias - The value for b[i] as described in the appendix of [1] is stored in Bias[1,i] -SVs - The ith support vector is stored in SVs[:,i]

    +
    best_estimator_estimator

    Estimator that was chosen by the search, i.e. estimator +which gave highest score (or smallest loss if specified) +on the left out data. Not available if refit=False.

    +
    +
    best_score_float

    Score of best_estimator on the left out data.

    +
    +
    best_params_dict

    Parameter setting that gave the best results on the hold out data.

    +
    +
    best_index_int

    The index (of the cv_results_ arrays) which corresponds to the best +candidate parameter setting.

    +

    The dict at search.cv_results_['params'][search.best_index_] gives +the parameter setting for the best model, that gives the highest +mean score (search.best_score_).

    +
    +
    scorer_function

    Scorer function used on the held out data to choose the best +parameters for the model.

    +
    +
    n_splits_int

    The number of cross-validation splits (folds/iterations).

    -
    -

    For more details,please refer to [1] and [2].

    -
    +

    The parameters selected are those that maximize the score of the held-out +data, according to the scoring parameter.

    +

    If n_jobs was set to a value higher than one, the data is copied for each +parameter setting(and not n_jobs times). This is done for efficiency +reasons if individual jobs take very little time, but may raise errors if +the dataset is large and not enough memory is available. A workaround in +this case is to set pre_dispatch. Then, the memory is copied only +pre_dispatch many times. A reasonable value for pre_dispatch is 2 * +n_jobs.

    +
    +
    GridSearchCV:

    Does exhaustive search over a grid of parameters.

    +
    +
    ParameterSampler:

    A generator over parameter settings, constructed from +param_distributions.

    +
    +
    +
    +
    +__abstractmethods__ = frozenset({})¶
    +
    + +
    +
    +__init__(param_distributions={}, n_iter=10, scoring=None, fit_params=None, n_jobs=1, iid=True, refit=True, cv=None, verbose=0, pre_dispatch='2*n_jobs', random_state=None, error_score='raise', return_train_score=True, n_jobspercore=100, fastr_plugin=None, maxlen=100, ranking_score='test_score')[source]¶
    +

    Initialize self. See help(type(self)) for accurate signature.

    -
    -
    -WORC.classification.RankedSVM.is_empty(any_structure)[source]¶
    +
    +
    +__module__ = 'WORC.classification.SearchCV'¶
    +
    +
    +fit(X, y=None, groups=None)[source]¶
    +

    Run fit on the estimator with randomly drawn parameters.

    +
    +
    Xarray-like, shape = [n_samples, n_features]

    Training vector, where n_samples in the number of samples and +n_features is the number of features.

    +
    +
    yarray-like, shape = [n_samples] or [n_samples, n_output], optional

    Target relative to X for classification or regression; +None for unsupervised learning.

    +
    +
    groupsarray-like, with shape (n_samples,), optional

    Group labels for the samples used while splitting the dataset into +train/test set.

    +
    +
    +
    + +
    +
    -
    -WORC.classification.RankedSVM.neg_dual_func(Lambda, Alpha_old, Alpha_new, c_value, kernel, num_training, num_class, Label, not_Label, Label_size, size_alpha)[source]¶
    -
    +
    +WORC.classification.SearchCV.chunks(l, n)[source]¶
    +

    Yield successive n-sized chunks from l.

    +
    + +
    +
    +WORC.classification.SearchCV.chunksdict(data, SIZE)[source]¶
    +

    Split a dictionary in equal parts of certain slice

    +
    + +
    +
    +WORC.classification.SearchCV.rms_score(truth, prediction)[source]¶
    +

    Root-mean-square-error metric

    +
    + +
    +
    +WORC.classification.SearchCV.sar_score(truth, prediction)[source]¶
    +

    SAR metric from Caruana et al. 2004

    +
    -
    -
    -

    SearchCV Module¶

    construct_classifier Module¶

    @@ -494,8 +1929,113 @@

    -
    -

    crossval Module¶

    +
    +

    createfixedsplits Module¶

    +
    +
    +WORC.classification.createfixedsplits.createfixedsplits(label_file=None, label_type=None, patient_IDs=None, test_size=0.2, N_iterations=1, regression=False, stratify=None, modus='singlelabel', output=None)[source]¶
    +

    Create fixed splits for a cross validation.

    +
    + +
    +
    +

    crossval Module¶

    +
    +
    +WORC.classification.crossval.crossval(config, label_data, image_features, param_grid=None, use_fastr=False, fastr_plugin=None, tempsave=False, fixedsplits=None, ensemble={'Use': False}, outputfolder=None, modus='singlelabel')[source]¶
    +

    Constructs multiple individual classifiers based on the label settings

    +
    +
    config: dict, mandatory

    Dictionary with config settings. See the Github Wiki for the +available fields and formatting.

    +
    +
    label_data: dict, mandatory

    Should contain the following: +patient_IDs (list): IDs of the patients, used to keep track of test and

    +
    +

    training sets, and label data

    +
    +
    +
    label (list): List of lists, where each list contains the

    label status for that patient for each +label

    +
    +
    label_name (list): Contains the different names that are stored

    in the label object

    +
    +
    +
    +
    image_features: numpy array, mandatory

    Consists of a tuple of two lists for each patient: +(feature_values, feature_labels)

    +
    +
    param_grid: dictionary, optional

    Contains the parameters and their values wich are used in the +grid or randomized search hyperparamater optimization. See the +construct_classifier function for some examples.

    +
    +
    use_fastr: boolean, default False

    If False, parallel execution through Joblib is used for fast +execution of the hyperparameter optimization. Especially suited +for execution on mutlicore (H)PC’s. The settings used are +specified in the config.ini file in the IOparser folder, which you +can adjust to your system.

    +

    If True, fastr is used to split the hyperparameter optimization in +separate jobs. Parameters for the splitting can be specified in the +config file. Especially suited for clusters.

    +
    +
    fastr_plugin: string, default None

    Determines which plugin is used for fastr executions. +When None, uses the default plugin from the fastr config.

    +
    +
    tempsave: boolean, default False

    If True, create a .hdf5 file after each cross validation containing +the classifier and results from that that split. This is written to +the GSOut folder in your fastr output mount. If False, only +the result of all combined cross validations will be saved to a .hdf5 +file. This will also be done if set to True.

    +
    +
    fixedsplits: string, optional

    By default, random split cross validation is used to train and +evaluate the machine learning methods. Optionally, you can provide +a .xlsx file containing fixed splits to be used. See the Github Wiki +for the format.

    +
    +
    ensemble: dictionary, optional

    Contains the configuration for constructing an ensemble.

    +
    +
    modus: string, default ‘singlelabel’

    Determine whether one-vs-all classification (or regression) for +each single label is used (‘singlelabel’) or if multilabel +classification is performed (‘multilabel’).

    +
    +
    +
    +
    panda_data: pandas dataframe

    Contains all information on the trained classifier.

    +
    +
    +
    + +
    +
    +WORC.classification.crossval.nocrossval(config, label_data_train, label_data_test, image_features_train, image_features_test, param_grid=None, use_fastr=False, fastr_plugin=None, ensemble={'Use': False}, modus='singlelabel')[source]¶
    +

    Constructs multiple individual classifiers based on the label settings

    +
    +
    Arguments:

    config (Dict): Dictionary with config settings +label_data (Dict): should contain: +patient_IDs (list): IDs of the patients, used to keep track of test and

    +
    +

    training sets, and label data

    +
    +
    +
    label (list): List of lists, where each list contains the

    label status for that patient for each +label

    +
    +
    label_name (list): Contains the different names that are stored

    in the label object

    +
    +
    image_features (numpy array): Consists of a tuple of two lists for each patient:

    (feature_values, feature_labels)

    +
    +
    ensemble: dictionary, optional

    Contains the configuration for constructing an ensemble.

    +
    +
    modus: string, default ‘singlelabel’

    Determine whether one-vs-all classification (or regression) for +each single label is used (‘singlelabel’) or if multilabel +classification is performed (‘multilabel’).

    +
    +
    +
    +
    Returns:

    classifier_data (pandas dataframe)

    +
    +
    +
    +

    estimators Module¶

    @@ -509,9 +2049,9 @@

    -
    X_array, shape = [n_samples, n_features]

    The input passed during fit()

    +
    X_array, shape = [n_samples, n_features]

    The input passed during fit()

    -
    y_array, shape = [n_samples]

    The labels passed during fit()

    +
    y_array, shape = [n_samples]

    The labels passed during fit()

    @@ -574,8 +2114,134 @@

    -
    -

    fitandscore Module¶

    +
    +

    fitandscore Module¶

    +
    +
    +WORC.classification.fitandscore.delete_cc_para(para)[source]¶
    +

    Delete all parameters that are involved in classifier construction.

    +
    + +
    +
    +WORC.classification.fitandscore.delete_nonestimator_parameters(parameters)[source]¶
    +

    Delete all parameters in a parameter dictionary that are not used for the +actual estimator.

    +
    + +
    +
    +WORC.classification.fitandscore.fit_and_score(X, y, scoring, train, test, para, fit_params=None, return_train_score=True, return_n_test_samples=True, return_times=True, return_parameters=True, error_score='raise', verbose=True, return_all=True)[source]¶
    +

    Fit an estimator to a dataset and score the performance. The following +methods can currently be applied as preprocessing before fitting, in +this order: +1. Select features based on feature type group (e.g. shape, histogram). +2. Oversampling +3. Apply feature imputation (WIP). +4. Apply feature selection based on variance of feature among patients. +5. Univariate statistical testing (e.g. t-test, Wilcoxon). +6. Scale features with e.g. z-scoring. +7. Use Relief feature selection. +8. Select features based on a fit with a LASSO model. +9. Select features using PCA. +10. If a SingleLabel classifier is used for a MultiLabel problem,

    +
    +

    a OneVsRestClassifier is employed around it.

    +
    +

    All of the steps are optional.

    +
    +
    estimator: sklearn estimator, mandatory

    Unfitted estimator which will be fit.

    +
    +
    X: array, mandatory

    Array containingfor each object (rows) the feature values +(1st Column) and the associated feature label (2nd Column).

    +
    +
    y: list(?), mandatory

    List containing the labels of the objects.

    +
    +
    scorer: sklearn scorer, mandatory

    Function used as optimization criterion for the hyperparamater optimization.

    +
    +
    train: list, mandatory

    Indices of the objects to be used as training set.

    +
    +
    test: list, mandatory

    Indices of the objects to be used as testing set.

    +
    +
    para: dictionary, mandatory

    Contains the settings used for the above preprocessing functions +and the fitting. TODO: Create a default object and show the +fields.

    +
    +
    fit_params:dictionary, default None

    Parameters supplied to the estimator for fitting. See the SKlearn +site for the parameters of the estimators.

    +
    +
    return_train_score: boolean, default True

    Save the training score to the final SearchCV object.

    +
    +
    return_n_test_samples: boolean, default True

    Save the number of times each sample was used in the test set +to the final SearchCV object.

    +
    +
    return_times: boolean, default True

    Save the time spend for each fit to the final SearchCV object.

    +
    +
    return_parameters: boolean, default True

    Return the parameters used in the final fit to the final SearchCV +object.

    +
    +
    error_score: numeric or “raise†by default

    Value to assign to the score if an error occurs in estimator +fitting. If set to “raiseâ€, the error is raised. If a numeric +value is given, FitFailedWarning is raised. This parameter +does not affect the refit step, which will always raise the error.

    +
    +
    verbose: boolean, default=True

    If True, print intermediate progress to command line. Warnings are +always printed.

    +
    +
    return_all: boolean, default=True

    If False, only the ret object containing the performance will be +returned. If True, the ret object plus all fitted objects will be +returned.

    +
    +
    +

    Depending on the return_all input parameter, either only ret or all objects +below are returned.

    +
    +
    ret: list

    Contains optionally the train_scores and the test_scores, +test_sample_counts, fit_time, score_time, parameters_est +and parameters_all.

    +
    +
    GroupSel: WORC GroupSel Object

    Either None if the groupwise feature selection is not used, or +the fitted object.

    +
    +
    VarSel: WORC VarSel Object

    Either None if the variance threshold feature selection is not used, or +the fitted object.

    +
    +
    SelectModel: WORC SelectModel Object

    Either None if the feature selection based on a fittd model is not +used, or the fitted object.

    +
    +
    feature_labels: list

    Labels of the features. Only one list is returned, not one per +feature object, as we assume all samples have the same feature names.

    +
    +
    scaler: scaler object

    Either None if feature scaling is not used, or +the fitted object.

    +
    +
    imputer: WORC Imputater Object

    Either None if feature imputation is not used, or +the fitted object.

    +
    +
    pca: WORC PCA Object

    Either None if PCA based feature selection is not used, or +the fitted object.

    +
    +
    StatisticalSel: WORC StatisticalSel Object

    Either None if the statistical test feature selection is not used, or +the fitted object.

    +
    +
    ReliefSel: WORC ReliefSel Object

    Either None if the RELIEF feature selection is not used, or +the fitted object.

    +
    +
    sm: WORC SMOTE Object

    Either None if the SMOTE oversampling is not used, or +the fitted object.

    +
    +
    ros: WORC ROS Object

    Either None if Random Oversampling is not used, or +the fitted object.

    +
    +
    +
    + +
    +
    +WORC.classification.fitandscore.replacenan(image_features, verbose=True, feature_labels=None)[source]¶
    +

    Replace the NaNs in an image feature matrix.

    +
    +

    metrics Module¶

    @@ -628,8 +2294,10 @@

    y_truth and y_prediction should both be lists with the multiclass label of each object, e.g.

    y_truth = [0, 0, 0, 0, 0, 0, 2, 2, 1, 1, 2] ### Groundtruth -y_prediction = [0, 0, 0, 0, 0, 0, 1, 2, 1, 2, 2] ### Predicted labels

    +y_prediction = [0, 0, 0, 0, 0, 0, 1, 2, 1, 2, 2] ### Predicted labels +y_score = [[0.3, 0.3, 0.4], [0.2, 0.6, 0.2], … ] # Normalized score per patient for all labels (three in this example)

    Calculation of accuracy accorading to formula suggested in CAD Dementia Grand Challege http://caddementia.grand-challenge.org +and the TADPOLE challenge https://tadpole.grand-challenge.org/Performance_Metrics/ Calculation of Multi Class AUC according to classpy: https://bitbucket.org/bigr_erasmusmc/classpy/src/master/classpy/multi_class_auc.py

    @@ -640,11 +2308,121 @@

    -
    -

    parameter_optimization Module¶

    +
    +

    parameter_optimization Module¶

    +
    +
    +WORC.classification.parameter_optimization.random_search_parameters(features, labels, N_iter, test_size, param_grid, scoring_method, n_splits=5, n_jobspercore=200, use_fastr=False, n_cores=1, fastr_plugin=None, maxlen=100, ranking_score='test_score')[source]¶
    +

    Train a classifier and simultaneously optimizes hyperparameters using a +randomized search.

    +
    +
    Arguments:

    features: numpy array containing the training features. +labels: list containing the object labels to be trained on. +N_iter: integer listing the number of iterations to be used in the

    +
    +

    hyperparameter optimization.

    +
    +
    +
    test_size: float listing the test size percentage used in the cross

    validation.

    +
    +
    +

    classifier: sklearn classifier to be tested +param_grid: dictionary containing all possible hyperparameters and their

    +
    +

    values or distrubitions.

    +
    +
    +
    scoring_method: string defining scoring method used in optimization,

    e.g. f1_weighted for a SVM.

    +
    +
    n_jobsperscore: integer listing the number of jobs that are ran on a

    single core when using the fastr randomized search.

    +
    +
    use_fastr: Boolean determining of either fastr or joblib should be used

    for the opimization.

    +
    +
    fastr_plugin: determines which plugin is used for fastr executions.

    When None, uses the default plugin from the fastr config.

    +
    +
    +
    +
    Returns:

    random_search: sklearn randomsearch object containing the results.

    +
    +
    +
    + +
    +
    +

    regressors Module¶

    -
    -

    trainclassifier Module¶

    +
    +

    trainclassifier Module¶

    +
    +
    +WORC.classification.trainclassifier.load_features(feat, patientinfo, label_type)[source]¶
    +

    Read feature files and stack the features per patient in an array. +Additionally, if a patient label file is supplied, the features from +a patient will be matched to the labels.

    +
    +
    featurefiles: list, mandatory

    List containing all paths to the .hdf5 feature files to be loaded. +The argument should contain a list per modelity, e.g. +[[features_mod1_patient1, features_mod1_patient2, …],

    +
    +

    [features_mod2_patient1, features_mod2_patient2, …]].

    +
    +
    +
    patientinfo: string, optional

    Path referring to the .txt file to be used to read patient +labels from. See the Github Wiki for the format.

    +
    +
    label_names: list, optional

    List containing all the labels that should be extracted from +the patientinfo file.

    +
    +
    +
    + +
    +
    +WORC.classification.trainclassifier.trainclassifier(feat_train, patientinfo_train, config, output_hdf, output_json, feat_test=None, patientinfo_test=None, fixedsplits=None, verbose=True)[source]¶
    +

    Train a classifier using machine learning from features. By default, if no +split in training and test is supplied, a cross validation +will be performed.

    +
    +
    feat_train: string, mandatory

    contains the paths to all .hdf5 feature files used. +modalityname1=file1,file2,file3,… modalityname2=file1,… +Thus, modalities names are always between a space and a equal +sign, files are split by commas. We assume that the lists of +files for each modality has the same length. Files on the +same position on each list should belong to the same patient.

    +
    +
    patientinfo: string, mandatory

    Contains the path referring to a .txt file containing the +patient label(s) and value(s) to be used for learning. See +the Github Wiki for the format.

    +
    +
    config: string, mandatory

    path referring to a .ini file containing the parameters +used for feature extraction. See the Github Wiki for the possible +fields and their description.

    +
    +
    output_hdf: string, mandatory

    path refering to a .hdf5 file to which the final classifier and +it’s properties will be written to.

    +
    +
    output_json: string, mandatory

    path refering to a .json file to which the performance of the final +classifier will be written to. This file is generated through one of +the WORC plotting functions.

    +
    +
    feat_test: string, optional

    When this argument is supplied, the machine learning will not be +trained using a cross validation, but rather using a fixed training +and text split. This field should contain paths of the test set +feature files, similar to the feat_train argument.

    +
    +
    patientinfo_test: string, optional

    When feat_test is supplied, you can supply optionally a patient label +file through which the performance will be evaluated.

    +
    +
    fixedsplits: string, optional

    By default, random split cross validation is used to train and +evaluate the machine learning methods. Optionally, you can provide +a .xlsx file containing fixed splits to be used. See the Github Wiki +for the format.

    +
    +
    verbose: boolean, default True

    print final feature values and labels to command line or not.

    +
    +
    +
    +
    @@ -656,7 +2434,7 @@

    -__dict__ = mappingproxy({'__module__': 'WORC.WORC', '__doc__': '\n A Workflow for Optimal Radiomics Classification (WORC) object that\n serves as a pipeline spawner and manager for optimizating radiomics\n studies. Depending on the attributes set, the object will spawn an\n appropriate pipeline and manage it.\n\n Note that many attributes are lists and can therefore contain multiple\n instances. For example, when providing two sequences per patient,\n the "images" list contains two items. The type of items in the lists\n is described below.\n\n All objects that serve as source for your network, i.e. refer to\n actual files to be used, should be formatted as fastr sources suited for\n one of the fastr plugings, see also\n http://fastr.readthedocs.io/en/stable/fastr.reference.html#ioplugin-reference\n The objects should be lists of these fastr sources or dictionaries with the\n sample ID\'s, e.g.\n\n images_train = [{\'Patient001\': vfs://input/CT001.nii.gz,\n \'Patient002\': vfs://input/CT002.nii.gz},\n {\'Patient001\': vfs://input/MR001.nii.gz,\n \'Patient002\': vfs://input/MR002.nii.gz}]\n\n Attributes\n ------------------\n name: String, default \'WORC\'\n name of the network.\n\n configs: list, required\n Configuration parameters, either ConfigParser objects\n created through the defaultconfig function or paths of config .ini\n files. (list, required)\n\n labels: list, required\n Paths to files containing patient labels (.txt files).\n\n network: automatically generated\n The FASTR network generated through the "build" function.\n\n images: list, optional\n Paths refering to the images used for Radiomics computation. Images\n should be of the ITK Image type.\n\n segmentations: list, optional\n Paths refering to the segmentations used for Radiomics computation.\n Segmentations should be of the ITK Image type.\n\n semantics: semantic features per image type (list, optional)\n\n masks: state which pixels of images are valid (list, optional)\n\n features: input Radiomics features for classification (list, optional)\n\n metadata: DICOM headers belonging to images (list, optional)\n\n Elastix_Para: parameter files for Elastix (list, optional)\n\n fastr_plugin: plugin to use for FASTR execution\n\n fastr_tempdir: temporary directory to use for FASTR execution\n\n additions: additional inputs for your network (dict, optional)\n\n source_data: data to use as sources for FASTR (dict)\n\n sink_data: data to use as sinks for FASTR (dict)\n\n CopyMetadata: Boolean, default True\n when using elastix, copy metadata from image to segmentation or not\n\n\n ', '__init__': <function WORC.__init__>, 'defaultconfig': <function WORC.defaultconfig>, 'add_tools': <function WORC.add_tools>, 'build': <function WORC.build>, 'build_training': <function WORC.build_training>, 'build_testing': <function WORC.build_testing>, 'set': <function WORC.set>, 'execute': <function WORC.execute>, '__dict__': <attribute '__dict__' of 'WORC' objects>, '__weakref__': <attribute '__weakref__' of 'WORC' objects>})¶
    +__dict__ = mappingproxy({'__module__': 'WORC.WORC', '__doc__': '\n A Workflow for Optimal Radiomics Classification (WORC) object that\n serves as a pipeline spawner and manager for optimizating radiomics\n studies. Depending on the attributes set, the object will spawn an\n appropriate pipeline and manage it.\n\n Note that many attributes are lists and can therefore contain multiple\n instances. For example, when providing two sequences per patient,\n the "images" list contains two items. The type of items in the lists\n is described below.\n\n All objects that serve as source for your network, i.e. refer to\n actual files to be used, should be formatted as fastr sources suited for\n one of the fastr plugings, see also\n http://fastr.readthedocs.io/en/stable/fastr.reference.html#ioplugin-reference\n The objects should be lists of these fastr sources or dictionaries with the\n sample ID\'s, e.g.\n\n images_train = [{\'Patient001\': vfs://input/CT001.nii.gz,\n \'Patient002\': vfs://input/CT002.nii.gz},\n {\'Patient001\': vfs://input/MR001.nii.gz,\n \'Patient002\': vfs://input/MR002.nii.gz}]\n\n Attributes\n ------------------\n name: String, default \'WORC\'\n name of the network.\n\n configs: list, required\n Configuration parameters, either ConfigParser objects\n created through the defaultconfig function or paths of config .ini\n files. (list, required)\n\n labels: list, required\n Paths to files containing patient labels (.txt files).\n\n network: automatically generated\n The FASTR network generated through the "build" function.\n\n images: list, optional\n Paths refering to the images used for Radiomics computation. Images\n should be of the ITK Image type.\n\n segmentations: list, optional\n Paths refering to the segmentations used for Radiomics computation.\n Segmentations should be of the ITK Image type.\n\n semantics: semantic features per image type (list, optional)\n\n masks: state which pixels of images are valid (list, optional)\n\n features: input Radiomics features for classification (list, optional)\n\n metadata: DICOM headers belonging to images (list, optional)\n\n Elastix_Para: parameter files for Elastix (list, optional)\n\n fastr_plugin: plugin to use for FASTR execution\n\n fastr_tempdir: temporary directory to use for FASTR execution\n\n additions: additional inputs for your network (dict, optional)\n\n source_data: data to use as sources for FASTR (dict)\n\n sink_data: data to use as sinks for FASTR (dict)\n\n CopyMetadata: Boolean, default True\n when using elastix, copy metadata from image to segmentation or not\n\n\n ', '__init__': <function WORC.__init__>, 'defaultconfig': <function WORC.defaultconfig>, 'add_tools': <function WORC.add_tools>, 'build': <function WORC.build>, 'build_training': <function WORC.build_training>, 'build_testing': <function WORC.build_testing>, 'set': <function WORC.set>, 'execute': <function WORC.execute>, 'add_evaluation': <function WORC.add_evaluation>, '__dict__': <attribute '__dict__' of 'WORC' objects>, '__weakref__': <attribute '__weakref__' of 'WORC' objects>})¶
    -__init__(name='WORC')[source]¶
    +__init__(name='test')[source]¶
    Initialize WORC object. Set the initial variables all to None,

    except for some defaults.

    @@ -299,6 +303,11 @@

    list of weak references to the object (if defined)

    +
    +
    +add_evaluation(label_type)[source]¶
    +
    +
    add_tools()[source]¶
    @@ -485,41 +494,67 @@

    Subpackagesclassification Package + +
  • detectors Package +
  • +
  • exampledata Package +
  • +
  • facade Package
  • featureprocessing Package
  • plotting Package
  • processing Package
  • +
  • resources Package +
  • tools Package
  • diff --git a/WORC/doc/_build/html/autogen/WORC.plotting.html b/WORC/doc/_build/html/autogen/WORC.plotting.html index e5b7d314..cae6ed86 100644 --- a/WORC/doc/_build/html/autogen/WORC.plotting.html +++ b/WORC/doc/_build/html/autogen/WORC.plotting.html @@ -8,7 +8,7 @@ - plotting Package — WORC 3.0.0 documentation + plotting Package — WORC 3.1.0 documentation @@ -61,7 +61,7 @@
    - 3.0.0 + 3.1.0
    @@ -101,22 +101,26 @@
  • Subpackages
  • @@ -190,18 +194,30 @@

    plotting Package¶

    +
    +

    plotting Package¶

    +

    compute_CI Module¶

    WORC.plotting.compute_CI.compute_confidence(metric, N_train, N_test, alpha=0.95)[source]¶
    -

    Function to calculate the adjusted confidence interval +

    Function to calculate the adjusted confidence interval for cross-validation. metric: numpy array containing the result for a metric for the different cross validations (e.g. If 20 cross-validations are performed it is a list of length 20 with the calculated accuracy for each cross validation) N_train: Integer, number of training samples N_test: Integer, number of test_samples -alpha: float ranging from 0 to 1 to calculate the alpha*100% CI, default 95%

    +alpha: float ranging from 0 to 1 to calculate the alpha*100% CI, default 0.95

    +
    + +
    +
    +WORC.plotting.compute_CI.compute_confidence_bootstrap(bootstrap_metric, test_metric, N_1, alpha=0.95)[source]¶
    +

    Function to calculate confidence interval for bootstrapped samples. +metric: numpy array containing the result for a metric for the different bootstrap iterations +test_metric: the value of the metric evaluated on the true, full test set +alpha: float ranging from 0 to 1 to calculate the alpha*100% CI, default 0.95

    @@ -266,6 +282,19 @@

    plotting Package

    plot_SVM Module¶

    +
    +
    +WORC.plotting.plot_SVM.combine_multiple_estimators(predictions, label_data, multilabel_type, label_types, ensemble=1, strategy='argmax', alpha=0.95)[source]¶
    +

    Combine multiple estimators in a single model.

    +

    Note: the multilabel_type labels should correspond to the ordering in label_types. +Hence, if multilabel_type = 0, the prediction is label_type[0] etc.

    +
    + +
    +
    +WORC.plotting.plot_SVM.fit_thresholds(thresholds, estimator, X_train, Y_train, ensemble, ensemble_scoring)[source]¶
    +
    +
    WORC.plotting.plot_SVM.main()[source]¶
    @@ -273,7 +302,7 @@

    plotting Package
    -WORC.plotting.plot_SVM.plot_SVM(prediction, label_data, label_type, show_plots=False, alpha=0.95, ensemble=False, verbose=True, ensemble_scoring=None, output='stats', modus='singlelabel')[source]¶
    +WORC.plotting.plot_SVM.plot_SVM(prediction, label_data, label_type, show_plots=False, alpha=0.95, ensemble=False, verbose=True, ensemble_scoring=None, output='stats', modus='singlelabel', thresholds=None, survival=False, generalization=False, shuffle_estimators=False, bootstrap=False, bootstrap_N=1000)[source]¶

    Plot the output of a single binary estimator, e.g. a SVM.

    prediction: pandas dataframe or string, mandatory

    output of trainclassifier function, either a pandas dataframe @@ -304,6 +333,10 @@

    plotting Package -

    plot_SVR Module¶

    plot_barchart Module¶

    @@ -413,13 +443,13 @@

    -WORC.plotting.plot_images.plot_im_and_overlay(image, mask, figsize=(3, 3), alpha=0.15)[source]¶
    +WORC.plotting.plot_images.plot_im_and_overlay(image, mask, figsize=(3, 3), alpha=0.4)[source]¶

    Plot an image in a matplotlib figure and overlay with a mask.

    -WORC.plotting.plot_images.slicer(image, mask, output_name, output_name_zoom, thresholds=[-240, 160], zoomfactor=4)[source]¶
    +WORC.plotting.plot_images.slicer(image, mask, output_name, output_name_zoom=None, thresholds=[-240, 160], zoomfactor=4, dpi=500, normalize=False, expand=False)[source]¶

    image and mask should both be arrays

    @@ -491,11 +521,26 @@

    -
    -

    plotminmaxresponse Module¶

    +
    +

    plotminmaxresponse Module¶

    +
    +
    +WORC.plotting.plotminmaxresponse.main()[source]¶
    +
    +
    -
    -

    scatterplot Module¶

    +
    +

    scatterplot Module¶

    +
    +
    +WORC.plotting.scatterplot.main()[source]¶
    +
    + +
    +
    +WORC.plotting.scatterplot.make_scatterplot(features, label_file, feature_label_1, feature_label_2, output)[source]¶
    +
    +
    diff --git a/WORC/doc/_build/html/autogen/WORC.processing.html b/WORC/doc/_build/html/autogen/WORC.processing.html index 47eb55af..397dde7f 100644 --- a/WORC/doc/_build/html/autogen/WORC.processing.html +++ b/WORC/doc/_build/html/autogen/WORC.processing.html @@ -8,7 +8,7 @@ - processing Package — WORC 3.0.0 documentation + processing Package — WORC 3.1.0 documentation @@ -36,7 +36,7 @@ - + @@ -61,7 +61,7 @@
    - 3.0.0 + 3.1.0
    @@ -101,6 +101,9 @@
  • Subpackages
  • @@ -362,7 +366,7 @@

    +
    diff --git a/WORC/doc/_build/html/autogen/WORC.resources.fastr_tools.html b/WORC/doc/_build/html/autogen/WORC.resources.fastr_tools.html new file mode 100644 index 00000000..b0982bf8 --- /dev/null +++ b/WORC/doc/_build/html/autogen/WORC.resources.fastr_tools.html @@ -0,0 +1,243 @@ + + + + + + + + + + + fastr_tools Package — WORC 3.1.0 documentation + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
    + + + +
    + + + + + +
    + +
    + + + + + + + + + + + + + + + + + +
    + + + + +
    +
    +
    +
    + +
    +

    fastr_tools Package¶

    +
    +

    fastr_tools Package¶

    +
    +
    + + +
    + +
    +
    + + + + +
    + +
    +

    + © Copyright 2016 -- 2019, Biomedical Imaging Group Rotterdam, Departments of Medical Informatics and Radiology, Erasmus MC, Rotterdam, The Netherlands + +

    +
    + Built with Sphinx using a theme provided by Read the Docs. + +
    + +
    +
    + +
    + +
    + + + + + + + + + + + + \ No newline at end of file diff --git a/WORC/doc/_build/html/autogen/WORC.resources.html b/WORC/doc/_build/html/autogen/WORC.resources.html new file mode 100644 index 00000000..7348488f --- /dev/null +++ b/WORC/doc/_build/html/autogen/WORC.resources.html @@ -0,0 +1,255 @@ + + + + + + + + + + + resources Package — WORC 3.1.0 documentation + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
    + + + +
    + + + + + +
    + +
    + + + + + + + + + + + + + + + + + +
    + + + + +
    +
    + +
    + + + + +
    + +
    +

    + © Copyright 2016 -- 2019, Biomedical Imaging Group Rotterdam, Departments of Medical Informatics and Radiology, Erasmus MC, Rotterdam, The Netherlands + +

    +
    + Built with Sphinx using a theme provided by Read the Docs. + +
    + +
    +
    + +
    + +
    + + + + + + + + + + + + \ No newline at end of file diff --git a/WORC/doc/_build/html/autogen/WORC.tools.html b/WORC/doc/_build/html/autogen/WORC.tools.html index c0132143..9345da10 100644 --- a/WORC/doc/_build/html/autogen/WORC.tools.html +++ b/WORC/doc/_build/html/autogen/WORC.tools.html @@ -8,7 +8,7 @@ - tools Package — WORC 3.0.0 documentation + tools Package — WORC 3.1.0 documentation @@ -36,7 +36,7 @@ - + @@ -60,7 +60,7 @@
    - 3.0.0 + 3.1.0
    @@ -100,14 +100,19 @@
  • Subpackages @@ -244,16 +249,16 @@

    tools Package

    Evaluate Module¶

    -class WORC.tools.Evaluate.Evaluate(label_type, ensemble=50, scores='percentages', network=None, features=None, fastr_plugin='ProcessPoolExecution', name='Example')[source]¶
    +class WORC.tools.Evaluate.Evaluate(label_type, ensemble=50, scores='percentages', parent=None, features=None, fastr_plugin='LinearExecution', name='Example')[source]¶

    Bases: object

    -__dict__ = mappingproxy({'__module__': 'WORC.tools.Evaluate', '__init__': <function Evaluate.__init__>, 'create_network': <function Evaluate.create_network>, 'set': <function Evaluate.set>, 'execute': <function Evaluate.execute>, '__dict__': <attribute '__dict__' of 'Evaluate' objects>, '__weakref__': <attribute '__weakref__' of 'Evaluate' objects>, '__doc__': None})¶
    +__dict__ = mappingproxy({'__module__': 'WORC.tools.Evaluate', '__init__': <function Evaluate.__init__>, 'create_network': <function Evaluate.create_network>, 'create_links_Standalone': <function Evaluate.create_links_Standalone>, 'create_links_Addon': <function Evaluate.create_links_Addon>, 'set': <function Evaluate.set>, 'execute': <function Evaluate.execute>, '__dict__': <attribute '__dict__' of 'Evaluate' objects>, '__weakref__': <attribute '__weakref__' of 'Evaluate' objects>, '__doc__': None})¶
    -__init__(label_type, ensemble=50, scores='percentages', network=None, features=None, fastr_plugin='ProcessPoolExecution', name='Example')[source]¶
    +__init__(label_type, ensemble=50, scores='percentages', parent=None, features=None, fastr_plugin='LinearExecution', name='Example')[source]¶

    Build a network that evaluates the performance of an estimator.

    network: fastr network, default None

    If you input a network, the evaluate network is added @@ -273,6 +278,16 @@

    tools Package + +

    + +
    + +
    +
    create_network()[source]¶
    @@ -388,6 +403,15 @@

    tools Package +

    createfixedsplits Module¶

    +
    +
    +WORC.tools.createfixedsplits.createfixedsplits(label_file=None, label_type=None, patient_IDs=None, test_size=0.2, N_iterations=1, regression=False, stratify=None, modus='singlelabel', output=None)[source]¶
    +

    Create fixed splits for a cross validation.

    +
    +

  • @@ -400,7 +424,7 @@

    tools Package - +

    diff --git a/WORC/doc/_build/html/genindex.html b/WORC/doc/_build/html/genindex.html index e862e476..0230388a 100644 --- a/WORC/doc/_build/html/genindex.html +++ b/WORC/doc/_build/html/genindex.html @@ -9,7 +9,7 @@ - Index — WORC 3.0.0 documentation + Index — WORC 3.1.0 documentation @@ -60,7 +60,7 @@
    - 3.0.0 + 3.1.0
    @@ -168,28 +168,63 @@

    Index

    | E | F | G + | H | I | L | M | N + | O | P | R | S | T + | V | W

    _

    + -
    + -
    • __weakref__ (WORC.addexceptions.WORCError attribute)
        @@ -332,6 +457,24 @@

        _

      • (WORC.classification.AdvancedSampler.exp_uniform attribute)
      • (WORC.classification.AdvancedSampler.log_uniform attribute) +
      • +
      • (WORC.classification.ObjectSampler.ObjectSampler attribute) +
      • +
      • (WORC.detectors.detectors.AbstractDetector attribute) +
      • +
      • (WORC.facade.simpleworc.configbuilder.ConfigBuilder attribute) +
      • +
      • (WORC.facade.simpleworc.exceptions.InvalidCsvFileException attribute) +
      • +
      • (WORC.facade.simpleworc.exceptions.InvalidOrderException attribute) +
      • +
      • (WORC.facade.simpleworc.exceptions.NoImagesFoundException attribute) +
      • +
      • (WORC.facade.simpleworc.exceptions.NoSegmentationsFoundException attribute) +
      • +
      • (WORC.facade.simpleworc.exceptions.PathNotFoundException attribute) +
      • +
      • (WORC.facade.simpleworc.simpleworc.SimpleWORC attribute)
      • (WORC.featureprocessing.Imputer.Imputer attribute)
      • @@ -352,10 +495,20 @@

        _

        A

          +
        • add_tools() (WORC.WORC.WORC method) +
        • addchangeorder() (WORC.tools.Elastix.Elastix method)
        • AdvancedSampler (class in WORC.classification.AdvancedSampler) @@ -366,12 +519,28 @@

          A

          B

          @@ -514,7 +795,11 @@

          I

          L

          - +
          -
        • load_config_XNAT() (in module WORC.processing.label_processing) -
        • @@ -632,6 +967,12 @@

          P

          R

            -
          • RankSVM_train_old() (in module WORC.classification.RankedSVM) +
          • refit_and_score() (WORC.classification.SearchCV.BaseSearchCV method) +
          • +
          • regression() (WORC.facade.simpleworc.simpleworc.SimpleWORC method) +
          • +
          • replacenan() (in module WORC.classification.fitandscore) +
          • +
          • rms_score() (in module WORC.classification.SearchCV)
          • ROC_thresholding() (in module WORC.plotting.plot_ROC)
          • @@ -660,11 +1009,21 @@

            R

            S

            + - @@ -729,6 +1106,14 @@

            T

            +
          • set_multicore_execution() (WORC.facade.simpleworc.simpleworc.SimpleWORC method) +
          • +
          • set_tmpdir() (WORC.facade.simpleworc.simpleworc.SimpleWORC method) +
          • +
            - +
          • StatisticalTestFeatures() (in module WORC.featureprocessing.StatisticalTestFeatures) +
          • StatisticalTestThreshold (class in WORC.featureprocessing.StatisticalTestThreshold) +
          • +
          • survival() (WORC.facade.simpleworc.simpleworc.SimpleWORC method)
          • switch (class in WORC.processing.classes)
          • @@ -710,9 +1079,15 @@

            T

            +

            V

            + + +
            +

            W

            + - + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + or other required elements. - thead: [ 1, "
          • User Manual
          •     WORC.addexceptions
                + WORC.classification +
                @@ -193,21 +198,91 @@

            Python Module Index

                WORC.classification.construct_classifier
                + WORC.classification.createfixedsplits +
                + WORC.classification.crossval +
                WORC.classification.estimators
                + WORC.classification.fitandscore +
                WORC.classification.metrics
                + WORC.classification.ObjectSampler +
                + WORC.classification.parameter_optimization +
                WORC.classification.RankedSVM
                + WORC.classification.regressors +
                + WORC.classification.SearchCV +
                + WORC.classification.trainclassifier +
                + WORC.detectors.detectors +
                + WORC.exampledata.datadownloader +
                + WORC.facade +
                + WORC.facade.simpleworc.configbuilder +
                + WORC.facade.simpleworc.exceptions +
                + WORC.facade.simpleworc.simpleworc +
                @@ -233,11 +308,21 @@

            Python Module Index

                WORC.featureprocessing.SelectIndividuals
                + WORC.featureprocessing.StatisticalTestFeatures +
                WORC.featureprocessing.StatisticalTestThreshold
                + WORC.featureprocessing.VarianceThreshold +
                @@ -263,6 +348,11 @@

            Python Module Index

                WORC.IOparser.file_io
                + WORC.plotting +
                @@ -303,6 +393,16 @@

            Python Module Index

                WORC.plotting.plot_SVM
                + WORC.plotting.plotminmaxresponse +
                + WORC.plotting.scatterplot +
                @@ -333,6 +433,16 @@

            Python Module Index

                WORC.resources.fastr_tests.segmentix_test
                + WORC.resources.fastr_tools +
                + WORC.tools.createfixedsplits +
                diff --git a/WORC/doc/_build/html/search.html b/WORC/doc/_build/html/search.html index 51bc0689..936a8eee 100644 --- a/WORC/doc/_build/html/search.html +++ b/WORC/doc/_build/html/search.html @@ -8,7 +8,7 @@ - Search — WORC 3.0.0 documentation + Search — WORC 3.1.0 documentation @@ -60,7 +60,7 @@
            - 3.0.0 + 3.1.0
            diff --git a/WORC/doc/_build/html/searchindex.js b/WORC/doc/_build/html/searchindex.js index 7c1f2dbc..4a98a351 100644 --- a/WORC/doc/_build/html/searchindex.js +++ b/WORC/doc/_build/html/searchindex.js @@ -1 +1 @@ -Search.setIndex({docnames:["autogen/WORC","autogen/WORC.IOparser","autogen/WORC.classification","autogen/WORC.featureprocessing","autogen/WORC.plotting","autogen/WORC.processing","autogen/WORC.resources.fastr_tests","autogen/WORC.tools","index","static/changelog","static/configuration","static/file_description","static/introduction","static/quick_start","static/user_manual"],envversion:{"sphinx.domains.c":1,"sphinx.domains.changeset":1,"sphinx.domains.cpp":1,"sphinx.domains.javascript":1,"sphinx.domains.math":2,"sphinx.domains.python":1,"sphinx.domains.rst":1,"sphinx.domains.std":1,"sphinx.ext.intersphinx":1,"sphinx.ext.todo":1,"sphinx.ext.viewcode":1,sphinx:56},filenames:["autogen/WORC.rst","autogen/WORC.IOparser.rst","autogen/WORC.classification.rst","autogen/WORC.featureprocessing.rst","autogen/WORC.plotting.rst","autogen/WORC.processing.rst","autogen/WORC.resources.fastr_tests.rst","autogen/WORC.tools.rst","index.rst","static/changelog.rst","static/configuration.rst","static/file_description.rst","static/introduction.rst","static/quick_start.rst","static/user_manual.rst"],objects:{"WORC.IOparser":{config_WORC:[1,0,0,"-"],config_io_classifier:[1,0,0,"-"],config_preprocessing:[1,0,0,"-"],config_segmentix:[1,0,0,"-"],file_io:[1,0,0,"-"]},"WORC.IOparser.config_WORC":{load_config:[1,1,1,""]},"WORC.IOparser.config_io_classifier":{load_config:[1,1,1,""]},"WORC.IOparser.config_preprocessing":{load_config:[1,1,1,""]},"WORC.IOparser.config_segmentix":{load_config:[1,1,1,""]},"WORC.IOparser.file_io":{load_data:[1,1,1,""]},"WORC.WORC":{Tools:[0,2,1,""],WORC:[0,2,1,""]},"WORC.WORC.Tools":{__dict__:[0,3,1,""],__init__:[0,4,1,""],__module__:[0,3,1,""],__weakref__:[0,3,1,""]},"WORC.WORC.WORC":{__dict__:[0,3,1,""],__init__:[0,4,1,""],__module__:[0,3,1,""],__weakref__:[0,3,1,""],add_tools:[0,4,1,""],build:[0,4,1,""],build_testing:[0,4,1,""],build_training:[0,4,1,""],defaultconfig:[0,4,1,""],execute:[0,4,1,""],set:[0,4,1,""]},"WORC.addexceptions":{WORCAssertionError:[0,5,1,""],WORCError:[0,5,1,""],WORCIOError:[0,5,1,""],WORCIndexError:[0,5,1,""],WORCKeyError:[0,5,1,""],WORCNotImplementedError:[0,5,1,""],WORCTypeError:[0,5,1,""],WORCValueError:[0,5,1,""]},"WORC.addexceptions.WORCAssertionError":{__module__:[0,3,1,""]},"WORC.addexceptions.WORCError":{__module__:[0,3,1,""],__weakref__:[0,3,1,""]},"WORC.addexceptions.WORCIOError":{__module__:[0,3,1,""],__weakref__:[0,3,1,""]},"WORC.addexceptions.WORCIndexError":{__module__:[0,3,1,""]},"WORC.addexceptions.WORCKeyError":{__module__:[0,3,1,""]},"WORC.addexceptions.WORCNotImplementedError":{__module__:[0,3,1,""]},"WORC.addexceptions.WORCTypeError":{__module__:[0,3,1,""]},"WORC.addexceptions.WORCValueError":{__module__:[0,3,1,""]},"WORC.classification":{AdvancedSampler:[2,0,0,"-"],RankedSVM:[2,0,0,"-"],construct_classifier:[2,0,0,"-"],estimators:[2,0,0,"-"],metrics:[2,0,0,"-"]},"WORC.classification.AdvancedSampler":{AdvancedSampler:[2,2,1,""],discrete_uniform:[2,2,1,""],exp_uniform:[2,2,1,""],log_uniform:[2,2,1,""]},"WORC.classification.AdvancedSampler.AdvancedSampler":{__dict__:[2,3,1,""],__init__:[2,4,1,""],__iter__:[2,4,1,""],__len__:[2,4,1,""],__module__:[2,3,1,""],__weakref__:[2,3,1,""]},"WORC.classification.AdvancedSampler.discrete_uniform":{__dict__:[2,3,1,""],__init__:[2,4,1,""],__module__:[2,3,1,""],__weakref__:[2,3,1,""],rvs:[2,4,1,""]},"WORC.classification.AdvancedSampler.exp_uniform":{__dict__:[2,3,1,""],__init__:[2,4,1,""],__module__:[2,3,1,""],__weakref__:[2,3,1,""],rvs:[2,4,1,""]},"WORC.classification.AdvancedSampler.log_uniform":{__dict__:[2,3,1,""],__init__:[2,4,1,""],__module__:[2,3,1,""],__weakref__:[2,3,1,""],rvs:[2,4,1,""]},"WORC.classification.RankedSVM":{RankSVM_test:[2,1,1,""],RankSVM_test_original:[2,1,1,""],RankSVM_train:[2,1,1,""],RankSVM_train_old:[2,1,1,""],is_empty:[2,1,1,""],neg_dual_func:[2,1,1,""]},"WORC.classification.construct_classifier":{construct_SVM:[2,1,1,""],construct_classifier:[2,1,1,""],create_param_grid:[2,1,1,""]},"WORC.classification.estimators":{RankedSVM:[2,2,1,""]},"WORC.classification.estimators.RankedSVM":{__init__:[2,4,1,""],__module__:[2,3,1,""],fit:[2,4,1,""],predict:[2,4,1,""],predict_proba:[2,4,1,""]},"WORC.classification.metrics":{ICC:[2,1,1,""],ICC_anova:[2,1,1,""],check_scoring:[2,1,1,""],multi_class_auc:[2,1,1,""],multi_class_auc_score:[2,1,1,""],pairwise_auc:[2,1,1,""],performance_multilabel:[2,1,1,""],performance_singlelabel:[2,1,1,""]},"WORC.featureprocessing":{Imputer:[3,0,0,"-"],Relief:[3,0,0,"-"],SelectGroups:[3,0,0,"-"],SelectIndividuals:[3,0,0,"-"],StatisticalTestThreshold:[3,0,0,"-"]},"WORC.featureprocessing.Imputer":{Imputer:[3,2,1,""]},"WORC.featureprocessing.Imputer.Imputer":{__dict__:[3,3,1,""],__init__:[3,4,1,""],__module__:[3,3,1,""],__weakref__:[3,3,1,""],fit:[3,4,1,""],transform:[3,4,1,""]},"WORC.featureprocessing.Relief":{SelectMulticlassRelief:[3,2,1,""]},"WORC.featureprocessing.Relief.SelectMulticlassRelief":{__abstractmethods__:[3,3,1,""],__init__:[3,4,1,""],__module__:[3,3,1,""],fit:[3,4,1,""],multi_class_relief:[3,4,1,""],single_class_relief:[3,4,1,""],transform:[3,4,1,""]},"WORC.featureprocessing.SelectGroups":{SelectGroups:[3,2,1,""]},"WORC.featureprocessing.SelectGroups.SelectGroups":{__abstractmethods__:[3,3,1,""],__init__:[3,4,1,""],__module__:[3,3,1,""],fit:[3,4,1,""],transform:[3,4,1,""]},"WORC.featureprocessing.SelectIndividuals":{SelectIndividuals:[3,2,1,""]},"WORC.featureprocessing.SelectIndividuals.SelectIndividuals":{__abstractmethods__:[3,3,1,""],__init__:[3,4,1,""],__module__:[3,3,1,""],fit:[3,4,1,""],transform:[3,4,1,""]},"WORC.featureprocessing.StatisticalTestThreshold":{StatisticalTestThreshold:[3,2,1,""]},"WORC.featureprocessing.StatisticalTestThreshold.StatisticalTestThreshold":{__abstractmethods__:[3,3,1,""],__init__:[3,4,1,""],__module__:[3,3,1,""],fit:[3,4,1,""],transform:[3,4,1,""]},"WORC.plotting":{compute_CI:[4,0,0,"-"],linstretch:[4,0,0,"-"],plot_ROC:[4,0,0,"-"],plot_SVM:[4,0,0,"-"],plot_barchart:[4,0,0,"-"],plot_boxplot:[4,0,0,"-"],plot_images:[4,0,0,"-"],plot_ranked_scores:[4,0,0,"-"]},"WORC.plotting.compute_CI":{compute_confidence:[4,1,1,""],compute_confidence_logit:[4,1,1,""]},"WORC.plotting.linstretch":{linstretch:[4,1,1,""]},"WORC.plotting.plot_ROC":{ROC_thresholding:[4,1,1,""],main:[4,1,1,""],plot_ROC:[4,1,1,""],plot_ROC_CIc:[4,1,1,""],plot_single_ROC:[4,1,1,""]},"WORC.plotting.plot_SVM":{main:[4,1,1,""],plot_SVM:[4,1,1,""]},"WORC.plotting.plot_barchart":{count_parameters:[4,1,1,""],main:[4,1,1,""],paracheck:[4,1,1,""],plot_barchart:[4,1,1,""],plot_bars:[4,1,1,""]},"WORC.plotting.plot_boxplot":{generate_boxplots:[4,1,1,""],main:[4,1,1,""]},"WORC.plotting.plot_images":{bbox_2D:[4,1,1,""],plot_im_and_overlay:[4,1,1,""],slicer:[4,1,1,""]},"WORC.plotting.plot_ranked_scores":{example:[4,1,1,""],main:[4,1,1,""],plot_ranked_images:[4,1,1,""],plot_ranked_percentages:[4,1,1,""],plot_ranked_posteriors:[4,1,1,""],plot_ranked_scores:[4,1,1,""]},"WORC.processing":{ExtractNLargestBlobsn:[5,0,0,"-"],classes:[5,0,0,"-"],label_processing:[5,0,0,"-"]},"WORC.processing.ExtractNLargestBlobsn":{ExtractNLargestBlobsn:[5,1,1,""]},"WORC.processing.classes":{"switch":[5,2,1,""]},"WORC.processing.classes.switch":{__dict__:[5,3,1,""],__init__:[5,4,1,""],__iter__:[5,4,1,""],__module__:[5,3,1,""],__weakref__:[5,3,1,""],match:[5,4,1,""]},"WORC.processing.label_processing":{findlabeldata:[5,1,1,""],load_config_XNAT:[5,1,1,""],load_label_XNAT:[5,1,1,""],load_label_csv:[5,1,1,""],load_label_txt:[5,1,1,""],load_labels:[5,1,1,""]},"WORC.resources.fastr_tests":{CalcFeatures_test:[6,0,0,"-"],elastix_test:[6,0,0,"-"],segmentix_test:[6,0,0,"-"]},"WORC.resources.fastr_tests.CalcFeatures_test":{create_network:[6,1,1,""],main:[6,1,1,""],sink_data:[6,1,1,""],source_data:[6,1,1,""]},"WORC.resources.fastr_tests.elastix_test":{create_network:[6,1,1,""],main:[6,1,1,""],sink_data:[6,1,1,""],source_data:[6,1,1,""]},"WORC.resources.fastr_tests.segmentix_test":{create_network:[6,1,1,""],main:[6,1,1,""],sink_data:[6,1,1,""],source_data:[6,1,1,""]},"WORC.tools":{Elastix:[7,0,0,"-"],Evaluate:[7,0,0,"-"],Slicer:[7,0,0,"-"],Transformix:[7,0,0,"-"]},"WORC.tools.Elastix":{Elastix:[7,2,1,""]},"WORC.tools.Elastix.Elastix":{__dict__:[7,3,1,""],__init__:[7,4,1,""],__module__:[7,3,1,""],__weakref__:[7,3,1,""],addchangeorder:[7,4,1,""],create_bbox:[7,4,1,""],create_network:[7,4,1,""],execute:[7,4,1,""],getparametermap:[7,4,1,""]},"WORC.tools.Evaluate":{Evaluate:[7,2,1,""]},"WORC.tools.Evaluate.Evaluate":{__dict__:[7,3,1,""],__init__:[7,4,1,""],__module__:[7,3,1,""],__weakref__:[7,3,1,""],create_network:[7,4,1,""],execute:[7,4,1,""],set:[7,4,1,""]},"WORC.tools.Slicer":{Slicer:[7,2,1,""]},"WORC.tools.Slicer.Slicer":{__dict__:[7,3,1,""],__init__:[7,4,1,""],__module__:[7,3,1,""],__weakref__:[7,3,1,""],create_network:[7,4,1,""],execute:[7,4,1,""],set:[7,4,1,""]},"WORC.tools.Transformix":{Transformix:[7,2,1,""]},"WORC.tools.Transformix.Transformix":{__dict__:[7,3,1,""],__init__:[7,4,1,""],__module__:[7,3,1,""],__weakref__:[7,3,1,""],create_network:[7,4,1,""],execute:[7,4,1,""]},WORC:{WORC:[0,0,0,"-"],__init__:[0,0,0,"-"],addexceptions:[0,0,0,"-"],featureprocessing:[3,0,0,"-"]}},objnames:{"0":["py","module","Python module"],"1":["py","function","Python function"],"2":["py","class","Python class"],"3":["py","attribute","Python attribute"],"4":["py","method","Python method"],"5":["py","exception","Python exception"]},objtypes:{"0":"py:module","1":"py:function","2":"py:class","3":"py:attribute","4":"py:method","5":"py:exception"},terms:{"04t10":[],"0rc1":8,"0x7fc950fa87d0":[],"0x7fc950fa8850":[],"0x7fc9661ccfd0":[],"105741d":8,"1st":[],"2nd":[],"58_umwemv":[],"5_interface__priority__enum__":[],"8_interface__priority__enum__":[],"95varianc":[],"abstract":[],"boolean":[0,4,5,9],"case":[5,14],"catch":0,"class":[0,2,3,7,8],"default":[0,2,3,4,7,9,10,13,14],"enum":[],"export":12,"final":[10,14],"float":[3,4],"function":[0,2,3,4,5,7,8,9,10,11],"gr\u00fcnhagen":8,"import":[2,3,10,12,14],"int":[2,3],"long":[],"new":[0,9,12],"public":[],"return":[0,1,2,4,5],"short":[],"static":[],"switch":[5,9],"throw":[],"true":[0,2,4],"try":12,"while":[],Added:8,Adding:[],For:[0,2,8,9,10,12,13,14],IDs:5,Not:12,One:2,PCs:[],ROS:[],SVs:2,That:[],The:[0,1,2,3,4,5,8,9,10,11,12],Then:[],There:[9,14],These:[4,10,14],USING:8,Use:9,Used:[],Using:12,Vos:8,With:8,__abstractmethods__:3,__add__:[],__contains__:[],__delitem__:[],__dict__:[0,2,3,5,7],__doc__:[0,2,3,5,7],__elastix_4:[],__fastr_result__:[],__getitem__:[],__getstate__:[],__iadd__:[],__init__:[0,2,3,5,7],__iter__:[2,5],__len__:2,__lshift__:[],__module__:[0,2,3,5,7],__radd__:[],__rrshift__:[],__setitem__:[],__sink_data__:[],__weakref__:[0,2,3,5,7],_init_provid:[],_train:[],abbrevi:[],abc:[],abort:[],about:[],abov:[12,14],acceler:[],accept:[2,9],access:[],accorad:2,accord:[2,4],account:[],accur:[0,2,5,7],accuraci:[2,4],achiev:[],achterberg:[],acquisit:12,across:[],act:10,action:[],activ:[],actual:[0,10,12,14],acycl:[],adapt:[8,12],add:[7,9,11,14],add_int:[],add_tool:0,addchangeord:7,added:[7,10,14],addexcept:8,addimag:[],adding:10,addint:[],addit:[0,9,14],addition:[1,4,10,13],address:8,adher:9,adjust:[4,9,10],adopt:[2,9],advanc:[8,13,14],advancedsampl:[0,8],advantag:10,advic:[],affect:[],affin:7,after:[9,14],again:[10,12],against:[],age:14,agent:[],aggreg:[],agre:[],aim:8,algorithm:[2,10,12],align:14,alingn:14,all:[0,1,2,3,4,5,9,10,12,13,14],allow:11,allow_non:2,almost:10,along:[3,12],alpha:[2,4],alpha_new:2,alpha_old:2,alphabet:[],alreadi:[12,13,14],also:[0,9,10,12,14],alt:[],alter:[2,13],altern:14,although:12,alwai:[2,12,14],among:[4,8,10],amount:12,analys:[],analysi:[],analyz:[],angl:[],ani:[2,12,13,14],annual:8,anoth:[12,14],anova:2,any_structur:2,anymor:9,anyon:[],anyth:12,apach:8,apart:[],api:[],app:[],appear:[],append:[9,10,14],appendix:2,appli:[9,10,12,14],applic:[8,12],approach:[3,8,10,12],appropri:0,arch:[],architectur:[],archiv:[],arg:[1,2,5],argument:[0,1,5],argv:[],arithmet:[],arnaud:8,around:[7,14],arrai:[1,2,3,4,5],articl:[8,12],ask:[],assertionerror:0,assign:[],associ:[],assum:[2,12,14],assumpt:[],ation:[],atla:[],attach:[],attempt:[],attribut:[0,2,3,5,7,8,9],auc:2,authent:[],author:[],autom:[],automat:[0,8,9,12,14],avail:[2,12],averag:4,avoid:[],awar:[],axi:3,back:[],backend:10,background:[],backward:[],barchart:[4,9],base:[0,2,3,4,5,7,9,10],basedatatyp:[],baseestim:[2,3],baseinput:[],baselin:12,baseoutput:[],basesearchcv:[],basesearchcvfastr:[],basesearchcvjoblib:[],bash:[],basic:12,bbox_2d:4,becaus:[],becom:[],been:[0,8,12],befor:[2,9,10,12,14],beginn:8,behav:[],behavior:2,behaviour:9,behind:[],beihang:[],being:[],bellow:[],belong:[0,2,3],below:[0,10,12,14],benefit:12,benign:8,bent:8,besid:[0,13],best:[4,10,12],best_estim:[],best_estimator_:[],best_index_:[],best_params_:[],best_score_:[],beta:2,better:[],between:2,bia:2,bibtext:[],big:9,bigr:10,bigr_erasmusmc:2,bin:[],binari:[3,4,5],binaryimag:5,bio:8,biomark:12,biomed:8,bitbucket:2,bitwise_xor:9,blazev:8,blob:5,block:[],blue:[],bme2019:[],bme:8,boil:[],bool:[],borrow:[],both:[2,4,8,9,12,14],bound:7,boundari:[],box:[7,13],boxplot:4,braband:8,brain_extract:[],brain_tissue_segment:[],brainextractiontool:[],branch:[],broadcast:[],brought:12,bug:9,build:[0,7,8,12,14],build_test:0,build_train:0,bundl:[],c_valu:2,cache_s:[],cad:2,caddementia:2,calcfeatur:[9,14],calcul:[2,3,4],call:14,callabl:[],callback:[],can:[0,2,3,4,8,9,10,12,13,14],cancel:[],cancer:8,candid:2,cannot:9,capac:[],capit:[],caption:[],cardin:9,cardinalti:[],caruana:4,cash:[10,12],castillo:8,categori:14,caus:[],certain:[7,10,14],cf_pyradio:[],challeg:2,challeng:2,chang:[8,10],changelog:8,chapter:[11,14],characterist:4,check:14,check_scor:2,choic:12,choos:[],chose:[],chosen:10,chunk:[],chunksdict:[],citat:[],cite:[],class_i:2,class_j:2,class_weight:[],classfic:[],classif:[0,9,14],classifi:[0,2,4,9,10],classifier_data:[],classifiermixin:2,classmethod:[],classpi:2,clear:[],clearer:[],clearli:[],clf:[],clinic:12,clone:13,close:[],closest:2,cluster:[10,12],cnb_alpha:[],code:8,coef0:[],coeffici:2,coliag:[],coliage_featur:3,collabor:8,collaps:[],colleagu:12,collect:[],color:[],column:[2,3,14],com:[8,13],combin:[2,8,9,10,12],combine_dimens:[],combine_sampl:[],come:[],comma:10,command:[0,7,8,10,12,13],command_vers:[],commandlin:[],common:2,compar:12,comparison:8,compat:9,complementnb:[],complementnd:[],complet:[13,14],complex:[],compon:[7,12],compress:[],comput:[0,9,10,12,14],compute_ci:[0,8],compute_confid:4,compute_confidence_logit:4,concaten:[],concept:12,conceptu:[],concern:12,concur:[],confer:8,conffid:9,confid:4,config:[0,1,2,7,9,10,13,14],config_file_path:[1,5],config_io_classifi:[0,8],config_preprocess:[0,8],config_segmentix:[0,8],config_worc:[0,8],configpars:[0,5,10,14],configur:[0,1,2,8,9,11,14],conflict:[],connect:[],connectivetissueoncologysocieti:8,consid:13,consist:14,consol:[],consolid:[],consortium:[],const_:[],const__addint__right_hand:[],const_addint__right_hand_0:[],constant1:[],constant:[3,12],constantnod:[],constraint:[],construct:[2,4,8,13],construct_classifi:[0,8],construct_svm:2,consum:[],consumpt:[],contact:[],contain:[0,1,2,3,4,5,9,10,14],containingfor:[],containssampl:[],contantnod:[],content:[],continu:2,contour:5,contrast:[],contribut:8,control:[],conveni:[],convent:[],convert:14,copi:[0,8,9,14],copymetadata:[0,14],copyright:[],core:10,corn:8,correct:14,correctli:[4,9],correl:12,correspond:[2,14],cosin:14,cost:2,could:12,couldnotdeletecredenti:[],couldnotretrievecredenti:[],couldnotsetcredenti:[],count_paramet:4,counter:[],coupl:14,cours:14,cpu:[],crash:[],creat:[0,2,4,7,10,12,14],create_:[],create_bbox:7,create_const:[],create_ensembl:[],create_link:[],create_macro:[],create_network:[6,7],create_network_copi:[],create_nod:[],create_param_grid:2,create_sink:[],create_sourc:10,creation:9,credenti:[],criterion:[],crop:12,cross:[4,9,10,14],cross_valid:[],crossval:[0,8],crossvalid:8,crypto:[],csv:[4,9,14],ct001:0,ct002:0,cto:8,current:[0,2,8,9,10,12,13,14],curv:4,custom:2,cut:[],cv_iter:[],cv_results_:[],dag:[],darwin:[],data:[0,2,3,4,5,9,10,12],datafil:9,datafram:[2,4],dataset:[0,12,14],datatyp:[9,11],datatypemanag:[],datayp:9,datetim:[],dbu:[],debug:[4,13],decent:12,decid:12,decis:[],decision_funct:[],decision_function_shap:[],def:[],defaultconfig:[0,10,14],defer:[],defin:[0,2,3,5,7,12,14],definit:[],degre:2,del_password_for_us:[],delai:[],delet:[],delete_cc_para:[],delete_nonestimator_paramet:[],demand:[],dementia:2,demo:[],demo_param:2,demonst:2,den:8,depend:[0,4,12,14],depict:[],deprec:[],depth:[],der:8,deriv:[],describ:[0,2,11,14],descript:[2,10],design:12,desir:[],desmoid:8,detail:[2,4,10,14],detect:[],determin:[4,10,12],determinist:2,dev:[],develop:[12,13,14],deviat:[],diagram:[],dicom:[0,10,14],dict:[0,1,2,3,5],dict_valu:[],dictionari:[0,1,2,4,5,10,14],did:[12,14],die:[],die_sid:[],differ:[2,4,5,8,9,12],differenti:8,difficult:12,dilat:14,dim1:[],dim2:[],dimens:[],dimension:12,dimnam:[],dir:[],direct:14,directli:[12,14],directori:[0,10,13,14],dirk:8,disambigu:[],discret:[],discrete_uniform:2,discuss:14,dispatch:[],displai:[],dist:13,distanc:3,distance_p:3,distinguish:2,distribut:2,distrubit:[],divers:12,divid:12,doc:[],doctest:[],document:9,doe:3,doing:[],don:[],done:[12,14],down:[],download:[],draw:[],draw_dimens:[],draw_network:14,drawn:10,dti:9,dti_post:[],dtrf:8,due:[9,12],dummi:9,dump:[],dure:2,each:[2,3,4,5,9,10,12,14],earlier:[],easi:[8,12],easier:12,easili:[10,12,14],ecr:8,edg:[],edit:[13,14],editelastixtransformfil:9,effect:[],effici:[],effort:12,eigen:[],either:[0,2,3,4,10,13,14],elabor:[],elasticnet:[],elasticnet_alpha:[],elasticnet_l1_ratio:[],elastix:[0,8,9,14],elastix_para:[0,8],elastixlogfil:[],elastixparameterfil:[],elastixtransformfil:[],element:14,ellipsi:[],els:[],email:[],emploi:[],empti:[],enabl:[2,10],encount:[],end:8,engin:[8,12],enhanc:[],enough:[],ensembl:[4,7,8,12],ensemble_scor:4,ensur:0,enter:[2,5],entir:[],entiti:[],enumtyp:[],env:[],environ:13,envis:[],equal:2,equival:[],erasmu:12,ercim:[],error:9,error_scor:[],especi:9,establish:8,estim:[0,4,7,8,10],etc:[3,8],european:8,eusomii:8,evalu:[0,4,8,9,14],even:[],event:[],everi:12,everyth:[],evolv:[],exact:[],exampl:[0,2,4,7,9,10,12,13,14],example_network_rerun:[],example_tool:[],except:0,exclud:[],exe:[],execu:[],execut:[0,7,8,10,12,13],execute_job:[],execution_fail:[],execution_plugin:[],executionplugin:14,executionpluginmanag:[],executionscript:[],exhaust:[],exist:[7,12],exp:2,exp_uniform:2,expand:[],expand_macro:[],expect:12,experi:[],explain:[],explan:14,explicit:[],explicitli:[],explor:[],explos:[],expon:2,express:[],ext:[],extend:[],extens:[10,12],extern:[],extra:[],extract:[1,4,5,10,12],extractnlargestblobsn:[0,8],f1_weight:[],facilit:[8,12],fail:[],fail_1:[],fail_2:[],failing_network:[],failing_network_2017:[],failing_network___step_1___sample_1_1:[],failur:[],fals:[2,4],famili:[],familiar:12,fancyimput:3,fas:[],fast:[],fastr3:9,fastr:[0,7,8,9,10,13],fastr_bug:8,fastr_failing_network_2017:[],fastr_plugin:[0,7,14],fastr_result_:[],fastr_result_s1:[],fastr_result_s2:[],fastr_result_s3:[],fastr_result_s4:[],fastr_run_dump:[],fastr_tempdir:[0,10,14],fastr_tmpdir:14,fastrconfig:[10,14],fastrhom:13,fastrinterfac:[],fastroutputvalidationerror:[],fastrtemp:[],fastrvalueerror:[],fatih:8,fator:2,feasibl:[],feat:[],feat_test:[],feat_train:[],featsel:8,featur:[0,1,2,3,4,5,7,8,9,10,12],feature_label:3,feature_select:3,feature_set:3,feature_valu:3,featurecalc:[],featurefil:1,featureprocess:[0,8],features_mod1_patient1:1,features_mod1_patient2:1,features_mod2_patient1:1,features_mod2_patient2:1,features_test:14,features_train:14,featuresc:8,fed:[],feed:[],feel:[12,13],fellow:12,felt:12,ferenc:[],fetch:[],few:12,fibromatosi:8,fibrosi:8,fict:12,field:[2,10,12],fier:[],fig:4,figsiz:4,figur:[4,12],figwidth:4,file1:[],file2:[],file3:[],file:[0,1,4,5,8,9,10,13,14],file_io:[0,8],file_path:[],filenam:[5,14],filepath:4,fill:[],fill_valu:3,fillhol:[],filter:12,finalbsplineinterpolationord:9,find:[8,12],find_password_for_us:[],findlabeldata:5,finish:[],first:[3,4,9,10,12,13,14],fit:[2,3,10],fit_and_scor:[],fit_param:[],fit_tim:[],fitandscor:[0,8],fitfailedwarn:[],fittd:[],five:12,fix:[4,8,12],fixed_imag:[],fixed_mask:[],fixedsplit:[],flag:[],flexibl:[9,12],float_valu:[],flow:[],flownod:[],focu:[],fold:[],folder:[4,9,10,13,14],follow:[3,4,8,10,12,13,14],font_siz:[],fontsiz:4,footnot:[],forc:[],foresight:12,form:[],format:[0,1,4,8,9,10,14],formula:2,forum:[],forward:12,forwardssampl:[],found:[8,10,12,13],foundat:8,four:12,fpr:4,fprt:4,framework:[8,9,12],frangi:[],free:13,freedesktop:[],freeli:14,frequenc:[],frequent:3,from:[0,1,2,3,4,5,8,9,12,14],froma:[],frontier:[],frontiersin:12,frozenset:3,fsl:[],fslmath:[],fulfil:[],full:12,fulli:8,fullnam:[],fun:12,funtion:3,further:9,furthermor:[],futur:9,gabor:[],gabor_angl:[],gabor_frequ:[],gamma:2,gaussiannb:[],gave:[],geert:8,gener:[0,2,4,8,9,12,14],generate_boxplot:4,genet:[5,10],georg:8,get:[4,8,12,13],get_password_for_us:[],getparametermap:7,gibhub:8,git:13,github:[1,2,4,8,13],give:[2,9,12,14],given:[0,2,4,9,14],glcm:[],glcm_angl:[],glcm_distanc:[],glcm_level:[],global:[],glrlm:[],glszm:[],glu:[],gnome:[],goe:[],going:12,googl:[],got:[],gotten:[],govern:[],gpl:[],grade:8,grand:2,graph:[],graphic:[],graphviz:[],grayscal:[],grid:2,grid_scores_:[],gridsearch:10,gridsearchcv:[],gridsearchcvfastr:[],gridsearchcvjoblib:[],ground:4,groundtruth:2,group:[3,10,12],groupsel:[],groupwis:[],groupwisesearch:[],gsout:[],guarante:2,gui:[],guid:[2,8],guidelin:[],guillaum:8,gzip:[],hachterberg:[],had:[9,12],hakim:[],halton:2,haltonsampl:2,hand:12,handl:[],happen:[],harmon:8,has:[0,8,10,12,13],hasdimens:[],hassampl:[],have:[0,2,5,9,10,12,14],hdf5:[1,4,14],head:14,header:[0,14],held:[],help:[0,2,5,7],henc:[2,9,10,12,14],herder:8,here:[10,14],hf_mean:3,hide:[],hide_unconnect:[],high:[8,12],higher:[],highest:[],highli:[2,12],hing:[],histogram:[],histogram_featur:3,histori:12,hofland:8,hold:0,hole:[],home:[],homogen:[],hope:8,host:8,hounsfield:10,how:[2,4,10,12,13,14],howev:[2,10,12,13],html:[0,14],http:[0,2,8,12,13,14],human:[],hyper:2,hyperoptim:8,hyperparamat:[],hyperparamet:[4,9,10,12],i_max:4,i_min:4,icc:2,icc_anova:2,icctyp:2,ict:[],id3:[],id4:[],id_:[],idea:[12,14],ident:[],identifi:[],ids:5,ieee:8,ignor:13,iid:[],illustr:12,imag:[0,4,5,7,8,9,10,12],image_featur:[4,5],image_features_temp:5,image_features_test:[],image_features_train:[],image_typ:[],imagefeatur:[8,14],images1:14,images_test:14,images_train:[0,14],imagin:[],img2:4,img:4,immedi:[],implement:[0,2,10,12,14],impli:[],implicitli:12,importerror:[],imposs:[],improv:[],imput:[0,8,9,12],imputat:[],in1:[],in2:[],in_1:[],in_2:[],in_:[],in_imag:[],incekara:8,includ:[0,9,10,12,14],incorrect:9,incorrectli:4,increas:[],indent:[],indep:[],independ:12,index:[3,8],index_to_sourc:[],index_to_target:[],indexerror:0,indic:5,individu:[],ineffici:12,infinit:9,influenc:[],info:[10,14],inform:[4,12],informat:8,inherit:[],ini:[0,1,9,10],init:[],initi:[0,2,5,7],initial_transform:[],inner:[],input:[0,2,4,7,9,12,13,14],input_fil:5,input_group:[],inputarrai:3,inputgroup:[],inputid_:[],inputmap:[],inputparameterdescript:[],insid:[],inspect:[],instal:8,instanc:[0,2],instanti:[],instead:[2,9,10,14],instruct:13,int_valu:[],integ:[2,3,4,5],integr:[8,12],inter:2,interact:[],interest:[],interfac:2,interfaceresult:[],intermed:4,intermedi:[],intern:8,interpret:12,intersect:[],interv:[4,9],intra:2,introduct:8,introductori:12,invalid:[],invalid_network:[],inverse_transform:[],involv:[],ioerror:0,ionnod:[],iopars:[0,8],ioplugin:[0,14],ipynb:13,iri:[],is_empti:2,is_valid:[],isbi:8,isi:14,isn:9,issu:[8,9,12,13],item:[0,2,3],iter:[2,4],iteritem:[],ith:2,itk:[0,9],itkimag:4,itkimagefil:[],its:12,itself:12,ivo:8,jacob:8,jifk:8,job:[],jobdag:[],joblib:[9,10],joblib_backend:[],joblib_ncor:[],jobstat:[],john:[],join:[],jose:8,journal:12,json:5,json_schema:[],jsoncollector:[],jth:2,jupyt:13,just:[9,14],kapsa:8,keep:[9,12],kei:[2,14],keio:[],kept:[],kernel:2,kessel:8,keychain:[],keyerror:0,keyr:[],keyringprovid:[],keyword:[],kfold:[],kill:[],kind:[12,14],klein:8,knn:3,know:[],known:[],koek:[],kwallet:[],label1:[10,14],label2:[10,14],label:[0,1,2,3,4,5,8,9,12],label_data:[4,5],label_data_test:[],label_data_train:[],label_fil:5,label_info:5,label_nam:[1,5,10],label_process:[0,8],label_s:2,label_set:3,label_statu:5,label_typ:[4,5,7],labels_test:14,labels_train:14,lambda:2,lambda_tol:2,lan:[],languag:[8,12],lanuag:[],laptop:12,larg:12,larger:9,largest:5,lasso:[],last:[9,12],lastli:[],later:10,launch:[],layer:[],layout:[],lbp:[],lbp_npoint:[],lbp_radiu:[],lda:[],lda_shrinkag:[],lda_solv:[],lear:[],learn:[4,12],least:[2,12],leav:[],leender:8,left:[],left_hand:[],legal:[],len:[],length:4,less:[],let:14,level:[],lgpl:[],lib:13,libari:[],librari:13,licens:8,lightweight:[],like:[2,9,10,12],limit:[],line:[12,13],linear:2,link1:[],link2:[],link:14,link_0:[],linstretch:[0,8],linux:9,lipoma:8,liposarcoma:8,list:[0,1,2,3,4,5,7,10,14],list_valu:[],littl:12,liver:[8,14],load:[1,5],load_config:1,load_config_xnat:5,load_data:1,load_featur:[],load_iri:[],load_label:5,load_label_csv:5,load_label_fil:[],load_label_txt:5,load_label_xnat:5,loc:2,local:13,localbinarytarget:[],locat:13,log:12,log_featur:3,log_fil:[],log_sigma:[],log_uniform:2,logic:[],login:[],longer:9,look:[10,12,14],loop:[],loss:[],lot:12,low:8,lower:[],lower_case_with_underscor:[],lower_threshold:[],lrc:[],lrpenalti:[],lsqr:[],luckili:12,maarten:8,mac:[],machin:12,maco:[],macro:[],macronod:[],made:[4,8,9,10,12,14],mai:[12,13],main:[4,6,13,14],major:9,make:[4,10,12,14],make_scor:[],malign:8,manag:0,mandatori:[1,2,3,4],mani:[0,4,9,10,12],manipul:14,mannwhitneyu:3,manual:[8,12,13],map:[2,14],mappingproxi:[0,2,3,5,7],marcel:[],marion:8,martijn:8,martin:8,mask:[0,4,8,9,12],masked_arrai:[],masks_test:14,masks_train:14,master:2,match:[1,5,10,14],match_typ:[],math:[],matlab:[5,8,12],matplotlib:4,matrix:2,matter:3,max:[],max_it:2,max_thread:[],maxim:[],maximum:2,maxlen:[],mean:[3,9,10],mean_fit_tim:[],mean_score_tim:[],mean_test_scor:[],mean_train_scor:[],meant:[],measur:2,median:3,medic:[8,12],meet:8,melissa:8,member:[],memori:9,mention:[],mercuri:[],merg:[],mesenter:8,messag:4,metadata:[0,8,9],metadata_test:14,metadata_train:14,method:[0,2,3,4,5,10,12,14],metric:[0,3,4,8],mhd:14,mic:[],miclea:8,micro:12,middl:4,might:13,milea:8,mimic:5,min:[],mind:[],mine:12,mini:[],minim:14,minimum:9,minkov:3,minm:[],minmax:[],minor:[9,10],miss:3,missing_valu:3,missingpi:3,mit:[],mixin:[],mobview:[],modal:[9,14],modalityname1:[],modalityname2:[],model:[1,7,10,12],model_evaluatio:[],model_select:3,modifi:[],modified_hub:[],modnam:1,modu:4,modul:14,modular:8,moment:[],more:[2,3,4,9,10,12,13,14],moreov:12,most:[3,10,12],most_frequ:3,mostli:10,mount:[],move:9,moving_imag:[],moving_mask:[],mr001:0,mr002:0,mstarmans91:[8,13],much:[9,13],multi:2,multi_class_auc:2,multi_class_auc_scor:2,multi_class_relief:3,multiclass:2,multicor:[],multilabel:9,multimod:9,multipl:[0,9,10,12,14],multipli:[],multiprocess:[],must:10,mutat:8,mutlicor:[],mutlipl:[],mxn:2,n_1:4,n_2:4,n_blob:[],n_core:[],n_featur:2,n_iter:2,n_job:[],n_jobspercor:[],n_jobsperscor:[],n_neighbor:3,n_neighbour:3,n_neightbor:3,n_output:[],n_sampl:2,n_split:[],n_splits_:[],n_test:4,n_train:4,naiv:12,name:[0,4,5,7,9,10,13,14],namespac:[],nan:3,ndarrai:[],nearest:3,neccesari:9,necessari:[],need:[9,10,12,14],neg_dual_func:2,neighbor:3,neighbour:3,nest:[],netrc:[],nettyp:7,network:[0,6,7,9,10,12,13,14],network_nam:[],network_st:[],networkrun:[],neuro:[],newbas:[],newest:[],newli:[],nework:0,next:14,ngtdm:[],nice:12,niessen:8,nifti:14,niftiimagefil:[],niftiimagefilecompress:[],nii:[0,14],nipyp:2,nnode:[],nocrossv:[],node1:[],node2:[],node:[9,10,12,14],node_group:[],nodeid:[],nodeid__:[],nodelist:[],noderun:[],nomean:[],non:[2,12],none:[0,1,2,3,4,5,7,10],norm_tol:2,normal:[10,12],normalization_factor:4,normalize_whitespac:[],nospac:[],not_label:2,notabl:9,notat:[],note:[0,2,9,10,12,14],notebook:13,notimpl:[],notimplementederror:0,now:9,nrrd:14,nsampl:4,num_class:2,num_train:2,number:[2,3,4,5,12],number_of_class:[],number_of_level:[],number_of_sid:[],numbertoextract:5,numer:[2,3,14],numf:3,numpi:[2,3,4,5,9],object:[0,2,3,4,5,7,8,9,10],obscur:[],observ:2,obtain:[],occur:[],occurr:3,off:14,offici:8,often:12,onc:5,one:[0,2,5,9,10,12,14],onevsrestclassifi:[],onli:[0,3,5,9,10,12,14],onlin:12,ontolog:12,onward:2,open:[8,9,12],oper:4,opim:[],optim:[0,10],optimiz:0,option:[0,1,2,3,4,9,13,14],orang:[],order:[3,12],ordinari:[],org:[2,12],organ:12,orient:[],orientation_featur:3,origin:[],oserror:0,other:[0,2,8,10,12,14],other_dict_valu:[],other_list_valu:[],other_str_valu:[],otherwis:2,ouput:[],our:[8,10],out:[4,5,12,13,14],out_1:[],out_2:[],out_:[],out_imag:[],outcom:12,output:[4,9,12,13],output_csv:4,output_hdf:[],output_itk:4,output_json:[],output_nam:4,output_name_zoom:4,output_png:4,output_tex:4,output_zip:4,outputfold:4,outputid:[],outputmap:[],oval:[],over:[2,10,12],overlai:4,overrid:[],oversampl:[9,10,12],overview:[13,14],overwritten:0,own:[10,12],packag:[8,9,13],pad:[4,7],padmo:8,page:[8,12,14],pair:[],pairwis:[],pairwise_auc:2,panda:[2,4],panda_data:[],paper:[],para:2,paracheck:4,paragraph:[],parallel:[9,10,13],param:[2,4],param_c:[],param_degre:[],param_distribut:2,param_gamma:[],param_grid:2,param_kernel:[],param_list:2,paramet:[0,2,3,4,9,10,12,14],parameter_optim:[0,8],parametergrid:[],parameters_al:[],parameters_est:[],parametersampl:2,paramt:2,parent:[],pars:[1,10,13],part:[10,12,14],particular:[],pass:[2,9,14],password:[],past:[],path:[0,1,4,5,9],patient001:0,patient002:0,patient1:[10,14],patient2:[10,14],patient3:[10,14],patient:[0,1,2,3,4,5,10,14],patient_featur:[3,14],patient_id:5,patientclass:[9,10],patientinfo:[1,5],patientinfo_test:[],patientinfo_train:[],payload:[],pca:9,pcatyp:[],pce:9,penalti:[],pentagon:[],peopl:8,pep8:[],pep:[],per:[0,1,3,9,10,14],percentag:[3,4,7],perform:[2,4,7,10,12,14],performance_multilabel:2,performance_singlelabel:2,phase:[],phase_featur:3,phase_minwavelength:[],phase_nscal:[],phd:12,philosophi:[],pick:[],pickl:[],pictur:[],pid:4,pilot:[],pinfo:[4,7,9],pink:[],pinpoint:[],pip:8,pipelin:[0,8,12,14],pixel:[0,4],place:[],placehold:3,plai:[],plaintext:[],plan:[],platform:[8,12],pleas:[2,8],plot:[0,8,9],plot_bar:4,plot_barchart:[0,8],plot_boxplot:[0,8],plot_im_and_overlai:4,plot_imag:[0,8],plot_ranked_imag:4,plot_ranked_percentag:4,plot_ranked_posterior:4,plot_ranked_scor:[0,8],plot_roc:[0,8],plot_roc_c:4,plot_single_roc:4,plot_single_svr:[],plot_svm:[0,8],plot_svr:[0,8],plotminmaxrespons:[0,8],plu:14,pluge:0,plugin:[0,12,14],png:[4,9],point:[2,4],pointer:[],pointint:4,pointsar:4,poli:2,polynomi:[],popul:[],port:9,posit:4,possibl:[2,8,12],post:13,posterior:4,power:[],practic:12,pre_dispatch:[],predefin:[],predict:[2,4,8,9,10,12,14],predict_log_proba:[],predict_proba:2,predictgener:8,prefer:[],preferred_typ:[],prefix:[],prepend:[],preprocess:[8,9,12,14],preprocessi:[],preprocss:[],present:[2,8,9],press:8,prevent:9,previou:[12,14],previous:[10,12],principl:12,print:14,priorit:[],prioriti:[],privat:[],probability_imag:[],probabl:[],problem:[8,12],procedur:[3,10,14],proceed:8,process:[0,8,12],process_fit:[],processpollexecut:14,processpoolexecut:7,produc:2,profil:[],program:12,progress:[],project:[5,9],projectid:[],prompt:[],prone:[],proper:[0,9],properli:[],properti:[],propos:[],prostat:8,prov:[],provdocu:[],proven:12,provid:[0,2,4,7,10],pseudo:2,publish:[],pull:[],purpos:0,push:[],put:[4,9,10,13,14],pxcastconvert:9,pycrypto:[],python3:[9,13],python:[8,9,10,12,13],qda:[],qda_reg_param:[],qualiti:[],quantit:12,question:12,quick:8,quit:12,qxm:2,radian:[],radii:[],radiolog:8,radiom:[0,10,14],radiu:14,rais:[],ran:[],randint:[],random:[2,10],random_search:[],random_search_paramet:[],random_st:2,randomizedsearchcv:[],randomizedsearchcvfastr:[],randomizedsearchcvjoblib:[],randomli:[],randomsearch:[],randomst:2,rang:4,rank:[3,4,9,12],rank_:[],rank_test_scor:[],ranked_pid:4,ranked_scor:4,ranked_truth:4,rankedsvm:[0,8,9],ranksvm:2,ranksvm_test:2,ranksvm_test_origin:2,ranksvm_train:2,ranksvm_train_old:2,rate:[],rather:[],ratio:4,razvan:8,rbf:2,read:[1,2,5,12,14],read_config_fil:[],readabl:[],readi:[],readthedoc:[0,8,14],real:[],realli:10,reason:[],rebuild:[],rebuilt:[],receiv:4,recommend:[2,10,12,13],record:[],recreat:[],rectangl:[],reduc:[],reduct:[9,12],ref:2,refer:[0,1,2,3,4,5,7,9,12,14],referen:[],referenc:[],refit:[],refit_and_scor:[],reflect:[],regist:[],registr:[9,12,14],registratio:0,registri:[],regress:2,regular:[],rel:[],relat:0,releas:[9,12],relev:12,reliabl:[],relief:[0,8,9],reliefdistancep:[],reliefnn:[],reliefnumfeatur:[],reliefsamples:[],reliefsel:[],reliefus:[],remov:9,repeat:[2,10],replac:[2,3],replacenan:[],repo:[],report:[],repositoi:[],repositori:8,repr:[],repres:[],represent:[],reproduc:12,request:[],requir:[0,2,8,9,12],rerun:[],resampl:[],research:[8,12],resolv:[],resourc:[5,6,8,12],resourcelimit:[],respect:[2,3],respons:[],rest:[],result:[3,4,12],result_1:[],result_2:[],resum:[],ret:[],retain:[],retreiv:5,retri:[],retriev:10,return_al:[],return_n_test_sampl:[],return_paramet:[],return_tim:[],return_train_scor:[],reus:[],rfmax_depth:[],rfmin_samples_split:[],rfn_estim:[],rfr:[],ride:[],right:[],right_hand:[],ring:14,risk:[],rms_score:[],rng:2,roc:[4,9],roc_threshold:4,roi:14,root:[],ros:[],round:2,rounded_list:2,routin:12,row:2,rtstructread:[0,8,9],rule:[],run:[9,10,12,13,14],rundir:[],runtim:[],runtimeerror:[],rvs:2,safe:[],same:[10,12,14],sampl:[0,2,3,4,10,13],sample_1_1:[],sample_1_2:[],sample_1_3:[],sample_id:[],sample_s:3,sampleprocess:8,sar:[],sar_scor:[],save:[4,9,10,14],scale:[2,10,12],scale_featur:[],scaler:[],scaling_method:[],scan:10,scatterplot:[0,8],scenario:[],scenc:[],schedul:[],schedulingplugin:[],schema:[],scheme:[],schoot:8,scikit:[],scipi:2,score:[2,3,4,7,9],score_tim:[],scorer:[],scorer_:[],scoring_method:[],scratch:[],script:[12,13],search:[2,3,8,9,13],searchcv:[0,4,8],sebastian:8,second:[3,10],secret:[],secret_servic:[],secretprovid:[],secretservic:[],secretstorag:[],section:[13,14],secur:[],see:[0,1,2,4,5,7,8,10,13,14],seed:2,seem:12,seen:2,seg1:14,seg2:14,seg:7,segment:[0,4,7,8,9,10,12],segmentations1:14,segmentations2:14,segmentations_test:14,segmentations_train:14,segmentix:[1,8,9,14],segradiu:[],segtyp:[],sel:[],select:[3,9,10,12],selectfeatgroup:8,selectfrommodel:[],selectgroup:[0,8],selectindividu:[0,8],selectmodel:[],selectmulticlassrelief:3,selectormixin:3,self:[0,2,5,7],selfeat_vari:[],semant:[0,8,9],semantic_featur:3,semantics_test:14,semantics_train:14,send:[],separ:[9,10,14],sequenc:[0,2,14],sequenti:[],serial:[],serpar:9,serv:[0,12,14],servic:[],session:[],set:[0,1,2,3,4,7,8,9,10,12,13],set_data:[],set_password_for_us:[],settin:[],settings_dict:1,sever:[5,9,10,12,14],sex:14,sf_compact:3,sgd:[],sgd_alpha:[],sgd_l1_ratio:[],sgd_loss:[],sgd_penalti:[],sgdr:[],shape:2,shape_featur:3,share:[],shear:12,shell:[],ship:[],shortcut:[],shorthand:[],should:[0,1,2,3,4,10,14],show:13,show_plot:4,shown:12,shrink:[],shrinkag:[],side:[],sign:[],signatur:[0,2,5,7],signific:4,similar:[9,12,14],simpl:[12,13],simpleelastix:14,simpleitk:14,simpler:12,simplest:[],simpli:[10,13],simplifi:[],simul:[],simultan:12,sinc:[],singl:[4,5,8,9,10,14],single_class_relief:3,singleclass:2,singlelabel:4,singleton:2,sink1:[],sink2:[],sink:[0,7,9,12,14],sink_1:[],sink_2:[],sink_3:[],sink_4:[],sink_5:[],sink_data:[0,6,7],sink_id1:[],sinkenod:[],sinknod:[],site:13,situat:[],size:[2,4,7,14],size_alpha:2,skip:14,sklearn:[2,3,10],slack:[],sleijfer:8,slice:4,slicer:[0,4,8,9],slight:2,small:9,smaller:[],smallest:[],smart:4,smit:8,smote:10,smote_neighbor:[],smote_ratio:[],snippet:[],societi:8,softwar:[8,12],solid:[],solut:[],solv:12,solver:[],some:[0,2,9,10,12,13],some_output_loc:[],somenam:[10,14],someon:12,someth:[],sometim:[],sort:[],souc:[],sourc:[0,1,2,3,4,5,6,7,8,9,10,12],source1:14,source2:14,source3:[],source_data:[0,6],source_data_data:14,source_id1:[],source_id2:[],source_nod:[],sourcenod:[],sourcetre:[],space:2,span:[],spawn:0,spawner:0,special:[],specif:[3,10,12,14],specifi:[0,10,14],spend:[],spent:[],split0_test_scor:[],split0_train_scor:[],split1_test_scor:[],split1_train_scor:[],split2_test_scor:[],split2_train_scor:[],split:[10,12,14],squar:[],squared_hing:[],src:2,ssh:13,stabl:[0,14],stack:1,stage:[],stai:[],standard:8,standardis:8,starman:8,start:[8,9,12],stat:[2,4],state:[0,2],statement:5,statist:[3,4,9],statisticalsel:[],statisticaltestfeatur:[0,8],statisticaltestmetr:[],statisticaltestthreshold:[0,8],statisticaltestus:[],statu:5,std_fit_tim:[],std_score_tim:[],std_test_scor:[],std_train_scor:[],stderr:[],stdout:[],stefan:8,step1:[],step:[12,14],step_1:[],step_id:[],still:[9,10,14],stimul:8,stop:5,storag:[],store:[2,14],str:[2,9],str_valu:[],straight:12,strategi:[3,8,9],stratif:8,stratifi:[],stratifiedkfold:[],strenght:[],strength:[],stretch:4,strict:[],string:[0,1,2,3,4,5,10,14],structur:[],stuck:13,student:12,studi:[0,8,12],style:[],sub:0,subclass:[],subfold:9,subinput:[],subject:2,subobjectmap:[],subouput:[],suboutput:[],subpackag:8,subprocess:[],subtract:9,succeed:[],succesful:[],success:[],successfulli:[],suggest:2,suit:[0,5],sum:[],summari:[],suppli:[1,4,10,14],support:[2,3,8,9,10,12,14],suppos:10,sure:14,surgeri:8,surrog:2,surviv:[],svc:[],svd:[],svg:[],svm:[2,4,9,10],svmc:[],svmcoef0:[],svmdegre:[],svmgamma:[],svmkernel:[],svr:2,symposium:8,syntax:[],synthet:10,sys:[],system:[0,13,14],tabl:2,tag:14,take:[2,14],taken:[],target:2,task:12,techniqu:10,tedious:12,tell:14,temp:[],templat:[],temporari:[0,9,14],tempsav:[],term:[9,12],terminolog:8,test:[0,3,4,9,10,13,14],test_data:2,test_sampl:4,test_sample_count:[],test_scor:[],test_siz:[],test_target:2,test_throwdi:[],testserv:[],tex:[4,9],text:[],textur:10,texture_featur:3,texture_gabor_featur:3,texture_glcm_featur:3,texture_glcmms_featur:3,texture_glrlm_featur:3,texture_glszm_featur:3,texture_lbp_featur:3,texture_ngtdm_featur:3,than:10,thei:[9,14],them:[2,10,12],therebi:[9,12],therefor:[0,12],thi:[0,2,3,4,8,9,10,11,12,13,14],thing:[10,14],thomeer:8,those:[],though:[],thread:10,three:2,thresh:[],threshold:[3,4],threshold_mask:[],thresholdimag:[],through:[0,7,8,9,10,12,14],throw_di:[],throwdi:[],thrown:[],thu:[10,12,14],tiff:14,timbergen:8,time:[4,12],timestamp:[],tionplugin:[],tmp:[],tmpdir:[],todo:0,togeth:[],tol:[],toler:2,tool:[0,8,9,10,11,12,13,14],tool_vers:[],toolbox:[10,14],toolmanag:[],toolnam:[],tools_path:[],top50:[],top:4,tortoisehg:[],total:[],tpr:4,tprt:4,trace:13,track:[],trade:[],trail:[],train:[0,2,4,9,10,14],train_data:2,train_scor:[],train_target:2,train_test_split:[],trainclassi:[],trainclassifi:[0,4,8,9],transform:[3,9,14],transformat:[],transformi:[],transformix:[0,8,9,14],translat:[],treat:10,tree:[],tri:12,trigger:[],trough:[],truth:4,tsampl:4,ttest:[3,9],tumor:[8,14],tumour:8,tune:12,tupl:[],turn:[],tutori:[8,10],twai:[],two:[0,14],txt:[0,1,4,9,10,14],type:[0,2,3,4,5,7,8,10,12],typeerror:0,typegroup:9,typenam:[],types_path:[],ubuntu:13,udr:2,ulat:[],unag:5,unavail:[],under:[8,9,14],underli:[],understand:12,unfit:[],uniform:2,uniformli:[],union:[],uniqu:[],unit:10,univari:[],univers:8,unknown:[],unless:[],unreleas:[],unseen:[],unsupervis:[],unsupport:[],until:[],untouch:[],updat:9,upon:13,upper:[],uppercamelcas:[],url:5,urltyp:9,usabl:[],usag:9,usd:3,use:[0,2,3,4,9,10,12,13,14],use_fastr:[],used:[0,1,2,3,4,5,8,9,10,12,14],useful:[],usepca:[],user:[2,11,13],user_manu:[],usernam:[],uses:11,using:[0,2,3,8,9,10,12,13,14],usr:13,usual:[],util:[],val1:[],val2:[],val3:[],val4:[],val:[],valid:[0,4,9,10,14],valu:[0,2,3,4,5,10,14],value1:10,value2:10,valueerror:0,valuetyp:[],van:8,vari:12,variabl:[0,9],varianc:[],variancethreshold:[0,8],variancethresholdmean:[],variant:12,variou:[8,10,11,12,14],varsel:[],vault:[],vector:2,veenland:8,verbos:4,verhoef:8,veri:12,verifi:[],version:9,versu:8,vessel:[],vessel_featur:3,vessel_radiu:[],vessel_scale_rang:[],vessel_scale_step:[],vfs:[0,14],via:8,view:[],vincent:8,virtual:[],virtualenv:13,virtualfilesystem:[],visser:8,visual:[],vizual:[],volum:8,voort:8,w3c:[],wai:[],wait:[],want:[0,8,10,13,14],warn:[],warp:14,wavelength:[],weak:[0,2,3,5,7],web:[],websit:[],weight:2,welch:3,well:[8,9,12,13],went:[],were:[9,12],what:[],whatev:[],when:[0,4,9,10,12,14],whenev:2,where:[2,12],wherea:[],whether:[4,5,9,14],which:[0,2,4,5,9,10,12,13,14],who:[],whole:12,wich:[],wide:[],wijnenga:8,wiki:[1,2,4],wilcoxon:3,window:[9,13],wip:[3,4],wiro:8,wise:[],wish:[],within:[12,14],without:[2,14],wonder:12,worc:[1,2,3,4,5,6,7,9,10,11,12,13],worc_config:[9,13],worcassertionerror:0,worccastconvert:9,worcerror:0,worcflow:8,worcindexerror:0,worcioerror:0,worckeyerror:0,worcnotimplementederror:0,worcpy27:[],worctutori:[8,13],worctypeerror:0,worcvalueerror:0,work:[5,9,10,12],workaround:10,workflow:[0,9,10,12,14],world:[],would:[10,12],wouter:8,wrap:12,wrapper:[],write:[],written:4,wrong:[],wtype:0,www:[],x_train:3,xcode:[],xlsx:[],xml:[],xnat:[5,10],y_predict:[2,4],y_score:[2,4],y_train:3,y_truth:[2,4],yellow:[],yet:[],yield:2,you:[0,5,7,9,10,12,13,14],your:[0,10,13,14],yourprovidernam:[],yourself:[8,12],yourusernam:[],z_score:[],zero:[],zip:[4,9],zoomfactor:4},titles:["WORC Package","IOparser Package","classification Package","featureprocessing Package","plotting Package","processing Package","fastr_tests Package","tools Package","WORC","Changelog","Configuration","Resource File Formats","Introduction","Quick start guide","User Manual"],titleterms:{"0rc1":9,"class":5,"function":14,Added:9,The:14,Using:[],addexcept:0,advanc:[],advancedsampl:2,algorithm:[],ask:[],attribut:14,broadcast:[],calcfeatures_test:6,chang:9,changelog:9,classif:[2,8,10],code:13,combin:[],command:14,compute_ci:4,config:[],config_io_classifi:1,config_preprocess:1,config_segmentix:1,config_worc:1,configur:[10,13],constantnod:[],construct:14,construct_classifi:2,continu:[],convent:[],creat:[],crossval:2,crossvalid:10,data:[],datatyp:[],debug:[],definit:[],descript:[],design:[],develop:8,differ:[],dimens:[],document:8,elastix:7,elastix_para:14,elastix_test:6,ensembl:10,error:[],estim:2,evalu:7,exampl:[],execut:14,extractnlargestblobsn:5,fastr:[12,14],fastr_bug:10,fastr_test:6,fastrhub:[],featsel:10,featur:14,featureprocess:3,featuresc:10,field:[],file:11,file_io:1,fitandscor:2,fix:9,flow:[],format:11,from:13,gener:10,guid:13,guidlin:[],help:[],hyperoptim:10,hyperparamet:[],imag:14,imagefeatur:10,implement:[],imput:[3,10],indic:8,input:[],insid:[],instal:13,introduct:12,invalid:[],iopars:1,ioplugin:[],label:[10,14],label_process:5,link:[],linstretch:4,manual:14,mask:14,match:[],metadata:14,metric:2,modul:[0,1,2,3,4,5,6,7,8],modular:12,name:[],network:[],node:[],object:14,optim:[8,12],origin:[],overview:[],own:[],packag:[0,1,2,3,4,5,6,7],parameter_optim:2,philosophi:[],pip:13,plot:4,plot_barchart:4,plot_boxplot:4,plot_imag:4,plot_ranked_scor:4,plot_roc:4,plot_svm:4,plot_svr:4,plotminmaxrespons:4,predictgener:10,preprocess:10,process:5,prov:[],proven:[],quick:13,radiom:[8,12],rankedsvm:2,refer:8,relief:3,resolv:[],resourc:11,rtstructread:5,run:[],sampl:[],sampleprocess:10,scatterplot:4,schedulingplugin:[],searchcv:2,secret:[],secretprovid:[],segment:14,segmentix:10,segmentix_test:6,select:[],selectfeatgroup:10,selectgroup:3,selectindividu:3,semant:14,set:14,simpl:[],sinknod:[],slicer:7,sourc:[13,14],sourcenod:[],split:[],standard:12,start:13,statisticaltestfeatur:3,statisticaltestthreshold:3,subpackag:0,system:[],tabl:8,terminolog:12,tool:7,trainclassifi:2,transformix:7,tutori:13,unreleas:[],upload:[],usag:[],user:[8,14],using:[],variancethreshold:3,via:13,w3c:[],worc:[0,8,14],worcpy27:[],workflow:8,your:[]}}) \ No newline at end of file +Search.setIndex({docnames:["autogen/WORC","autogen/WORC.IOparser","autogen/WORC.classification","autogen/WORC.config","autogen/WORC.detectors","autogen/WORC.exampledata","autogen/WORC.facade","autogen/WORC.facade.simpleworc","autogen/WORC.featureprocessing","autogen/WORC.plotting","autogen/WORC.processing","autogen/WORC.resources","autogen/WORC.resources.fastr_tests","autogen/WORC.resources.fastr_tools","autogen/WORC.tools","autogen/config/WORC.config_Bootstrap_defopts","autogen/config/WORC.config_Bootstrap_description","autogen/config/WORC.config_Classification_defopts","autogen/config/WORC.config_Classification_description","autogen/config/WORC.config_CrossValidation_defopts","autogen/config/WORC.config_CrossValidation_description","autogen/config/WORC.config_Ensemble_defopts","autogen/config/WORC.config_Ensemble_description","autogen/config/WORC.config_Featsel_defopts","autogen/config/WORC.config_Featsel_description","autogen/config/WORC.config_FeatureScaling_defopts","autogen/config/WORC.config_FeatureScaling_description","autogen/config/WORC.config_General_defopts","autogen/config/WORC.config_General_description","autogen/config/WORC.config_HyperOptimization_defopts","autogen/config/WORC.config_HyperOptimization_description","autogen/config/WORC.config_ImageFeatures_defopts","autogen/config/WORC.config_ImageFeatures_description","autogen/config/WORC.config_Imputation_defopts","autogen/config/WORC.config_Imputation_description","autogen/config/WORC.config_Labels_defopts","autogen/config/WORC.config_Labels_description","autogen/config/WORC.config_Normalize_defopts","autogen/config/WORC.config_Normalize_description","autogen/config/WORC.config_SampleProcessing_defopts","autogen/config/WORC.config_SampleProcessing_description","autogen/config/WORC.config_Segmentix_defopts","autogen/config/WORC.config_Segmentix_description","autogen/config/WORC.config_SelectFeatGroup_defopts","autogen/config/WORC.config_SelectFeatGroup_description","index","static/changelog","static/configuration","static/file_description","static/introduction","static/quick_start","static/user_manual"],envversion:{"sphinx.domains.c":1,"sphinx.domains.changeset":1,"sphinx.domains.cpp":1,"sphinx.domains.javascript":1,"sphinx.domains.math":2,"sphinx.domains.python":1,"sphinx.domains.rst":1,"sphinx.domains.std":1,"sphinx.ext.intersphinx":1,"sphinx.ext.todo":1,"sphinx.ext.viewcode":1,sphinx:56},filenames:["autogen/WORC.rst","autogen/WORC.IOparser.rst","autogen/WORC.classification.rst","autogen/WORC.config.rst","autogen/WORC.detectors.rst","autogen/WORC.exampledata.rst","autogen/WORC.facade.rst","autogen/WORC.facade.simpleworc.rst","autogen/WORC.featureprocessing.rst","autogen/WORC.plotting.rst","autogen/WORC.processing.rst","autogen/WORC.resources.rst","autogen/WORC.resources.fastr_tests.rst","autogen/WORC.resources.fastr_tools.rst","autogen/WORC.tools.rst","autogen/config/WORC.config_Bootstrap_defopts.rst","autogen/config/WORC.config_Bootstrap_description.rst","autogen/config/WORC.config_Classification_defopts.rst","autogen/config/WORC.config_Classification_description.rst","autogen/config/WORC.config_CrossValidation_defopts.rst","autogen/config/WORC.config_CrossValidation_description.rst","autogen/config/WORC.config_Ensemble_defopts.rst","autogen/config/WORC.config_Ensemble_description.rst","autogen/config/WORC.config_Featsel_defopts.rst","autogen/config/WORC.config_Featsel_description.rst","autogen/config/WORC.config_FeatureScaling_defopts.rst","autogen/config/WORC.config_FeatureScaling_description.rst","autogen/config/WORC.config_General_defopts.rst","autogen/config/WORC.config_General_description.rst","autogen/config/WORC.config_HyperOptimization_defopts.rst","autogen/config/WORC.config_HyperOptimization_description.rst","autogen/config/WORC.config_ImageFeatures_defopts.rst","autogen/config/WORC.config_ImageFeatures_description.rst","autogen/config/WORC.config_Imputation_defopts.rst","autogen/config/WORC.config_Imputation_description.rst","autogen/config/WORC.config_Labels_defopts.rst","autogen/config/WORC.config_Labels_description.rst","autogen/config/WORC.config_Normalize_defopts.rst","autogen/config/WORC.config_Normalize_description.rst","autogen/config/WORC.config_SampleProcessing_defopts.rst","autogen/config/WORC.config_SampleProcessing_description.rst","autogen/config/WORC.config_Segmentix_defopts.rst","autogen/config/WORC.config_Segmentix_description.rst","autogen/config/WORC.config_SelectFeatGroup_defopts.rst","autogen/config/WORC.config_SelectFeatGroup_description.rst","index.rst","static/changelog.rst","static/configuration.rst","static/file_description.rst","static/introduction.rst","static/quick_start.rst","static/user_manual.rst"],objects:{"WORC.IOparser":{config_WORC:[1,0,0,"-"],config_io_classifier:[1,0,0,"-"],config_preprocessing:[1,0,0,"-"],config_segmentix:[1,0,0,"-"],file_io:[1,0,0,"-"]},"WORC.IOparser.config_WORC":{load_config:[1,1,1,""]},"WORC.IOparser.config_io_classifier":{load_config:[1,1,1,""]},"WORC.IOparser.config_preprocessing":{load_config:[1,1,1,""]},"WORC.IOparser.config_segmentix":{load_config:[1,1,1,""]},"WORC.IOparser.file_io":{load_data:[1,1,1,""]},"WORC.WORC":{Tools:[0,2,1,""],WORC:[0,2,1,""]},"WORC.WORC.Tools":{__dict__:[0,3,1,""],__init__:[0,4,1,""],__module__:[0,3,1,""],__weakref__:[0,3,1,""]},"WORC.WORC.WORC":{__dict__:[0,3,1,""],__init__:[0,4,1,""],__module__:[0,3,1,""],__weakref__:[0,3,1,""],add_evaluation:[0,4,1,""],add_tools:[0,4,1,""],build:[0,4,1,""],build_testing:[0,4,1,""],build_training:[0,4,1,""],defaultconfig:[0,4,1,""],execute:[0,4,1,""],set:[0,4,1,""]},"WORC.addexceptions":{WORCAssertionError:[0,5,1,""],WORCError:[0,5,1,""],WORCIOError:[0,5,1,""],WORCIndexError:[0,5,1,""],WORCKeyError:[0,5,1,""],WORCNotImplementedError:[0,5,1,""],WORCTypeError:[0,5,1,""],WORCValueError:[0,5,1,""]},"WORC.addexceptions.WORCAssertionError":{__module__:[0,3,1,""]},"WORC.addexceptions.WORCError":{__module__:[0,3,1,""],__weakref__:[0,3,1,""]},"WORC.addexceptions.WORCIOError":{__module__:[0,3,1,""],__weakref__:[0,3,1,""]},"WORC.addexceptions.WORCIndexError":{__module__:[0,3,1,""]},"WORC.addexceptions.WORCKeyError":{__module__:[0,3,1,""]},"WORC.addexceptions.WORCNotImplementedError":{__module__:[0,3,1,""]},"WORC.addexceptions.WORCTypeError":{__module__:[0,3,1,""]},"WORC.addexceptions.WORCValueError":{__module__:[0,3,1,""]},"WORC.classification":{AdvancedSampler:[2,0,0,"-"],ObjectSampler:[2,0,0,"-"],RankedSVM:[2,0,0,"-"],SearchCV:[2,0,0,"-"],construct_classifier:[2,0,0,"-"],createfixedsplits:[2,0,0,"-"],crossval:[2,0,0,"-"],estimators:[2,0,0,"-"],fitandscore:[2,0,0,"-"],metrics:[2,0,0,"-"],parameter_optimization:[2,0,0,"-"],regressors:[2,0,0,"-"],trainclassifier:[2,0,0,"-"]},"WORC.classification.AdvancedSampler":{AdvancedSampler:[2,2,1,""],discrete_uniform:[2,2,1,""],exp_uniform:[2,2,1,""],log_uniform:[2,2,1,""]},"WORC.classification.AdvancedSampler.AdvancedSampler":{__dict__:[2,3,1,""],__init__:[2,4,1,""],__iter__:[2,4,1,""],__len__:[2,4,1,""],__module__:[2,3,1,""],__weakref__:[2,3,1,""]},"WORC.classification.AdvancedSampler.discrete_uniform":{__dict__:[2,3,1,""],__init__:[2,4,1,""],__module__:[2,3,1,""],__weakref__:[2,3,1,""],rvs:[2,4,1,""]},"WORC.classification.AdvancedSampler.exp_uniform":{__dict__:[2,3,1,""],__init__:[2,4,1,""],__module__:[2,3,1,""],__weakref__:[2,3,1,""],rvs:[2,4,1,""]},"WORC.classification.AdvancedSampler.log_uniform":{__dict__:[2,3,1,""],__init__:[2,4,1,""],__module__:[2,3,1,""],__weakref__:[2,3,1,""],rvs:[2,4,1,""]},"WORC.classification.ObjectSampler":{ObjectSampler:[2,2,1,""]},"WORC.classification.ObjectSampler.ObjectSampler":{__dict__:[2,3,1,""],__init__:[2,4,1,""],__module__:[2,3,1,""],__weakref__:[2,3,1,""],fit:[2,4,1,""],init_NearMiss:[2,4,1,""],init_RandomOverSampling:[2,4,1,""],init_RandomUnderSampling:[2,4,1,""],init_SMOTE:[2,4,1,""]},"WORC.classification.RankedSVM":{RankSVM_test:[2,1,1,""],RankSVM_test_original:[2,1,1,""],RankSVM_train:[2,1,1,""],RankSVM_train_old:[2,1,1,""],is_empty:[2,1,1,""],neg_dual_func:[2,1,1,""]},"WORC.classification.SearchCV":{BaseSearchCV:[2,2,1,""],BaseSearchCVJoblib:[2,2,1,""],BaseSearchCVfastr:[2,2,1,""],Ensemble:[2,2,1,""],GridSearchCVJoblib:[2,2,1,""],GridSearchCVfastr:[2,2,1,""],RandomizedSearchCVJoblib:[2,2,1,""],RandomizedSearchCVfastr:[2,2,1,""],chunks:[2,1,1,""],chunksdict:[2,1,1,""],rms_score:[2,1,1,""],sar_score:[2,1,1,""]},"WORC.classification.SearchCV.BaseSearchCV":{__abstractmethods__:[2,3,1,""],__init__:[2,4,1,""],__module__:[2,3,1,""],best_params_:[2,3,1,""],best_score_:[2,3,1,""],create_ensemble:[2,4,1,""],decision_function:[2,4,1,""],inverse_transform:[2,4,1,""],predict:[2,4,1,""],predict_log_proba:[2,4,1,""],predict_proba:[2,4,1,""],preprocess:[2,4,1,""],process_fit:[2,4,1,""],refit_and_score:[2,4,1,""],score:[2,4,1,""],transform:[2,4,1,""]},"WORC.classification.SearchCV.BaseSearchCVJoblib":{__abstractmethods__:[2,3,1,""],__module__:[2,3,1,""]},"WORC.classification.SearchCV.BaseSearchCVfastr":{__abstractmethods__:[2,3,1,""],__module__:[2,3,1,""]},"WORC.classification.SearchCV.Ensemble":{__abstractmethods__:[2,3,1,""],__init__:[2,4,1,""],__module__:[2,3,1,""],decision_function:[2,4,1,""],inverse_transform:[2,4,1,""],predict:[2,4,1,""],predict_log_proba:[2,4,1,""],predict_proba:[2,4,1,""],transform:[2,4,1,""]},"WORC.classification.SearchCV.GridSearchCVJoblib":{__abstractmethods__:[2,3,1,""],__init__:[2,4,1,""],__module__:[2,3,1,""],fit:[2,4,1,""]},"WORC.classification.SearchCV.GridSearchCVfastr":{__abstractmethods__:[2,3,1,""],__init__:[2,4,1,""],__module__:[2,3,1,""],fit:[2,4,1,""]},"WORC.classification.SearchCV.RandomizedSearchCVJoblib":{__abstractmethods__:[2,3,1,""],__init__:[2,4,1,""],__module__:[2,3,1,""],fit:[2,4,1,""]},"WORC.classification.SearchCV.RandomizedSearchCVfastr":{__abstractmethods__:[2,3,1,""],__init__:[2,4,1,""],__module__:[2,3,1,""],fit:[2,4,1,""]},"WORC.classification.construct_classifier":{construct_SVM:[2,1,1,""],construct_classifier:[2,1,1,""],create_param_grid:[2,1,1,""]},"WORC.classification.createfixedsplits":{createfixedsplits:[2,1,1,""]},"WORC.classification.crossval":{crossval:[2,1,1,""],nocrossval:[2,1,1,""]},"WORC.classification.estimators":{RankedSVM:[2,2,1,""]},"WORC.classification.estimators.RankedSVM":{__init__:[2,4,1,""],__module__:[2,3,1,""],fit:[2,4,1,""],predict:[2,4,1,""],predict_proba:[2,4,1,""]},"WORC.classification.fitandscore":{delete_cc_para:[2,1,1,""],delete_nonestimator_parameters:[2,1,1,""],fit_and_score:[2,1,1,""],replacenan:[2,1,1,""]},"WORC.classification.metrics":{ICC:[2,1,1,""],ICC_anova:[2,1,1,""],check_scoring:[2,1,1,""],multi_class_auc:[2,1,1,""],multi_class_auc_score:[2,1,1,""],pairwise_auc:[2,1,1,""],performance_multilabel:[2,1,1,""],performance_singlelabel:[2,1,1,""]},"WORC.classification.parameter_optimization":{random_search_parameters:[2,1,1,""]},"WORC.classification.trainclassifier":{load_features:[2,1,1,""],trainclassifier:[2,1,1,""]},"WORC.detectors":{detectors:[4,0,0,"-"]},"WORC.detectors.detectors":{AbstractDetector:[4,2,1,""],BigrClusterDetector:[4,2,1,""],CartesiusClusterDetector:[4,2,1,""],CsvDetector:[4,2,1,""],DebugDetector:[4,2,1,""],HostnameDetector:[4,2,1,""],LinuxDetector:[4,2,1,""]},"WORC.detectors.detectors.AbstractDetector":{__abstractmethods__:[4,3,1,""],__dict__:[4,3,1,""],__module__:[4,3,1,""],__weakref__:[4,3,1,""],do_detection:[4,4,1,""]},"WORC.detectors.detectors.BigrClusterDetector":{__abstractmethods__:[4,3,1,""],__module__:[4,3,1,""]},"WORC.detectors.detectors.CartesiusClusterDetector":{__abstractmethods__:[4,3,1,""],__module__:[4,3,1,""]},"WORC.detectors.detectors.CsvDetector":{__abstractmethods__:[4,3,1,""],__init__:[4,4,1,""],__module__:[4,3,1,""]},"WORC.detectors.detectors.DebugDetector":{__abstractmethods__:[4,3,1,""],__module__:[4,3,1,""]},"WORC.detectors.detectors.HostnameDetector":{__abstractmethods__:[4,3,1,""],__init__:[4,4,1,""],__module__:[4,3,1,""]},"WORC.detectors.detectors.LinuxDetector":{__abstractmethods__:[4,3,1,""],__module__:[4,3,1,""]},"WORC.exampledata":{datadownloader:[5,0,0,"-"]},"WORC.exampledata.datadownloader":{download_HeadAndNeck:[5,1,1,""],download_project:[5,1,1,""],download_subject:[5,1,1,""]},"WORC.facade.simpleworc":{configbuilder:[7,0,0,"-"],exceptions:[7,0,0,"-"],simpleworc:[7,0,0,"-"]},"WORC.facade.simpleworc.configbuilder":{ConfigBuilder:[7,2,1,""]},"WORC.facade.simpleworc.configbuilder.ConfigBuilder":{__dict__:[7,3,1,""],__init__:[7,4,1,""],__module__:[7,3,1,""],__weakref__:[7,3,1,""],build_config:[7,4,1,""],coarse_overrides:[7,4,1,""],custom_config_overrides:[7,4,1,""],estimator_scoring_overrides:[7,4,1,""],full_overrides:[7,4,1,""],fullprint:[7,4,1,""]},"WORC.facade.simpleworc.exceptions":{InvalidCsvFileException:[7,5,1,""],InvalidOrderException:[7,5,1,""],NoImagesFoundException:[7,5,1,""],NoSegmentationsFoundException:[7,5,1,""],PathNotFoundException:[7,5,1,""]},"WORC.facade.simpleworc.exceptions.InvalidCsvFileException":{__init__:[7,4,1,""],__module__:[7,3,1,""],__weakref__:[7,3,1,""]},"WORC.facade.simpleworc.exceptions.InvalidOrderException":{__init__:[7,4,1,""],__module__:[7,3,1,""],__weakref__:[7,3,1,""]},"WORC.facade.simpleworc.exceptions.NoImagesFoundException":{__init__:[7,4,1,""],__module__:[7,3,1,""],__weakref__:[7,3,1,""]},"WORC.facade.simpleworc.exceptions.NoSegmentationsFoundException":{__init__:[7,4,1,""],__module__:[7,3,1,""],__weakref__:[7,3,1,""]},"WORC.facade.simpleworc.exceptions.PathNotFoundException":{__init__:[7,4,1,""],__module__:[7,3,1,""],__weakref__:[7,3,1,""]},"WORC.facade.simpleworc.simpleworc":{SimpleWORC:[7,2,1,""]},"WORC.facade.simpleworc.simpleworc.SimpleWORC":{__dict__:[7,3,1,""],__init__:[7,4,1,""],__module__:[7,3,1,""],__weakref__:[7,3,1,""],add_config_overrides:[7,4,1,""],add_evaluation:[7,4,1,""],binary_classification:[7,4,1,""],execute:[7,4,1,""],images_from_this_directory:[7,4,1,""],labels_from_this_file:[7,4,1,""],predict_labels:[7,4,1,""],regression:[7,4,1,""],segmentations_from_this_directory:[7,4,1,""],semantics_from_this_file:[7,4,1,""],set_multicore_execution:[7,4,1,""],set_tmpdir:[7,4,1,""],survival:[7,4,1,""]},"WORC.featureprocessing":{Imputer:[8,0,0,"-"],Relief:[8,0,0,"-"],SelectGroups:[8,0,0,"-"],SelectIndividuals:[8,0,0,"-"],StatisticalTestFeatures:[8,0,0,"-"],StatisticalTestThreshold:[8,0,0,"-"],VarianceThreshold:[8,0,0,"-"]},"WORC.featureprocessing.Imputer":{Imputer:[8,2,1,""]},"WORC.featureprocessing.Imputer.Imputer":{__dict__:[8,3,1,""],__init__:[8,4,1,""],__module__:[8,3,1,""],__weakref__:[8,3,1,""],fit:[8,4,1,""],transform:[8,4,1,""]},"WORC.featureprocessing.Relief":{SelectMulticlassRelief:[8,2,1,""]},"WORC.featureprocessing.Relief.SelectMulticlassRelief":{__abstractmethods__:[8,3,1,""],__init__:[8,4,1,""],__module__:[8,3,1,""],fit:[8,4,1,""],multi_class_relief:[8,4,1,""],single_class_relief:[8,4,1,""],transform:[8,4,1,""]},"WORC.featureprocessing.SelectGroups":{SelectGroups:[8,2,1,""]},"WORC.featureprocessing.SelectGroups.SelectGroups":{__abstractmethods__:[8,3,1,""],__init__:[8,4,1,""],__module__:[8,3,1,""],fit:[8,4,1,""],transform:[8,4,1,""]},"WORC.featureprocessing.SelectIndividuals":{SelectIndividuals:[8,2,1,""]},"WORC.featureprocessing.SelectIndividuals.SelectIndividuals":{__abstractmethods__:[8,3,1,""],__init__:[8,4,1,""],__module__:[8,3,1,""],fit:[8,4,1,""],transform:[8,4,1,""]},"WORC.featureprocessing.StatisticalTestFeatures":{StatisticalTestFeatures:[8,1,1,""]},"WORC.featureprocessing.StatisticalTestThreshold":{StatisticalTestThreshold:[8,2,1,""]},"WORC.featureprocessing.StatisticalTestThreshold.StatisticalTestThreshold":{__abstractmethods__:[8,3,1,""],__init__:[8,4,1,""],__module__:[8,3,1,""],fit:[8,4,1,""],transform:[8,4,1,""]},"WORC.featureprocessing.VarianceThreshold":{VarianceThresholdMean:[8,2,1,""],selfeat_variance:[8,1,1,""]},"WORC.featureprocessing.VarianceThreshold.VarianceThresholdMean":{__abstractmethods__:[8,3,1,""],__init__:[8,4,1,""],__module__:[8,3,1,""],fit:[8,4,1,""],transform:[8,4,1,""]},"WORC.plotting":{compute_CI:[9,0,0,"-"],linstretch:[9,0,0,"-"],plot_ROC:[9,0,0,"-"],plot_SVM:[9,0,0,"-"],plot_barchart:[9,0,0,"-"],plot_boxplot:[9,0,0,"-"],plot_images:[9,0,0,"-"],plot_ranked_scores:[9,0,0,"-"],plotminmaxresponse:[9,0,0,"-"],scatterplot:[9,0,0,"-"]},"WORC.plotting.compute_CI":{compute_confidence:[9,1,1,""],compute_confidence_bootstrap:[9,1,1,""],compute_confidence_logit:[9,1,1,""]},"WORC.plotting.linstretch":{linstretch:[9,1,1,""]},"WORC.plotting.plot_ROC":{ROC_thresholding:[9,1,1,""],main:[9,1,1,""],plot_ROC:[9,1,1,""],plot_ROC_CIc:[9,1,1,""],plot_single_ROC:[9,1,1,""]},"WORC.plotting.plot_SVM":{combine_multiple_estimators:[9,1,1,""],fit_thresholds:[9,1,1,""],main:[9,1,1,""],plot_SVM:[9,1,1,""]},"WORC.plotting.plot_barchart":{count_parameters:[9,1,1,""],main:[9,1,1,""],paracheck:[9,1,1,""],plot_barchart:[9,1,1,""],plot_bars:[9,1,1,""]},"WORC.plotting.plot_boxplot":{generate_boxplots:[9,1,1,""],main:[9,1,1,""]},"WORC.plotting.plot_images":{bbox_2D:[9,1,1,""],plot_im_and_overlay:[9,1,1,""],slicer:[9,1,1,""]},"WORC.plotting.plot_ranked_scores":{example:[9,1,1,""],main:[9,1,1,""],plot_ranked_images:[9,1,1,""],plot_ranked_percentages:[9,1,1,""],plot_ranked_posteriors:[9,1,1,""],plot_ranked_scores:[9,1,1,""]},"WORC.plotting.plotminmaxresponse":{main:[9,1,1,""]},"WORC.plotting.scatterplot":{main:[9,1,1,""],make_scatterplot:[9,1,1,""]},"WORC.processing":{ExtractNLargestBlobsn:[10,0,0,"-"],classes:[10,0,0,"-"],label_processing:[10,0,0,"-"]},"WORC.processing.ExtractNLargestBlobsn":{ExtractNLargestBlobsn:[10,1,1,""]},"WORC.processing.classes":{"switch":[10,2,1,""]},"WORC.processing.classes.switch":{__dict__:[10,3,1,""],__init__:[10,4,1,""],__iter__:[10,4,1,""],__module__:[10,3,1,""],__weakref__:[10,3,1,""],match:[10,4,1,""]},"WORC.processing.label_processing":{findlabeldata:[10,1,1,""],load_config_XNAT:[10,1,1,""],load_label_XNAT:[10,1,1,""],load_label_csv:[10,1,1,""],load_label_txt:[10,1,1,""],load_labels:[10,1,1,""]},"WORC.resources":{fastr_tools:[13,0,0,"-"]},"WORC.resources.fastr_tests":{CalcFeatures_test:[12,0,0,"-"],elastix_test:[12,0,0,"-"],segmentix_test:[12,0,0,"-"]},"WORC.resources.fastr_tests.CalcFeatures_test":{create_network:[12,1,1,""],main:[12,1,1,""],sink_data:[12,1,1,""],source_data:[12,1,1,""]},"WORC.resources.fastr_tests.elastix_test":{create_network:[12,1,1,""],main:[12,1,1,""],sink_data:[12,1,1,""],source_data:[12,1,1,""]},"WORC.resources.fastr_tests.segmentix_test":{create_network:[12,1,1,""],main:[12,1,1,""],sink_data:[12,1,1,""],source_data:[12,1,1,""]},"WORC.tools":{Elastix:[14,0,0,"-"],Evaluate:[14,0,0,"-"],Slicer:[14,0,0,"-"],Transformix:[14,0,0,"-"],createfixedsplits:[14,0,0,"-"]},"WORC.tools.Elastix":{Elastix:[14,2,1,""]},"WORC.tools.Elastix.Elastix":{__dict__:[14,3,1,""],__init__:[14,4,1,""],__module__:[14,3,1,""],__weakref__:[14,3,1,""],addchangeorder:[14,4,1,""],create_bbox:[14,4,1,""],create_network:[14,4,1,""],execute:[14,4,1,""],getparametermap:[14,4,1,""]},"WORC.tools.Evaluate":{Evaluate:[14,2,1,""]},"WORC.tools.Evaluate.Evaluate":{__dict__:[14,3,1,""],__init__:[14,4,1,""],__module__:[14,3,1,""],__weakref__:[14,3,1,""],create_links_Addon:[14,4,1,""],create_links_Standalone:[14,4,1,""],create_network:[14,4,1,""],execute:[14,4,1,""],set:[14,4,1,""]},"WORC.tools.Slicer":{Slicer:[14,2,1,""]},"WORC.tools.Slicer.Slicer":{__dict__:[14,3,1,""],__init__:[14,4,1,""],__module__:[14,3,1,""],__weakref__:[14,3,1,""],create_network:[14,4,1,""],execute:[14,4,1,""],set:[14,4,1,""]},"WORC.tools.Transformix":{Transformix:[14,2,1,""]},"WORC.tools.Transformix.Transformix":{__dict__:[14,3,1,""],__init__:[14,4,1,""],__module__:[14,3,1,""],__weakref__:[14,3,1,""],create_network:[14,4,1,""],execute:[14,4,1,""]},"WORC.tools.createfixedsplits":{createfixedsplits:[14,1,1,""]},WORC:{WORC:[0,0,0,"-"],__init__:[0,0,0,"-"],addexceptions:[0,0,0,"-"],classification:[2,0,0,"-"],facade:[6,0,0,"-"],featureprocessing:[8,0,0,"-"],plotting:[9,0,0,"-"]}},objnames:{"0":["py","module","Python module"],"1":["py","function","Python function"],"2":["py","class","Python class"],"3":["py","attribute","Python attribute"],"4":["py","method","Python method"],"5":["py","exception","Python exception"]},objtypes:{"0":"py:module","1":"py:function","2":"py:class","3":"py:attribute","4":"py:method","5":"py:exception"},terms:{"04t10":[],"0rc1":45,"0x7fc950fa87d0":[],"0x7fc950fa8850":[],"0x7fc9661ccfd0":[],"105741d":45,"1st":2,"22nd":51,"2nd":2,"58_umwemv":[],"5_interface__priority__enum__":[],"8_interface__priority__enum__":[],"95varianc":[23,24,47],"abstract":[],"boolean":[0,2,8,9,10,15,23,25,33,39,43,46,47],"case":[2,10,51],"catch":[0,46],"class":[0,2,4,7,8,14,40,45,46,47],"default":[0,2,8,9,14,15,17,18,19,21,23,25,27,29,31,33,35,37,39,41,43,46,47,50,51],"enum":[],"export":49,"final":[2,8,47,51],"float":[2,8,9,19,29,31,32,47],"function":[0,2,4,7,8,9,10,14,18,38,45,46,47,48],"gr\u00fcnhagen":45,"import":[2,8,45,47,49,51],"int":[2,8],"long":[],"new":[0,46,49],"public":[],"return":[0,1,2,8,9,10,46],"short":[],"static":[],"switch":[10,46],"throw":[],"true":[0,2,5,8,9,17,23,24,25,27,30,31,34,37,38,39,41,43,44,47,50,51],"try":[2,49],"while":2,Added:45,Adding:[],For:[0,2,18,45,46,47,49,50,51],IDs:[2,10],Not:[2,35,47,49],One:2,PCs:[18,47],ROS:2,SVs:2,That:8,The:[0,1,2,8,9,10,20,24,36,45,46,47,48,49],Then:2,There:[46,50,51],These:[9,47,50,51],USING:45,Use:[2,15,16,18,21,22,24,46,47,50],Used:[],Using:49,Vos:45,Will:[],With:45,__abstractmethods__:[2,4,8],__add__:[],__contains__:[],__delitem__:[],__dict__:[0,2,4,7,8,10,14],__doc__:[0,2,4,7,8,10,14],__elastix_4:[],__fastr_result__:[],__file__:50,__getitem__:[],__getstate__:[],__iadd__:[],__init__:[0,2,4,7,8,10,14],__iter__:[2,10],__len__:2,__lshift__:[],__module__:[0,2,4,7,8,10,14],__radd__:[],__rrshift__:[],__setitem__:[],__sink_data__:[],__weakref__:[0,2,4,7,8,10,14],_abc_data:4,_abc_impl:4,_cluster_config_overrid:7,_debug_config_overrid:7,_error_buldoz:7,_generate_detector_messag:4,_init_provid:[],_is_detect:4,_repeatedsplit:[],_set_and_validate_estim:7,_train:[],_valid:7,abbrevi:[18,47],abc:[2,4],abort:[],about:[],abov:[2,18,47,49,51],abspath:50,abstractdetector:4,acceler:[],accept:[2,46],access:[],accorad:2,accord:[2,9,50,51],accordingli:50,account:[8,51],accur:[0,2,4,7,8,10,14],accuraci:[2,9,51],achiev:[],achterberg:[],acquisit:49,across:2,act:47,action:[],activ:[],actual:[0,2,45,47,49,51],acycl:[],adapt:[45,49],add:[2,14,46,48,50,51],add_config_overrid:7,add_evalu:[0,7,50,51],add_int:[],add_tool:0,addchangeord:14,added:[14,46,47,51],addexcept:45,addimag:[],adding:[2,47,50],addint:[],addit:[0,28,46,47,50,51],addition:[1,2,9,47],address:45,adher:46,adjust:[2,9,46,47],adopt:[2,46],advanc:[45,50,51],advancedsampl:[0,45],advantag:47,advic:50,affect:2,affin:14,after:[2,28,46,47,50,51],again:[47,49,50],against:[],age:51,agent:[],aggreg:[],agre:[],aim:45,aka:51,algorithm:[2,47,49],align:51,alingn:51,all:[0,1,2,8,9,10,17,28,34,46,47,49,50,51],alloc:[],allow:48,allow_non:2,almost:47,along:[8,49],alpha:[2,9,24,47],alpha_new:2,alpha_old:2,alphabet:[],alreadi:[47,49,51],als:51,also:[0,2,24,40,46,47,49,50,51],alt:[],alter:[2,47],altern:51,although:49,alwai:[2,8,49,50,51],among:[2,8,9,45,47],amount:49,anaconda:50,analys:50,analysi:[24,45,47],analyz:[],angl:[32,47],ani:[2,17,29,47,49,50,51],annual:45,anoth:[49,51],anova:2,any_structur:2,anymor:46,anyon:[],anyth:49,apach:45,apart:[],api:[],app:[],appear:[],append:[46,47,51],appendix:2,appli:[2,8,28,38,46,47,49,51],applic:[45,49],approach:[8,45,47,49],appropri:0,arch:[],architectur:[],archiv:[],area:51,arg:[1,2,4,10],argmax:9,argument:[0,1,2,10],argv:[],arithmet:[],arnaud:45,around:[2,14,42,47,51],arrai:[1,2,8,9,10],articl:[45,49],ask:[],assertionerror:0,assign:[2,30,47],associ:2,assum:[2,8,49,50,51],assumpt:[2,51],ation:[],atla:[],attach:[],attempt:[],attribut:[0,2,4,7,8,10,14,45,46],atyp:51,auc:[2,51],authent:[],author:[],auto:2,autoclassifi:[],autogen:[],autom:[],automat:[0,45,46,49,51],autosklearn:[],autosklearn_output_:[],autosklearn_tmp_:[],autosklearnclassifi:[],avail:[2,49],averag:9,avoid:2,awar:[],axi:8,axial:46,back:[],backend:[28,47],background:[],backward:[],balanc:51,band:51,barchart:[9,46,51],base:[0,2,4,7,8,9,10,14,24,38,46,47,51],basecrossvalid:[],basedatatyp:[],baseestim:[2,8],baseinput:[],baselin:49,baseoutput:[],basesearchcv:2,basesearchcvfastr:2,basesearchcvjoblib:2,baseshufflesplit:[],bash:[],basic:49,bbox_2d:9,becaus:[],becom:[],been:[0,2,45,49],befor:[2,32,46,47,49,50,51],beforehand:50,beginn:45,behav:[],behavior:2,behaviour:46,behind:[],beihang:[],being:[38,47],bellow:[],belong:[0,2,8],below:[0,2,24,47,49,50,51],benefit:49,bengio:51,benign:45,bent:45,besid:[0,47,51],best:[2,9,47,49],best_estim:2,best_estimator_:2,best_index_:2,best_params_:2,best_score_:2,beta:2,better:[],between:[2,8,24,32,47],bia:2,bibtext:[],big:46,bigr:47,bigr_erasmusmc:2,bigrclusterdetector:4,bin:[],binari:[2,8,9,10,46,50],binary_classif:[7,50],binaryimag:10,bio:45,biomark:49,biomed:45,bitbucket:2,bitwise_xor:46,blazev:45,blob:[10,42,47],block:50,blue:[],bme2019:[],bme:45,bmia:50,boil:[],bool:[],boostrap:46,bootstrap:[3,9,16,45,51],bootstrap_metr:9,bootstrap_n:9,borrow:[],both:[2,9,45,46,49,51],bound:14,boundari:[8,24,32,47],box:[14,47],boxplot:9,braband:45,brain_extract:[],brain_tissue_segment:[],brainextractiontool:[],branch:[18,47],breviti:50,broadcast:[],brought:49,bug:46,bugfix:46,buggi:46,build:[0,14,45,49,50,51],build_config:7,build_test:0,build_train:0,built:[],bundl:[],c_valu:2,cache_s:2,cad:2,caddementia:2,calcfeatur:[27,46,47,51],calcfeatures_test:[0,11],calcul:[2,8,9,28,47],call:[2,46,50,51],callabl:2,callback:[],can:[0,2,8,9,32,34,38,45,46,47,49,50,51],cancel:[],cancer:45,candid:2,cannot:46,capac:[],capit:[],caption:[],cardin:46,cardinalti:[],cartesiusclusterdetector:4,caruana:[2,9],cash:[47,49],cast:46,castillo:45,categori:51,caus:[],certain:[2,14,47,51],cf_pyradio:[],cf_pyradiom:[27,47],challeg:2,challeng:[2,51],chanc:[],chang:[45,47,50],changelog:45,chapter:[47,48,50,51],characterist:[9,51],check:51,check_scor:2,choic:[2,49],choos:[2,46],chose:[],chosen:[2,47],chunk:2,chunksdict:2,citat:[],cite:[],class_i:2,class_j:2,class_weight:2,classfic:[30,47],classif:[0,3,36,46,50,51],classifi:[0,2,9,17,18,46,47,51],classifier_data:2,classifiermixin:2,classmethod:[],classpi:2,clear:[],clearer:[],clearli:[],clf:2,clinic:49,clone:50,close:[],closest:2,cluster:[2,18,47,49,50],cnb_alpha:[17,18,47],coars:50,coarse_overrid:7,code:45,coef0:2,coeffici:[2,51],coliag:[31,32,44,47],coliage_featur:[8,43,44,47],collabor:45,collaps:[],colleagu:49,collect:[],color:[],column:[2,8,51],com:[45,50],combin:[2,9,45,46,47,49],combine_dimens:[],combine_multiple_estim:9,combine_sampl:[],come:[],comma:[2,8,47],command:[0,2,8,14,45,46,47,49,50],command_vers:[],commandlin:[],common:2,commun:50,compar:49,comparison:45,compat:46,complementnb:[18,47],complementnd:[17,47],complet:[47,51],complex:[],compon:[14,24,47,49],compress:[],comput:[0,32,46,47,49,50,51],compute_ci:[0,45],compute_confid:9,compute_confidence_bootstrap:9,compute_confidence_logit:9,concaten:[],concept:49,conceptu:[],concern:49,concord:51,concur:[],confer:[45,51],conffid:46,confid:[9,46,51],config:[0,1,2,7,8,14,24,46,47,50,51],config_file_path:[1,10],config_general_defopt:[],config_general_descript:[],config_io_classifi:[0,45],config_preprocess:[0,45],config_segmentix:[0,45],config_worc:[0,45],configbuild:[0,6,46],configpars:[0,10,47,51],configur:[0,1,2,45,46,48,50,51],conflict:[],connect:[],connectivetissueoncologysocieti:45,consid:50,consist:[2,50,51],consol:7,consolid:[],consortium:[],const_:[],const__addint__right_hand:[],const_addint__right_hand_0:[],constant1:[],constant:[8,33,47,49],constantnod:[],constraint:[],construct:[2,9,45,50],construct_classifi:[0,45],construct_svm:2,constructor:[],consum:[],consumpt:2,contact:[],contain:[0,1,2,8,9,10,46,47,50,51],containingfor:2,containssampl:[],contantnod:[],content:[7,45],continu:2,contour:[10,42,47],contrast:2,contribut:45,control:2,conveni:[],convent:[],converg:9,convers:46,convert:[46,51],copi:[0,2,45,46,51],copymetadata:[0,51],copyright:[],core:[2,28,30,47,50],corn:45,correct:51,correctli:[9,46,51],correl:[49,51],correspond:[2,8,9,30,47,51],cosin:51,cost:2,could:49,couldnotdeletecredenti:[],couldnotretrievecredenti:[],couldnotsetcredenti:[],count_paramet:9,counter:[],coupl:51,cours:51,cox:51,cpu:2,crash:50,creat:[0,2,9,14,46,47,49,50,51],create_:[],create_bbox:14,create_const:[],create_ensembl:[2,46],create_link:[],create_links_addon:14,create_links_standalon:14,create_macro:[],create_network:[12,14],create_network_copi:[],create_nod:[],create_param_grid:2,create_sink:[],create_sourc:47,createfixedsplit:[0,45],creation:[45,46],credenti:[],criterion:2,crop:49,cross:[2,9,14,20,28,30,46,47,51],cross_valid:[27,28,47],crossval:[0,45],crossvalid:[3,45],crypto:[],csv:[9,46,50,51],csv_file_path:4,csvdetector:4,ct001:0,ct002:0,cto:45,current:[0,2,38,45,46,47,49,50,51],curv:[9,51],custom:2,custom_config_overrid:7,cut:[],cv_iter:2,cv_result:[],cv_results_:2,dag:[],darwin:[],data:[0,2,8,9,10,20,46,47,49,50],data_path:50,datadir:50,datadownload:[0,45,50],datafil:46,datafold:[5,50],datafram:[2,9],dataset:[0,2,30,46,47,49,50,51],datatyp:[46,48],datatypemanag:[],datayp:46,datetim:[],dbu:[],debug:[9,28,45,47,50],debugdetector:4,debuggin:[],dec:7,decent:49,decid:49,decis:[],decision_funct:2,decision_function_shap:2,decomposit:[0,45],def:[],defaultconfig:[0,7,47,51],defer:[],defin:[0,2,4,7,8,10,14,24,42,47,49,50,51],definit:[],degre:[2,18,32,47],del:50,del_password_for_us:[],delai:2,delet:2,delete_cc_para:2,delete_nonestimator_paramet:2,delete_output_folder_after_termin:[],delete_tmp_folder_after_termin:[],demand:2,dementia:2,demo:[],demo_param:2,demonst:2,den:45,depend:[0,2,9,49,51],depict:[],deprec:[],depth:[18,47],der:45,deriv:[],describ:[0,2,48,51],descript:[2,8,16,18,20,22,24,26,28,30,32,34,36,38,40,42,44,47],design:49,desir:[],desmoid:45,detail:[2,9,47,51],detect:[],detector:[0,45,46],determin:[2,9,16,22,24,26,28,32,34,36,40,42,47,49,50,51],determinist:2,dev:[],develop:[2,49,50,51],deviat:[32,47],diagram:[],dicom:[0,47,51],dict:[0,1,2,8,10],dict_valu:[],dictionari:[0,1,2,9,10,47,51],did:[49,51],die:[],die_sid:[],differ:[2,9,10,45,46,49],differenti:45,difficult:49,dilat:51,dim1:[],dim2:[],dimens:[],dimension:49,dimnam:[],dir:[],direct:[46,51],directli:[49,51],directori:[0,47,50,51],dirk:45,dirnam:50,disabl:[],disable_evaluator_output:[],disambigu:[],discret:[32,47],discrete_uniform:2,discuss:51,dispatch:2,displai:[],dist:50,distanc:[8,24,32,47],distance_p:8,distinguish:[2,51],distribut:[2,50,51],distrubit:2,divers:49,divid:49,do_detect:4,doc:[],doctest:2,document:[2,46],doe:[2,8,46],doing:[],don:50,done:[2,49,51],down:[],download:[46,50],download_headandneck:[5,50],download_project:5,download_subject:5,dpi:9,draw:[],draw_dimens:[],draw_network:51,drawn:[2,30,47],drop:46,dti:46,dti_post:[],dtrf:45,due:[2,46,49],dummi:46,dump:[],dure:2,each:[2,8,9,10,46,47,49,50,51],earlier:50,easi:[45,49],easier:[46,49],easili:[47,49,50,51],ecr:45,edg:[32,47],edit:[50,51],editelastixtransformfil:46,edwardo:2,effect:[],effici:2,effort:49,efron:51,eigen:[17,47],either:[0,2,8,9,24,47,50,51],elabor:[],elasticnet:[17,18,47],elasticnet_alpha:[17,18,47],elasticnet_l1_ratio:[17,18,47],elastix4:[27,47],elastix:[0,27,45,46,47,51],elastix_para:0,elastix_test:[0,11],elastixlogfil:[],elastixparameterfil:[],elastixtransformfil:[],element:[24,47,51],ellipsi:2,els:[],email:[],embed:46,empir:51,emploi:2,empti:2,enabl:[2,47],encount:[],end:45,engin:[2,45,49],enhanc:[],enough:2,ensembl:[2,3,9,14,22,45,46,49],ensemble_memory_limit:[],ensemble_nbest:[],ensemble_s:[],ensemble_scor:9,ensur:0,enter:[2,10],entir:2,entiti:[],enumtyp:[],env:[],environ:50,envis:[],equal:[2,8,22,47],equival:[],erasmu:49,ercim:[],error:[2,46,50,51],error_scor:2,especi:[2,28,46,47],establish:45,estim:[0,7,9,14,17,18,22,30,45,47],estimator_scoring_overrid:7,etc:[2,8,9,45],etcetera:50,european:45,eusomii:45,evalu:[0,2,9,30,45,46,47,50],even:[],event:[],everi:[28,47,49],everyth:[],evolv:[],exact:2,exampl:[0,2,9,14,46,47,49,50,51],example_network_rerun:[],example_stwstrategyhn4:50,example_stwstrategymmd:[],example_tool:[],exampledata:[0,45,50],examplefil:50,excel:51,except:[0,6,46],exclud:[24,47],exclude_estim:[],exclude_preprocessor:[],exe:[],execu:[],execut:[0,2,7,14,17,18,45,47,49,50],execute_first:7,execute_job:[],execution_fail:[],execution_plugin:[],executionplugin:51,executionpluginmanag:[],executionscript:[],exhaust:2,exist:[14,46,49],exp:2,exp_uniform:2,expand:9,expand_macro:[],expect:[49,50],expected_hostnam:4,experi:45,experiment:[],experiment_fold:50,experiment_nam:50,explain:[24,47],explan:51,explicit:2,explicitli:[],explor:2,explos:2,expon:[2,18,47],express:2,ext:[],extend:[],extens:[49,50],extern:[],extra:[],extract:[1,2,8,9,10,42,47,49],extractnlargestblobsn:[0,45],f1_weight:[2,29,47],facad:[0,7,45,46,51],facilit:[45,49],fail:46,fail_1:[],fail_2:[],failing_network:[],failing_network_2017:[],failing_network___step_1___sample_1_1:[],failur:[],fals:[2,5,9,14,15,17,18,23,27,31,33,34,37,38,39,41,43,47,50],famili:[],familiar:49,fancyimput:8,fas:[],fashion:50,fast:2,fastr3:46,fastr:[0,2,14,17,18,30,45,46,47,50],fastr_bug:[],fastr_failing_network_2017:[],fastr_plugin:[0,2,14,17,18,47,51],fastr_result_:[],fastr_result_s1:[],fastr_result_s2:[],fastr_result_s3:[],fastr_result_s4:[],fastr_run_dump:[],fastr_tempdir:[0,47,51],fastr_test:[0,11],fastr_tmpdir:51,fastr_tool:[0,11],fastrconfig:[47,51],fastrhom:47,fastrinterfac:[],fastroutputvalidationerror:[],fastrtemp:[],fastrvalueerror:[],fatih:45,fator:2,feasibl:[],feat:2,feat_test:2,feat_train:2,featsel:[3,45],featur:[0,1,2,8,9,10,14,24,26,28,32,34,44,46,47,49,50],feature_fil:50,feature_label:[2,8,50],feature_label_1:9,feature_label_2:9,feature_select:[8,24,47],feature_set:8,feature_valu:[2,8,50],featurecalc:[],featurecalcul:[27,28,47],featurefil:[1,2],featurefile_p1:50,featureprocess:[0,45],features_:50,features_from_this_directori:50,features_mod1_patient1:[1,2],features_mod1_patient2:[1,2],features_mod2_patient1:[1,2],features_mod2_patient2:[1,2],features_p1:50,features_test:51,features_train:51,featuresc:[3,45],fed:[],feed:[],feel:[49,50],fellow:49,felt:49,ferenc:[],fetch:[],few:49,fibromatosi:45,fibrosi:45,fict:49,field:[2,8,47,49,50],fier:[],fig:9,figsiz:9,figur:[9,49],figwidth:9,file1:[2,8],file2:[2,8],file3:[2,8],file:[0,1,2,8,9,10,36,45,46,47,50,51],file_io:[0,45],file_path:[],filenam:[10,51],filepath:9,fill:[42,47],fill_valu:8,fillhol:[41,42,47],filter:[32,47,49],finalbsplineinterpolationord:46,find:[2,45,46,49,50],find_password_for_us:[],findlabeldata:10,fine:[],finish:[],first:[8,9,24,46,47,49,50,51],fit:[2,8,30,46,47,51],fit_and_scor:2,fit_param:2,fit_threshold:9,fit_tim:2,fitandscor:[0,45,46],fitfailedwarn:2,fittd:2,five:49,fix:[2,9,14,24,45,47,49,51],fixed_imag:[],fixed_mask:[],fixedsplit:2,flag:[],flexibl:[46,49],float_valu:[],flow:[],flownod:[],focu:[],fold:2,folder:[2,9,46,47,50,51],follow:[2,8,9,45,47,49,50,51],font_siz:[],fontsiz:9,footnot:[],forc:[],foresight:49,form:[],format:[0,1,2,8,9,45,46,47,51],formula:2,forum:[],forward:49,forwardssampl:[],found:[2,45,47,49,50],foundat:45,four:49,fpr:9,fprt:9,framework:[45,46,49],frangi:[32,47],free:50,freedesktop:[],freeli:51,frequenc:[32,47],frequent:8,from:[0,1,2,8,9,10,17,30,32,36,42,45,46,47,49,51],froma:[],frontier:[],frontiersin:49,frozenset:[2,4,8],fsl:[],fslmath:[],fulfil:2,full:[7,9,37,38,47,49,50],full_overrid:7,fulli:45,fullnam:[],fullprint:7,fun:49,funtion:8,further:46,furthermor:[],futur:46,gabor:[32,44,47],gabor_angl:[31,32,47],gabor_frequ:[31,32,47],gamma:[2,18,47],garcia:2,gaussiannb:[17,47],gave:2,geert:45,gener:[0,2,3,9,24,40,45,46,49,51],generate_boxplot:9,genet:[10,47],georg:45,get:[2,9,45,49,50],get_password_for_us:[],get_smac_object_callback:[],getfold:[],getparametermap:14,gibhub:45,git:50,github:[1,2,8,9,45,50,51],give:[2,46,49,50,51],given:[0,2,8,9,30,32,46,47,51],glcm:[32,44,47],glcm_angl:[31,32,47],glcm_distanc:[31,32,47],glcm_level:[31,32,47],glob:50,global:[],glrlm:[32,44,47],glszm:[32,44,47],glu:[],gnome:[],goe:[],going:49,googl:[],got:[],gotten:[],govern:[],gpl:[],grade:45,grahpviz:46,grain:[],grand:2,graph:[],graphic:[],graphviz:[],grayscal:[32,47],grid:[2,30,47],grid_scor:46,grid_scores_:[],gridsearch:[18,47],gridsearchcv:2,gridsearchcvfastr:2,gridsearchcvjoblib:2,ground:[9,51],groundtruth:2,group:[2,8,24,47,49,51],groupsel:2,groupwis:[2,51],groupwisesearch:[23,24,47],gsout:2,guarante:2,gui:[],guid:[2,45],guidelin:51,guillaum:45,gzip:[],hachterberg:[],had:[46,49],haibo:2,hakim:[],halton:2,haltonsampl:2,hand:49,handl:46,happen:[],harmon:45,has:[0,2,8,45,47,49],hasdimens:[],hassampl:[],have:[0,2,8,10,24,46,47,49,50,51],hdf5:[1,2,8,9,50,51],head:[50,51],header:[0,2,51],held:2,hello:45,help:[0,2,4,7,8,10,14],henc:[2,9,46,47,49,51],herder:45,here:[2,47,51],hf_mean:8,hide:[],hide_unconnect:[],high:[45,49,50],higher:2,highest:2,highli:[2,49],hing:[17,18,47],histogram:[2,31,32,44,47],histogram_featur:[8,43,44,47],histori:49,hofland:45,hold:[0,2],holdout:[],hole:[42,47],home:46,homogen:[18,47],hope:45,horribl:50,host:45,hostnamedetector:4,hounsfield:47,how:[2,9,22,32,42,46,47,49,50,51],howev:[2,47,49],html:[0,24,40,47,51],http:[0,2,24,40,45,47,49,50,51],human:[],hyper:2,hyperoptim:[3,30,45],hyperparamat:2,hyperparamet:[2,9,30,46,47,49],i_max:9,i_min:9,icc:[2,51],icc_anova:2,icctyp:2,ict:[],id3:[],id4:[],id_:[],idea:[49,51],ident:2,identifi:50,ids:10,ieee:[2,45],ignor:47,iid:2,illustr:49,imag:[0,2,9,10,14,28,32,38,45,46,47,49,50],image_featur:[2,8,9,10],image_features_temp:10,image_features_test:2,image_features_train:2,image_file_nam:50,image_typ:[31,32,47],imagedatadir:50,imagefeatur:[3,45,51],images1:51,images_from_this_directori:[7,50],images_test:51,images_train:[0,51],imagin:[],imaginary_label_1:50,imbalanc:[2,40,47],imblearn:[40,47],img2:9,img:9,immedi:2,implement:[0,2,18,47,49,51],impli:[],implicitli:49,importerror:[],imposs:2,improv:2,imput:[0,2,3,34,45,46,49],imputat:2,in1:[],in2:[],in_1:[],in_2:[],in_:[],in_imag:[],incekara:45,includ:[0,2,22,46,47,49,51],include_estim:[],include_preprocessor:[],incompat:[],incorrect:46,incorrectli:[9,51],increas:[2,30,47],indent:[],indep:[],independ:[49,51],index:[2,8,45,47,51],index_to_sourc:[],index_to_target:[],indexerror:0,indic:[2,10],individu:2,ineffici:49,infer:51,infinit:46,influenc:[],info:[47,51],inform:[2,9,49,51],informat:45,inherit:[],ini:[0,1,2,8,46,47],init:[],init_nearmiss:2,init_randomoversampl:2,init_randomundersampl:2,init_smot:2,initi:[0,2,4,7,8,10,14,46],initial_configurations_via_metalearn:[],initial_transform:[],inner:[32,47],input:[0,2,9,14,45,46,47,49,51],input_fil:10,input_group:[],inputarrai:8,inputgroup:[],inputid_:[],inputmap:[],inputparameterdescript:[],insert:[],insid:[],inspect:46,instal:[45,46,47],instanc:[0,2],instanti:2,instead:[2,46,47,50,51],instruct:[],int_valu:[],integ:[2,8,9,10,15,17,19,21,22,23,27,29,31,32,33,34,39,41,47],integr:[45,49],intensif:[],inter:2,interact:[45,46],interest:[],interfac:2,interfaceresult:[],intermed:9,intermedi:[2,50],intermediatefacad:[46,51],intern:[45,51],interpret:49,intersect:[],interv:[9,46,51],inteteg:[23,47],intra:2,intraclass:51,introduct:[45,50],introductori:49,invalid:[],invalid_network:[],invalidcsvfileexcept:7,invalidorderexcept:7,inverse_transform:2,involv:2,ioerror:0,ionnod:[],iopars:[0,2,45],ioplugin:[0,51],ipynb:[],iri:2,is_detect:[],is_empti:2,is_valid:[],isbi:45,isi:51,isn:46,issu:[45,46,49,50,51],item:[0,2,8,50],iter:[2,9,16,18,28,30,47,51],iteritem:[],ith:2,itk:[0,46],itkimag:9,itkimagefil:[],its:[2,49],itself:49,ivo:45,jacob:45,jifk:45,job:[2,30,47],jobdag:[],joblib:[2,18,28,46,47],joblib_backend:[27,28,47],joblib_ncor:[27,28,47],jobstat:[],john:[],join:50,jose:45,journal:49,json:[2,10,46,50],json_schema:[],jsoncollector:[],jth:2,jupyt:[],just:[46,50,51],kapsa:45,keep:[2,46,49],kei:[2,3,46,47,51],keio:[],kept:8,kernel:[2,18,47],kessel:45,keychain:[],keyerror:0,keyr:[],keyringprovid:[],keyword:[],kfold:2,kill:[],kind:[49,51],klein:45,knn:[8,33,34,47],know:[],knowledg:2,known:[],koek:[],kwallet:[],kwarg:[2,4,7],label1:[35,47,51],label2:[35,47,51],label:[0,1,2,3,8,9,10,36,45,46,49,50],label_data:[2,9,10],label_data_test:2,label_data_train:2,label_fil:[2,9,10,14,50],label_info:10,label_nam:[1,2,10,35,36,47,50],label_process:[0,45],label_s:2,label_set:8,label_statu:10,label_typ:[0,2,8,9,10,14,51],labels_from_this_fil:[7,50],labels_test:51,labels_train:51,lambda:2,lambda_tol:2,lan:[],languag:[45,49],lanuag:[],laptop:49,larg:[2,49],larger:46,largest:[10,42,47],lasso:[2,17,24,47],last:[46,49],lastli:[38,47],later:47,launch:[],layer:[],layout:[],lbp:[32,44,47],lbp_npoint:[31,32,47],lbp_radiu:[31,32,47],lda:[17,18,47],lda_shrinkag:[17,18,47],lda_solv:[17,18,47],lear:[],learn:[2,8,9,24,40,47,49,51],least:[2,49],leav:[],leender:45,left:[2,46],left_hand:[],legal:[],len:[],length:[2,8,9],lengthi:50,less:[],let:[50,51],level:[32,47,51],lgpl:[],lib:50,libari:[],librari:50,licens:45,lightweight:2,like:[2,46,47,49,50],limit:[],line:[2,8,49,50],linear:[2,17,47],linearexecut:[14,17,47],link1:[],link2:[],link:[46,50,51],link_0:[],linstretch:[0,45],linux:46,linuxdetector:4,lipoma:45,liposarcoma:45,list:[0,1,2,4,7,8,9,10,14,32,34,47,51],list_valu:[],littl:[2,49],liver:[45,51],load:[1,2,10,32,47,50],load_config:1,load_config_xnat:10,load_data:1,load_featur:2,load_iri:2,load_label:10,load_label_csv:10,load_label_fil:[],load_label_txt:10,load_label_xnat:10,loc:[2,17,23,33,39,47],local:[7,32,47,50],localbinarytarget:[],locat:[47,50],log:[18,31,32,44,47,49],log_featur:[8,43,44,47],log_fil:[],log_sigma:[31,32,47],log_uniform:2,logger:[],logging_config:[],logic:[],login:[],longer:46,look:[47,49,51],loop:[],loss:[2,18,47],lot:49,low:45,lower:[8,24,47],lower_case_with_underscor:[],lower_threshold:[],lrc:[17,18,47],lrpenalti:[17,18,47],lsqr:[17,47],luckili:49,maarten:45,mac:[],machin:[2,49,51],maco:[],macro:[],macronod:[],macskassi:51,made:[9,45,46,49,51],mai:[2,47,49,50],main:[9,12,50,51],major:[40,46,47],make:[2,9,46,47,49,50,51],make_scatterplot:9,make_scor:2,malign:45,manag:0,mandatori:[1,2,8,9],mani:[0,2,9,22,42,46,47,49],manipul:51,mann:51,mannwhitneyu:[8,23,47],manual:[45,49,50],map:[2,51],mappingproxi:[0,2,4,7,8,10,14],marcel:[],marion:45,martijn:45,martin:45,mask:[0,2,9,38,41,42,46,47,49,50],masked_arrai:2,masks_test:51,masks_train:51,master:2,match:[1,2,10,47,51],match_typ:[],math:[],matlab:[10,45,49],matplotlib:9,matrix:2,matter:8,max:[24,31,47],max_it:[2,17,18,47],max_thread:[],maxim:2,maximum:[2,18,32,47],maxlen:[2,29,30,46,47],mean:[2,8,33,46,47,51],mean_fit_tim:2,mean_score_tim:2,mean_test_scor:2,mean_train_scor:2,meant:[],measur:[2,51],median:[8,33,38,47],medic:[45,49],meet:45,melissa:45,member:2,memori:[2,30,46,47],mention:[],mercuri:[],merg:[],mesenter:45,messag:[2,9],metadata:[0,46],metadata_directori:[],metadata_test:51,metadata_train:51,metalearn:[],method:[0,2,8,9,10,24,26,34,37,38,47,49,51],metric:[0,8,9,29,30,45,46,47,51],mhd:51,mic:[],miclea:45,micro:49,microsoft:50,middl:[9,51],might:50,milea:45,mimic:10,min:[24,31,47],mind:[],mine:49,mini:[],minim:[2,32,47,50,51],minimum:[18,32,38,46,47],minkov:8,minm:[37,47],minmax:[25,47],minor:[40,46,47],miss:8,missing_valu:8,missingpi:8,mit:[],mixin:[],ml_memory_limit:[],mobview:[],modal:[2,8,32,46,47,51],modalityname1:[2,8],modalityname2:[2,8],model:[1,2,9,14,24,30,44,46,47,49,51],model_evaluatio:[],model_select:[2,8],modifi:[],modified_hub:[17,47],modnam:1,modu:[2,9,14,35,36,47],modul:[6,11,24,46,47,51],modular:45,moment:[],more:[2,8,9,46,47,49,50,51],moreov:49,most:[2,8,18,47,49],most_frequ:[8,33,47],mostli:47,mount:[2,50],move:46,moving_imag:[],moving_mask:[],mr001:0,mr002:0,mse:51,mstarmans91:[45,50],much:[40,46,47],multi:2,multi_class_auc:2,multi_class_auc_scor:2,multi_class_relief:8,multiclass:[2,51],multicor:[28,47],multilabel:[2,35,36,46,47],multilabel_typ:9,multimod:46,multipl:[0,2,9,46,47,49,50,51],multipli:[41,42,47],multiprocess:[27,47],multislic:[32,44,47],must:[2,47],mutat:45,mutlicor:2,mutlipl:[],mxn:2,n_1:9,n_2:9,n_blob:[41,42,47],n_core:2,n_featur:2,n_iter:[2,14,15,16,19,20,29,30,47],n_job:2,n_jobspercor:[2,29,30,47],n_jobsperscor:2,n_neighbor:[2,8,33,34,47],n_neighbour:8,n_neightbor:8,n_output:2,n_sampl:2,n_split:[2,29,30,46,47],n_splits_:2,n_test:9,n_train:9,nadeau:51,naiv:49,name:[0,2,8,9,10,14,18,46,47,50,51],name_of_label_predicted_for_evalu:51,namespac:[],nan:[2,8,34,46,47],ndarrai:2,nearest:[8,24,34,47],neccesari:46,necessari:[],neck:50,need:[2,46,47,49,50,51],neg:[46,51],neg_dual_func:2,neighbor:[8,24,34,40,47],neighbour:8,nest:[],netrc:[],nettyp:14,network:[0,12,14,45,46,47,49,50],network_nam:[],network_st:[],networkrun:[],neural:51,neuro:[],newbas:2,newest:[],newli:[],nework:0,next:[50,51],ngtdm:[32,44,47],nice:49,niessen:45,nifti:51,niftiimagefil:[],niftiimagefilecompress:[],nii:[0,50,51],nipyp:2,nnode:[],nocrossv:2,node1:[],node2:[],node:[46,47,49,51],node_group:[],nodeid:[],nodeid__:[],nodelist:[],noderun:[],noimagesfoundexcept:7,nomean:8,non:[2,49],none:[0,1,2,4,5,7,8,9,10,14,17,41,42,47],nonparametr:51,norm_tol:2,normal:[2,3,9,38,45,46,49,51],normalization_factor:9,normalize_whitespac:2,nosegmentationsfoundexcept:7,nospac:[],not_label:2,notabl:46,notat:[],note:[0,2,9,46,47,49,50,51],notebook:[],notimpl:[],notimplementederror:0,now:46,npv:[46,51],nrrd:51,nsampl:9,nsubject:[5,50],num_class:2,num_param:[],num_train:2,number:[2,8,9,10,16,18,20,24,28,30,32,34,40,47,49],number_of_class:[],number_of_level:[],number_of_sid:[],numbertoextract:10,numer:[2,8,51],numf:8,numpi:[2,8,9,10,46,50],object:[0,2,4,7,8,9,10,14,18,40,45,46,47,50],objectsampl:[0,45],obscur:[],observ:2,obsolet:[28,47],obtain:[],occur:[2,24,47,51],occurr:8,off:[2,51],offici:45,often:[49,51],omit:50,onc:10,one:[0,2,9,10,46,47,49,50,51],onevsrest:46,onevsrestclassifi:2,onli:[0,2,8,10,18,30,46,47,49,50,51],onlin:[49,50],ontolog:49,onward:2,open:[45,46,49,50],oper:[9,51],opim:2,optim:[0,2,18,30,46,47,51],optimiz:0,option:[0,1,2,8,9,15,17,19,21,23,25,27,29,31,33,35,37,39,41,43,46,47,50,51],orang:[],order:[2,8,9,49],ordinari:[],org:[2,24,47,49],organ:49,orient:[31,32,44,47],orientation_featur:[8,43,44,47],origin:[2,47],oserror:0,other:[0,2,8,24,45,47,49,51],other_dict_valu:[],other_list_valu:[],other_str_valu:[],otherwis:[2,38,47],ouput:[],our:[45,47,50,51],out:[2,9,10,47,49,50,51],out_1:[],out_2:[],out_:[],out_imag:[],outcom:[2,30,47,49,50],outer:[20,47],output:[2,8,9,14,46,47,49,50],output_csv:9,output_dir:[],output_fold:[],output_hdf:2,output_itk:9,output_json:2,output_nam:9,output_name_zoom:9,output_png:9,output_tex:9,output_zip:9,outputfold:[2,9,50],outputid:[],outputmap:[],oval:[],over:[2,47,49],over_sampl:[40,47],overal:[46,50],overfit:[],overid:46,overlai:9,overrid:46,oversampl:[2,39,40,46,47,49],overview:[47,51],overwritten:0,own:[27,47,49,50],packag:[45,46],packagedir:46,pad:[9,14],padmo:45,page:[45,49,51],pair:[],pairwis:[],pairwise_auc:2,panda:[2,9,50],panda_data:2,paper:[],para:2,paracheck:9,paragraph:[],parallel:[2,46,47],param:[2,9],param_c:2,param_degre:2,param_distribut:2,param_gamma:2,param_grid:2,param_kernel:2,param_list:2,paramet:[0,2,8,9,18,24,30,40,46,47,49,51],parameter_optim:[0,45],parametergrid:2,parameters_al:2,parameters_est:2,parametersampl:2,paramt:2,parent:14,pars:[1,47],part:[2,24,32,47,49,51],partial:[],particular:[],pass:[2,46,51],password:[],past:[],path:[0,1,2,7,8,9,10,46,50],pathnotfoundexcept:7,patient001:0,patient002:0,patient1:[47,51],patient2:[47,51],patient3:[47,51],patient:[0,1,2,8,9,10,40,44,46,47,50,51],patient_001:50,patient_002:50,patient_featur:[8,43,44,47,51],patient_id:[2,10,14],patientclass:[46,47],patientinfo:[1,2,8,10],patientinfo_test:2,patientinfo_train:2,pattern:51,payload:[],pca:[2,24,46,47],pcatyp:[23,24,47],pce:46,pearson:51,peform:50,penalti:[18,47],pentagon:[],peopl:45,pep8:[],pep:[],per:[0,1,2,8,46,47,51],per_run_time_limit:[],percentag:[2,8,9,14,20,30,47,50,51],percentil:46,perform:[2,8,9,14,28,30,36,46,47,49,50,51],performance_all_0:50,performance_fil:50,performance_metr:2,performance_multilabel:2,performance_singlelabel:2,phase:[31,32,44,47],phase_featur:[8,43,44,47],phase_minwavelength:[31,32,47],phase_nscal:[31,32,47],phd:49,phil:45,philosophi:[],pick:51,pickl:[],pictur:[],pid:9,pid_:[],pilot:[],pinfo:[9,14,46],pinfo_hn:50,pink:[],pinpoint:[],pip:45,pipelin:[0,45,49,51],pixel:[0,9,32,47],place:[],placehold:8,plai:[],plaintext:[],plan:[],platform:[45,49,50],pleas:[2,45,50,51],plot:[0,2,45,46],plot_bar:9,plot_barchart:[0,45],plot_boxplot:[0,45],plot_im_and_overlai:9,plot_imag:[0,45],plot_ranked_imag:9,plot_ranked_percentag:9,plot_ranked_posterior:9,plot_ranked_scor:[0,45],plot_roc:[0,45],plot_roc_c:9,plot_single_roc:9,plot_single_svr:[],plot_svm:[0,45,46],plot_svr:46,plotminmaxrespons:[0,45],plotrankedscor:46,plu:[2,51],pluge:0,plugin:[0,2,17,18,47,49,51],png:[9,46],point:[2,9,32,47],pointer:[],pointint:9,pointsar:9,poli:[2,17,47],polynomi:[18,47],popul:[],port:46,posit:[2,8,9,24,47,51],possibl:[2,8,45,49],post:50,posterior:[9,51],power:[],ppv:51,practic:49,pre_dispatch:2,precis:51,precomput:50,predefin:[],predict:[2,9,27,45,46,47,49,50,51],predict_label:[7,46,50],predict_log_proba:2,predict_proba:2,predictgener:[],predit:46,prefer:[],preferred_typ:[],prefix:[],prepend:[],preprocess:[2,27,28,46,47,49,51],preprocessi:[],preprocessor:[],preprocss:2,present:[2,45,46],press:45,prevent:46,previou:[49,51],previous:[47,49],principl:[24,47,49],print:[2,7,8,46,50,51],prior:[],priorit:[],prioriti:[],privat:[],probability_imag:[],probabl:[2,50],problem:[2,45,46,49],procedur:[8,47,51],proceed:[45,51],process:[0,2,28,45,47,49,51],process_fit:2,processor:[],processpollexecut:51,processpoolexecut:14,produc:2,profil:[],program:49,progress:2,project:[5,10,46],project_nam:5,projectid:[35,36,47],prompt:[],prone:[],proper:[0,46],properli:46,properti:2,proport:[],propos:[],prostat:45,prov:[],provdocu:[],proven:49,provid:[0,2,9,14,22,47],provost:51,prune:[],pseudo:2,publish:[],pull:[],purpos:0,push:[],put:[9,46,47,51],pxcastconvert:46,pycrypto:[],pyradiom:[27,47,50],python3:[46,50],python:[45,46,47,49,50],qda:[17,18,47],qda_reg_param:[17,18,47],qualiti:2,quantit:49,question:49,quick:[45,47],quit:49,qxm:2,radian:[32,47],radii:[32,47],radiolog:45,radiom:[0,47,51],radiu:[32,42,47,51],rais:2,ran:[2,50],randint:[],random:[2,24,40,47,51],random_numb:[],random_search:2,random_search_paramet:2,random_st:2,randomizedsearchcv:2,randomizedsearchcvfastr:2,randomizedsearchcvjoblib:2,randomli:[2,24,47],randomsearch:2,randomst:2,rang:[9,18,24,40,47],rank:[8,9,30,46,47,49,51],rank_:2,rank_test_scor:2,ranked_pid:9,ranked_scor:9,ranked_truth:9,rankedsvm:[0,45,46],ranking_scor:[2,29,30,47],ranksvm:2,ranksvm_test:2,ranksvm_test_origin:2,ranksvm_train:2,ranksvm_train_old:2,rate:51,rather:2,ratio:[9,18,40,47],razvan:45,rbf:[2,17,47],reach:[],read:[1,2,10,49,50,51],read_config_fil:[],read_hdf:50,readabl:[],readi:[],readthedoc:[0,40,45,46,47,51],real:[],realli:47,reason:2,rebuild:[],rebuilt:[],recal:51,receiv:[9,51],recommend:[2,18,47,49,50],recommmend:50,record:[],recreat:2,rectangl:[],reduc:2,reduct:[46,49],ref:2,refer:[0,1,2,3,4,7,8,9,10,14,27,46,47,49,51],referen:[],referenc:[],refit:2,refit_and_scor:2,reflect:[],regardless:50,regist:[],registr:[28,46,47,49,51],registratio:0,registrationnod:[27,28,47],registri:[],regress:[2,7,14,36,46,47,51],regressor:[0,45],regular:[18,47],rel:2,relat:0,releas:[46,49],relev:49,reliabl:[],relief:[0,2,24,45,46,47],reliefdistancep:[23,24,47],reliefnn:[23,24,47],reliefnumfeatur:[23,24,47],reliefsamples:[23,24,47],reliefsel:2,reliefus:[23,24,47],remov:[28,46,47],renam:46,repeat:[2,47],replac:[2,8,34,47],replacenan:[2,46],repo:[],report:51,repositoi:[],repositori:[45,50],repr:[],repres:2,represent:[],reproduc:49,request:[],requir:[0,2,18,45,46,47,49,50],rerun:[],resampl:51,resampling_strategi:[],resampling_strategy_argu:[],research:[45,49],resolv:[],resourc:[0,10,12,45,49],resourcelimit:[],respect:[2,8,50],respons:[],rest:[],result:[2,8,9,28,38,45,47,49],result_1:[],result_2:[],resum:[],ret:2,retain:[],retreiv:10,retri:[],retriev:[],return_al:2,return_n_test_sampl:2,return_paramet:2,return_tim:2,return_train_scor:2,reus:[],revert:46,rfmax_depth:[17,18,47],rfmin_samples_split:[17,18,47],rfn_estim:[17,18,47],rfr:[17,47],ride:[],right:51,right_hand:[],ring:[41,42,46,47,51],risk:[],rms_score:2,rng:2,roc:[9,46,51],roc_threshold:9,roi:[37,38,46,47,51],root:2,ros:2,rosset:51,round:2,rounded_list:2,routin:49,row:[2,8],rst:[],rtstructread:[0,45,46],rule:[],run:[2,46,47,49,50,51],rundir:[],runhistori:[],runtim:2,runtimeerror:[],rvs:2,safe:[],sagit:46,same:[2,8,18,40,46,47,49,50,51],sampl:[0,2,8,9,18,24,30,40,47,51],sample_1_1:[],sample_1_2:[],sample_1_3:[],sample_id:[],sample_s:8,sampleprocess:[3,45],sampling_strategi:2,sar:2,sar_scor:2,save:[2,9,28,30,46,47,50,51],scale:[2,17,18,23,26,32,33,39,40,47,49],scale_featur:[25,26,47],scaler:[2,46],scaling_method:[25,26,47],scan:[47,50],scatterplot:[0,45],scenario:[],scenario_dict:[],scenc:[],schedul:[],schedulingplugin:[],schema:[],scheme:[],schoot:45,scienc:51,scikit:[2,24,47],scipi:2,score:[2,8,9,14,30,38,46,47,51],score_tim:2,scorer:2,scorer_:2,scoring_method:[2,7,29,30,47],scratch:[],script:[49,50],script_path:50,scroll:51,search:[2,8,24,30,45,46,47],searchcv:[0,9,45,46],sebastian:45,second:[2,8,47],secret:[],secret_servic:[],secretprovid:[],secretservic:[],secretstorag:[],section:[47,51],secur:[],see:[0,1,2,4,7,8,9,10,14,18,24,40,45,47,50,51],seed:2,seem:49,seen:[2,51],seg1:51,seg2:51,seg:14,segment:[0,9,14,28,42,46,47,49,50],segmentation_file_nam:50,segmentations1:51,segmentations2:51,segmentations_from_this_directori:[7,50],segmentations_test:51,segmentations_train:51,segmentix:[1,3,27,28,45,46,51],segmentix_test:[0,11],segradiu:[41,42,47],segtyp:[41,42,47],sel:8,select:[2,8,18,24,46,47,49,51],selectfeatgroup:[3,24,45],selectfrommodel:[23,24,47],selectgroup:[0,45],selectindividu:[0,45],selectmodel:2,selectmulticlassrelief:8,selectormixin:8,self:[0,2,4,7,8,10,14,18,47],selfeat_vari:8,semant:[0,44,46,47],semantic_featur:[8,43,44,47],semantics_from_this_fil:7,semantics_test:51,semantics_train:51,send:[],sensit:51,separ:[2,46,47,51],sequenc:[0,2,51],sequenti:[],serial:[],serpar:46,serv:[0,49,51],servic:[],session:5,set:[0,1,2,8,9,14,18,30,34,38,45,46,47,49,50],set_data:[],set_multicore_execut:[7,50],set_password_for_us:[],set_tmpdir:[7,50],settin:2,settings_dict:1,setup:[],sever:[8,10,46,47,49,51],sex:51,sf_compact:8,sgd:[17,18,47],sgd_alpha:[17,18,47],sgd_l1_ratio:[17,18,47],sgd_loss:[17,18,47],sgd_penalti:[17,18,47],sgdr:[17,47],shape:[2,8,31,32,44,47],shape_featur:[8,43,44,47],share:[],shared_mod:[],shear:49,sheet:51,shell:[],ship:[],shortcut:[],shorthand:[],should:[0,1,2,8,9,28,40,42,47,51],show:[2,50],show_plot:9,shown:49,shrink:2,shrinkag:[18,47],shuffl:[],shuffle_estim:9,side:[],sign:[2,8],signatur:[0,2,4,7,8,10,14],signific:[9,51],similar:[2,8,46,49,50,51],simpl:[49,50],simpleelastix:51,simpleitk:[38,47,51],simpler:49,simplest:[],simpleworc:[0,6,46,50],simpli:[47,50,51],simplifi:[],simul:[],simultan:[2,49],sinc:[],singl:[2,9,10,30,32,34,45,46,47,51],single_class_relief:8,singleclass:2,singlelabel:[2,9,14,35,36,47],singleton:2,sink1:[],sink2:[],sink:[0,14,46,49,51],sink_1:[],sink_2:[],sink_3:[],sink_4:[],sink_5:[],sink_data:[0,12,14],sink_id1:[],sinkenod:[],sinknod:[],site:[2,50],situat:[],size:[2,9,14,24,30,32,40,47,51],size_alpha:2,skip:[50,51],sklearn:[2,8,9,17,18,24,29,46,47],slack:[18,47],sleijfer:45,slice:[2,9,51],slicer:[0,9,45,46],slight:2,smac:[],smac_scenario_arg:[],small:46,smaller:[40,47],smallest:2,smart:9,smbo:[],smit:45,smote:[2,39,40,46,47],smote_neighbor:[2,39,40,47],smote_ratio:[2,39,40,47],snapshot:51,snippet:[],societi:45,softwar:[45,49],solid:[],solut:2,solv:49,solver:[18,47],some:[0,2,46,47,49,50],some_output_loc:[],somenam:[47,51],someon:49,someth:[],sometim:46,sort:[2,46],souc:[],sourc:[0,1,2,4,5,7,8,9,10,12,14,45,46,47,49],source1:51,source2:51,source3:[],source_data:[0,12],source_data_data:51,source_id1:[],source_id2:[],source_nod:[],sourcenod:[],sourcetre:[],space:[2,8],span:2,spawn:[0,2],spawner:0,spearmand:51,special:[],specif:[8,18,47,49,50,51],specifi:[0,2,18,24,28,30,40,47,51],speed:50,spend:2,spent:[],split0_test_scor:2,split0_train_scor:2,split1_test_scor:2,split1_train_scor:2,split2_test_scor:2,split2_train_scor:2,split:[2,8,14,18,20,46,47,49,51],squar:[2,51],squared_hing:[17,47],src:2,ssh:50,stabl:[0,24,40,47,51],stack:[1,2],stage:[],stai:[],standard:[32,45,47,50,51],standardis:45,starman:45,start:[2,45,46,47,49],stat:[2,9,50],state:[0,2,22,47,50],statement:10,statist:[2,8,9,24,46,47,50,51],statisticalsel:2,statisticaltestfeatur:[0,45,46],statisticaltestmetr:[23,24,47],statisticaltestthreshold:[0,23,24,45,47],statisticaltestus:[23,24,47],statsticaltestthreshold:46,statu:[2,10],std_fit_tim:2,std_score_tim:2,std_test_scor:2,std_train_scor:2,stderr:[],stdout:[],stefan:45,step1:[],step:[2,32,46,47,49,51],step_1:[],step_id:[],still:[46,47,50,51],stimul:45,stop:10,storag:[],store:[2,50,51],str:[2,46],str_valu:[],straight:49,strategi:[2,8,9,33,34,45,46,47],stratif:45,stratifi:[2,14],stratifiedkfold:2,strenght:[18,47],strength:[18,47],stretch:9,strict:[],string:[0,1,2,8,9,10,29,35,47,51],strongli:50,structur:50,stuck:50,student:[8,49,51],studi:[0,45,49],studio:50,stwheadandneck:[],stwstrategyhn1:50,style:[],sub:0,subclass:[],subdirectori:[],subfold:[46,50],subinput:[],subject:[2,5],subkei:[15,16,17,18,19,20,21,22,23,24,25,26,27,28,29,30,31,32,33,34,35,36,37,38,39,40,41,42,43,44,47],subobjectmap:[],subouput:[],suboutput:[],subpackag:45,subprocess:[],subset:50,subtract:[41,42,46,47],succeed:[],succesful:[],success:2,successfulli:[],suggest:2,suit:[0,2,10],sum:[],summari:[],suppli:[1,2,9,32,38,40,42,47,51],support:[2,8,35,45,46,47,49,51],suppos:47,sure:[50,51],surgeri:45,surrog:2,surviv:[7,9,51],svc:2,svd:[17,47],svg:[],svm:[2,9,17,18,46,47],svmc:[17,18,47],svmcoef0:[17,18,47],svmdegre:[17,18,47],svmgamma:[17,18,47],svmkernel:[17,18,47],svr:[2,17,47],symlink:46,symposium:45,syntax:[],synthet:47,sys:[],system:[0,2,47,50,51],tabl:[2,51],tadpol:[2,51],tag:51,take:[2,8,51],taken:[],target:2,task:49,techniqu:47,tedious:49,tell:51,temp:[],tempdir:50,templat:[],temporari:[0,46,50,51],tempsav:[2,27,28,47],term:[18,46,47,49],termin:[],terminolog:45,test:[0,2,8,9,20,24,30,46,47,50,51],test_data:2,test_metr:9,test_sampl:9,test_sample_count:2,test_scor:[2,29,47],test_siz:[2,14,19,20,29,30,47],test_target:2,test_throwdi:[],testserv:[],tex:[9,46],text:2,textur:[32,44,47],texture_featur:8,texture_gabor:[31,32,47],texture_gabor_featur:[8,43,44,47],texture_glcm:[31,32,47],texture_glcm_featur:[8,43,44,47],texture_glcmm:[31,32,47],texture_glcmms_featur:[8,43,44,47],texture_glrlm:[31,32,47],texture_glrlm_featur:[8,43,44,47],texture_glszm:[31,32,47],texture_glszm_featur:[8,43,44,47],texture_lbp:[31,32,47],texture_lbp_featur:[8,43,44,47],texture_ngtdm:[31,32,47],texture_ngtdm_featur:[8,43,44,47],than:[2,40,47],thei:[2,46,50,51],them:[2,47,49],therebi:[46,49,51],therefor:[0,8,49,50,51],thi:[0,2,8,9,30,38,40,45,46,47,48,49,50,51],thing:[47,50,51],thoma:45,thomeer:45,those:2,though:[],thread:[27,47],three:2,thresh:[8,9],threshold:[2,8,9,24,46,47],threshold_mask:[],thresholdimag:[],through:[0,2,14,45,46,47,49,50,51],throw_di:[],throwdi:[],thrown:[],thu:[2,8,47,49,51],tibshirani:51,tiff:51,timbergen:45,time:[2,9,20,47,49,50,51],time_left_for_this_task:[],timestamp:[],tionplugin:[],tip:45,tmp:[],tmp_dir:[],tmp_folder:[],tmpdir:50,todo:[0,2,8],togeth:[],tol:2,toler:2,tool:[0,27,28,45,46,47,48,49,50,51],tool_vers:[],toolbox:[47,51],toolmanag:[],toolnam:[],tools_path:[],top50:2,top:[9,46],tortoisehg:[],total:2,tpr:9,tprt:9,trace:50,track:2,trade:2,trail:[],train:[0,2,9,18,20,24,30,46,47,51],train_data:2,train_scor:2,train_siz:[],train_target:2,train_test_split:2,trainclassi:[],trainclassifi:[0,8,9,45,46],transact:2,transform:[2,8,28,46,47,51],transformat:[],transformationnod:[27,28,47],transformi:[],transformix:[0,27,45,46,47,51],translat:[],travi:46,treat:47,tree:[18,47],tri:[2,49],trick:45,trigger:[],trough:[],truth:[2,9,46,51],tsampl:9,ttest:[8,23,46,47],tumor:[45,50,51],tumour:45,tune:[2,49],tupl:2,turn:[],tutori:[45,47],twai:[],two:[0,2,9,17,23,31,33,39,47,50,51],txt:[0,1,2,8,9,46,47,51],type:[0,2,4,7,8,9,10,14,18,24,28,45,47,49],typeerror:0,typegroup:46,typenam:[],types_path:[],typic:51,ubuntu:50,udr:2,ulat:[],unag:10,unavail:[],uncorrect:51,under:[2,45,46,51],underli:2,understand:49,unfit:2,uniform:[2,18,40,47],uniformli:2,union:[],uniqu:[],unit:[46,47],univari:[2,51],univers:[2,45],unknown:[],unless:2,unreleas:[],unseen:[],unsupervis:2,unsupport:[],until:2,untouch:[],updat:46,upon:47,upper:[24,47],uppercamelcas:[],url:[10,35,36,47],urltyp:46,usabl:2,usag:[30,46,47],usd:8,use:[0,2,8,9,16,18,22,24,26,28,33,34,40,44,46,47,49,50,51],use_fastr:2,useag:8,used:[0,1,2,8,9,10,18,20,24,28,30,32,34,36,38,40,42,45,46,47,49,50,51],useful:[2,28,47,51],usepca:[23,24,47],user:[2,48,50],user_manu:[],usermanu:50,usernam:[],uses:[2,48,50],using:[0,2,8,18,24,34,38,45,46,47,49,50,51],usr:50,usual:[],util:2,val1:[],val2:[],val3:[],val4:[],val:[],valid:[0,2,8,9,14,20,28,30,46,47,51],valu:[0,2,8,9,10,24,34,46,47,50,51],value1:47,value2:47,valueerror:0,valuetyp:[],van:45,vari:49,variabl:[0,46,50],varianc:[2,8,23,24,47],variancethreshold:[0,24,45,46,47],variancethresholdmean:8,variant:49,variou:[2,45,46,47,48,49,51],varsel:2,vault:[],vector:2,veenland:45,verbos:[2,5,8,9],verhoef:45,veri:[2,49],verifi:[],version:[46,50],versu:45,vessel:[31,32,44,47],vessel_featur:[8,43,44,47],vessel_radiu:[31,32,47],vessel_scale_rang:[31,32,47],vessel_scale_step:[31,32,47],vfs:[0,51],via:45,view:[],vincent:45,virtual:[],virtualenv:50,virtualfilesystem:[],visser:45,visual:50,vizual:[],vol:51,volum:45,voort:45,w3c:[],wai:51,wait:[],want:[0,45,47,50,51],warn:2,warp:51,wavelength:[32,47],weak:[0,2,4,7,8,10,14],web:[],websit:[],weight:2,welch:[8,23,47,51],well:[45,46,47,49,50],went:[],were:[46,49,51],weus:51,what:[],whatev:[],when:[0,2,8,9,18,34,46,47,49,51],whenev:2,where:[2,49,50],wherea:[],whether:[2,9,10,16,22,26,28,32,36,40,42,46,47,50,51],which:[0,2,9,10,24,28,30,46,47,49,50,51],whitnei:51,who:[],whole:[30,47,49],wich:2,wide:[],width:51,wijnenga:45,wiki:[1,2,8,9],wilcoxon:[2,8,23,47,51],window:[18,45,46,47],wip:[2,8,9,35,36,47],wiro:45,wise:[],wish:[],within:[49,51],without:[2,51],wonder:49,worc:[1,2,4,5,7,8,9,10,12,14,18,27,46,47,48,49,50],worc_:50,worc_config:[46,47],worcassertionerror:0,worccastconvert:46,worccastcovert:46,worcerror:0,worcflow:45,worcindexerror:0,worcioerror:0,worckeyerror:0,worcnotimplementederror:0,worcpy27:[],worctutori:[45,50],worctypeerror:0,worcvalueerror:0,work:[10,46,49],workaround:2,workflow:[0,30,46,47,49,50,51],world:45,would:[47,49,50],wouter:45,wrap:49,wrapper:[],write:[],written:[2,9],wrong:[],wtype:0,www:[],x_train:[2,8,9],xcode:[],xlsx:2,xml:[],xnat:[10,50],xnat_url:5,y_optim:[],y_predict:[2,9],y_score:[2,9],y_train:[2,8,9],y_truth:[2,9],yaml:[],yellow:[],yet:[35,46,47],yield:2,yml:46,you:[0,2,10,14,40,46,47,49,50,51],your:[0,2,27,30,36,45,47,50],yourprovidernam:[],yourself:[45,49],yourusernam:[],z_score:[25,37,47],zero:[34,46,47],zip:[9,46,50],zoomfactor:9},titles:["WORC Package","IOparser Package","classification Package","<no title>","detectors Package","exampledata Package","facade Package","simpleworc Package","featureprocessing Package","plotting Package","processing Package","resources Package","fastr_tests Package","fastr_tools Package","tools Package","<no title>","<no title>","<no title>","<no title>","<no title>","<no title>","<no title>","<no title>","<no title>","<no title>","<no title>","<no title>","<no title>","<no title>","<no title>","<no title>","<no title>","<no title>","<no title>","<no title>","<no title>","<no title>","<no title>","<no title>","<no title>","<no title>","<no title>","<no title>","<no title>","<no title>","WORC","Changelog","Configuration","Resource File Formats","Introduction","Quick start guide","User Manual"],titleterms:{"0rc1":46,"class":10,"function":51,"import":50,Added:46,The:[50,51],Using:[],actual:50,addexcept:0,advanc:[],advancedsampl:2,algorithm:[],analysi:50,ask:[],attribut:51,bootstrap:47,broadcast:[],calcfeatures_test:12,chang:46,changelog:46,classif:[2,45,47],code:50,combin:[],command:51,compute_ci:9,config:[],config_io_classifi:1,config_preprocess:1,config_segmentix:1,config_worc:1,configbuild:7,configur:47,constantnod:[],construct:51,construct_classifi:2,content:47,continu:[],convent:[],creat:[],createfixedsplit:[2,14],creation:47,crossval:2,crossvalid:47,data:[],datadownload:5,datatyp:[],debug:51,decomposit:8,definit:[],descript:[],design:[],detector:4,develop:45,differ:[],dimens:[],document:45,elastix:14,elastix_para:51,elastix_test:12,ensembl:47,error:[],estim:2,evalu:[14,51],exampl:[],exampledata:5,except:7,execut:51,experi:50,extractnlargestblobsn:10,facad:6,fastr:[49,51],fastr_bug:[],fastr_test:12,fastr_tool:13,fastrhub:[],featsel:47,featur:51,featureprocess:8,featuresc:47,field:[],file:48,file_io:1,fitandscor:2,fix:46,flow:[],format:48,from:50,full:[],gener:47,guid:50,guidlin:[],hello:50,help:[],hyperoptim:47,hyperparamet:[],imag:51,imagefeatur:47,implement:[],imput:[8,47],indic:45,input:50,insid:[],instal:50,interact:47,intermediatefacad:[],introduct:[47,49],invalid:[],iopars:1,ioplugin:[],label:[47,51],label_process:10,link:[],linstretch:9,manual:51,mask:51,match:[],metadata:51,metric:2,modul:[0,1,2,4,5,7,8,9,10,12,14,45],modular:49,name:[],network:51,node:[],normal:47,object:51,objectsampl:2,optim:[45,49],origin:[],overview:[],own:[],packag:[0,1,2,4,5,6,7,8,9,10,11,12,13,14,50],parameter_optim:2,philosophi:[],pip:50,plot:9,plot_barchart:9,plot_boxplot:9,plot_imag:9,plot_ranked_scor:9,plot_roc:9,plot_svm:9,plot_svr:[],plotminmaxrespons:9,predictgener:[],preprocess:[],process:10,prov:[],proven:[],quick:50,radiom:[45,49],rankedsvm:2,refer:45,regressor:2,relief:8,resolv:[],resourc:[11,48],result:50,rtstructread:10,run:[],sampl:[],sampleprocess:47,scatterplot:9,schedulingplugin:[],searchcv:2,secret:[],secretprovid:[],section:[],segment:51,segmentix:47,segmentix_test:12,select:[],selectfeatgroup:47,selectgroup:8,selectindividu:8,semant:51,set:51,simpl:[],simpleworc:7,sinknod:[],slicer:14,sourc:[50,51],sourcenod:[],split:[],standard:49,start:50,statisticaltestfeatur:8,statisticaltestthreshold:8,subpackag:[0,6,11],system:[],tabl:45,terminolog:49,tip:50,tool:14,trainclassifi:2,transformix:14,trick:50,tutori:50,unreleas:[],upload:[],usag:[],user:[45,51],using:[],variancethreshold:8,via:50,w3c:[],window:50,worc:[0,45,51],worcpy27:[],workflow:45,world:50,your:51}}) \ No newline at end of file diff --git a/WORC/doc/_build/html/static/changelog.html b/WORC/doc/_build/html/static/changelog.html index 55f75b84..405b9b86 100644 --- a/WORC/doc/_build/html/static/changelog.html +++ b/WORC/doc/_build/html/static/changelog.html @@ -8,7 +8,7 @@ - Changelog — WORC 3.0.0 documentation + Changelog — WORC 3.1.0 documentation @@ -61,7 +61,7 @@
            - 3.0.0 + 3.1.0
            @@ -92,40 +92,46 @@
          • Configuration
          • Resource File Formats
          • Changelog
              -
            • 3.0.0 - 2019-05-08
                +
              • 3.1.0 - 2019-10-16
              • -
              • 2.1.3 - 2019-04-08
                  -
                • Changed
                • +
                • 3.0.0 - 2019-05-08
                • -
                • 2.1.2 - 2019-04-02
                    -
                  • Added
                  • -
                  • Changed
                  • -
                  • Fixed
                  • +
                  • 2.1.3 - 2019-04-08
                  • -
                  • 2.1.1 - 2019-02-15
                      +
                    • 2.1.2 - 2019-04-02
                    • -
                    • 2.1.0 - 2018-08-09
                        +
                      • 2.1.1 - 2019-02-15
                      • -
                      • 2.0.0 - 2018-02-13
                      • @@ -202,10 +208,81 @@

                        ChangelogKeep a Changelog and this project adheres to Semantic Versioning

                        -

                        3.0.0 - 2019-05-08¶

                        +

                        3.1.0 - 2019-10-16¶

                        Added¶

                          +
                        • Thresholding option in plot_SVM.

                        • +
                        • NPV (Negative Preditive Value) to classification metrics.

                        • +
                        • Facade for easier interaction with WORC.

                        • +
                        • Thresholding option in plot_SVM.

                        • +
                        • Function to create fixed splits for cross validation.

                        • +
                        • n_splits parameter for train-test cross validation.

                        • +
                        • Added generalization score.

                        • +
                        • Parameter to choose how many of the optimal settings to save (maxlen).

                        • +
                        • Option to combine multiple onevsrest models in plot_SVM.

                        • +
                        • StatsticalTestThreshold feature selection for multilabel problems.

                        • +
                        • Support for test sets in which only one class is present in various +plotting functions and the metrics.

                        • +
                        • Installation: create fastr home if it does not exist yet.

                        • +
                        • Boostrapping as performance evaluation in plot_SVM.

                        • +
                        • Confidence intervals for boostrapping based on percentile.

                        • +
                        • Catch for if patient is in the test set, but not the overall label set.

                        • +
                        • Downloader for downloading example datasets.

                        • +
                        • ReadTheDocs.yml for configuration of documentation.

                        • +
                        • Unit test included in Travis.

                        • +
                        • Various detectors.

                        • +
                        +
                        +
                        +

                        Changed¶

                        +
                          +
                        • Plot_SVR is removed: it’s now embedded in plot_SVM.

                        • +
                        • Moved statistical feature selection to last step in fit and score.

                        • +
                        • Also the minimum train and validation score are now saved.

                        • +
                        • Put scaler at top of fitandscore function.

                        • +
                        • Make link in file conversion if output is same format as input.

                        • +
                        • Sort keys in performance output JSON.

                        • +
                        • VarianceThreshold features selection on by default.

                        • +
                        • Removed grid_scores from SearchCV as support is dropped in sklearn > 0.20

                        • +
                        • Renamed IntermediateFacade to SimpleWORC

                        • +
                        • Use inspect to find packagedir

                        • +
                        +
                        +
                        +

                        Fixed¶

                        +
                          +
                        • Metric computation can now handle it when both the truth and the predicted +labels are from a single class.

                        • +
                        • Plotting module now correctly initialized.

                        • +
                        • Plot_SVM now also works properly for regression.

                        • +
                        • Masks for ROI normalization now properly added.

                        • +
                        • Preprocessing: mask needed to be cast to binary.

                        • +
                        • Failed workflows now return nan instead of zero for performance.

                        • +
                        • Several bugs in multilabel performance evaluation

                        • +
                        • Ring in segmentix was in sagital instead of axial direction.

                        • +
                        • Added replacenan in features before applying SMOTE.

                        • +
                        • Metadata test was not passed to calcfeatures: bugfix.

                        • +
                        • Bugfix: overide labels in facade when predict_labels is called.

                        • +
                        • Several bugfixes in the overrides in the facade configbuilder.

                        • +
                        • Various print commands converted to Python3: .format prints were still +left and sometimes buggy.

                        • +
                        • StatisticalTestFeatures and PlotRankedScores tools only accepted cardinality +of 1.

                        • +
                        • Bugfixes in many plotting functions: opening files with ‘w’ instead of ‘wb’ +due to python3 conversion, Compatibility issues with plot_SVM due to +conversion.

                        • +
                        • Except error when Grahpviz is not installed.

                        • +
                        • Symlinking in worccastcovert not supported by Windows, reverted to copying.

                        • +
                        • Bugfix in create_ensemble in SearchCV when using ensemble = 1.

                        • +
                        +
                        +
                        +
                        +

                        3.0.0 - 2019-05-08¶

                        +
                        +

                        Added¶

                        +
                        • Now ported to Python3.6+ (Python 2 is no longer supported!). Thereby also to fastr3.

                        • Compatibility for Windows. Some small changes in functions, as some packages @@ -214,8 +291,8 @@

                          Added
                        • Config is now also a sink.

                        -
                        -

                        Changed¶

                        +
                        +

                        Changed¶

                        • PCE and DTI node removed, as they were not open source.

                        • Pinfo file can now also be a csv. Txt is still supported.

                        • @@ -224,8 +301,8 @@

                          Changed -

                          Fixed¶

                          +
                          +

                          Fixed¶

                          • WORC_config.py was not correctly copied in Windows due to incorrect path separation.

                          • Source creation for the config was only for Linux.

                          • @@ -236,41 +313,41 @@

                            Fixed

                        -
                        -

                        2.1.3 - 2019-04-08¶

                        -
                        -

                        Changed¶

                        +
                        +

                        2.1.3 - 2019-04-08¶

                        +
                        +

                        Changed¶

                        • PREDICT was updated, so had to update the requirements. Changed it to a minimum of PREDICT to prevent these issues in the future.

                        -
                        -

                        2.1.2 - 2019-04-02¶

                        -
                        -

                        Added¶

                        +
                        +

                        2.1.2 - 2019-04-02¶

                        +
                        +

                        Added¶

                        • Dummy workflow in segmentix and calcfeatures PREDICT tools.

                        • Added several new PREDICT parameters.

                        • Slicer tool.

                        -
                        -

                        Changed¶

                        +
                        +

                        Changed¶

                        • Memory for elastix tool is now larger.

                        -
                        -

                        Fixed¶

                        +
                        +

                        Fixed¶

                        -Evaluate framework now correctly adopts the name you give it.

                        -
                        -

                        2.1.1 - 2019-02-15¶

                        -
                        -

                        Added¶

                        +
                        +

                        2.1.1 - 2019-02-15¶

                        +
                        +

                        Added¶

                        -
                        -

                        Changed¶

                        +
                        +

                        Changed¶

                        • Major reduction in memory usage, especially due to PREDICT updates.

                        • Only use first configuration in the classify config.

                        • Outputs are now in multiple subfolders instead of one big folder.

                        -
                        -

                        Fixed¶

                        +
                        +

                        Fixed¶

                        • Minor bug in test workflow: needed str of label in appending to classify.

                        • There was a bug in using a .ini file as a config.

                        -
                        -

                        2.1.0 - 2018-08-09¶

                        -
                        -

                        Added¶

                        +
                        +

                        2.1.0 - 2018-08-09¶

                        +
                        +

                        Added¶

                        -
                        -

                        Changed¶

                        +
                        +

                        Changed¶

                        • Separate sinks for the output segmentations of the elastix and segmentix nodes.

                        • @@ -328,8 +405,8 @@

                          Changed

                        -
                        -

                        Fixed¶

                        +
                        +

                        Fixed¶

                        • Patientclass ID was used for both test and training. Now given separate names.

                        • When elastix is used but segmentix isn’t, there was a bug.

                        • @@ -341,10 +418,10 @@

                          Fixed

                        -
                        -

                        2.0.0 - 2018-02-13¶

                        -
                        -

                        Added¶

                        +
                        +

                        2.0.0 - 2018-02-13¶

                        +
                        +

                        Added¶

                        -
                        -

                        Changed¶

                        +
                        +

                        Changed¶

                        • Option for multiple modalities. Supports infinitely many inputs per object.

                        • Moved many PREDICT parameters to the configuration file.

                        • @@ -364,8 +441,8 @@

                          Changed

                        -
                        -

                        Fixed¶

                        +
                        +

                        Fixed¶

                        • Proper combining of features from multiple modalities to classify tool.

                        • Minor bugs in segmentix tool.

                        • diff --git a/WORC/doc/_build/html/static/configuration.html b/WORC/doc/_build/html/static/configuration.html index a6ceead5..9a0b8898 100644 --- a/WORC/doc/_build/html/static/configuration.html +++ b/WORC/doc/_build/html/static/configuration.html @@ -8,7 +8,7 @@ - Configuration — WORC 3.0.0 documentation + Configuration — WORC 3.1.0 documentation @@ -61,7 +61,7 @@
                          - 3.0.0 + 3.1.0
                          @@ -90,22 +90,26 @@
                        • Quick start guide
                        • User Manual
                        • Configuration
                        • Resource File Formats
                        • @@ -179,7 +183,20 @@

                          Configuration¶

                          -

                          As WORC and the default tools used are mostly Python based, we’ve chosen +

                          +

                          Introduction¶

                          +

                          WORC has defaults for all settings so it can be run out of the box to test the examples. +However, you may want to alter the fastr configuration to your system settings, e.g. +to locate your input and output folders and how much you want to parallelize the execution.

                          +

                          Fastr will search for a config file named config.py in the $FASTRHOME directory +(which defaults to ~/.fastr/ if it is not set). So if $FASTRHOME is set the ~/.fastr/ +will be ignored. Additionally, .py files from the $FASTRHOME/config.d folder will be parsed +as well. You will see that upon installation, WORC has already put a WORC_config.py file in the +config.d folder.

                          +

                          For a sample configuration file and a complete overview of the options in config.py see +the configuration-chapter section.

                          +

                          % Note: Above was originally from quick start +As WORC and the default tools used are mostly Python based, we’ve chosen to put our configuration in a configparser object. This has several advantages:

                            @@ -187,6 +204,9 @@
                          1. Second, each tool can be set to parse only specific parts of the configuration, enabling us to supply one file to all tools instead of needing many parameter files.

                          +
                          +
                          +

                          Creation and interaction¶

                          The default configuration is generated through the WORC.defaultconfig() function. You can then change things as you would in a dictionary and @@ -219,38 +239,527 @@ list can be created by using commas for separation, e.g. Network.create_source.

                          -
                          -

                          General¶

                          -
                          -

                          PREDICTGeneral¶

                          -

                          These fields contain general settings for when using PREDICT. +

                          +

                          Contents¶

                          +

                          The config object can be indexed as config[key][subkey] = value. The various keys, subkeys, and the values +(description, defaults and options) can be found below.

                          + ++++ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +

                          Key

                          Reference

                          Bootstrap

                          Bootstrap

                          Classification

                          Classification

                          CrossValidation

                          CrossValidation

                          Ensemble

                          Ensemble

                          Featsel

                          Featsel

                          FeatureScaling

                          FeatureScaling

                          General

                          General

                          HyperOptimization

                          HyperOptimization

                          ImageFeatures

                          ImageFeatures

                          Imputation

                          Imputation

                          Labels

                          Labels

                          Normalize

                          Normalize

                          SampleProcessing

                          SampleProcessing

                          Segmentix

                          Segmentix

                          SelectFeatGroup

                          SelectFeatGroup

                          +

                          Details on each section of the config can be found below.

                          +
                          +

                          General¶

                          +

                          These fields contain general settings for when using WORC. For more info on the Joblib settings, which are used in the Joblib Parallel function, see here. When you run WORC on a cluster with nodes supporting only a single core to be used per node, e.g. the BIGR cluster, use only 1 core and threading as a backend.

                          +

                          Description:

                          + ++++ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +

                          Subkey

                          Description

                          cross_validation

                          Determine whether a cross validation will be performed or not. Obsolete, will be removed.

                          Segmentix

                          Determine whether to use Segmentix tool for segmentation preprocessing.

                          FeatureCalculator

                          Specifies which feature calculation tool should be used.

                          Preprocessing

                          Specifies which tool will be used for image preprocessing.

                          RegistrationNode

                          Specifies which tool will be used for image registration.

                          TransformationNode

                          Specifies which tool will be used for applying image transformations.

                          Joblib_ncores

                          Number of cores to be used by joblib for multicore processing.

                          Joblib_backend

                          Type of backend to be used by joblib for multicore processing.

                          tempsave

                          Determines whether after every cross validation iteration the result will be saved, in addition to the result after all iterations. Especially useful for debugging.

                          +

                          Defaults and Options:

                          + +++++ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +

                          Subkey

                          Default

                          Options

                          cross_validation

                          True

                          True, False

                          Segmentix

                          False

                          True, False

                          FeatureCalculator

                          predict/CalcFeatures:1.0

                          predict/CalcFeatures:1.0, pyradiomics/CF_pyradiomics:1.0, your own tool reference

                          Preprocessing

                          worc/PreProcess:1.0

                          worc/PreProcess:1.0, your own tool reference

                          RegistrationNode

                          ‘elastix4.8/Elastix:4.8’

                          ‘elastix4.8/Elastix:4.8’, your own tool reference

                          TransformationNode

                          ‘elastix4.8/Transformix:4.8’

                          ‘elastix4.8/Transformix:4.8’, your own tool reference

                          Joblib_ncores

                          4

                          Integer > 0

                          Joblib_backend

                          multiprocessing

                          multiprocessing, threading

                          tempsave

                          False

                          True, False

                          -

                          Segmentix¶

                          +

                          Segmentix¶

                          These fields are only important if you specified using the segmentix tool in the general configuration.

                          +

                          Description:

                          + ++++ + + + + + + + + + + + + + + + + + + + + + + +

                          Subkey

                          Description

                          mask

                          If a mask is supplied, should the mask be subtracted from the contour or multiplied.

                          segtype

                          If Ring, then a ring around the segmentation will be used as contour.

                          segradius

                          Define the radius of the ring used if segtype is Ring.

                          N_blobs

                          How many of the largest blobs are extracted from the segmentation. If None, no blob extraction is used.

                          fillholes

                          Determines whether hole filling will be used.

                          +

                          Defaults and Options:

                          + +++++ + + + + + + + + + + + + + + + + + + + + + + + + + + + + +

                          Subkey

                          Default

                          Options

                          mask

                          subtract

                          subtract, multiply

                          segtype

                          None

                          None, Ring

                          segradius

                          5

                          Integer > 0

                          N_blobs

                          1

                          Integer > 0

                          fillholes

                          False

                          True, False

                          -
                          -

                          Preprocessing¶

                          +
                          +

                          Normalize¶

                          The preprocessing node acts before the feature extraction on the image. Currently, only normalization is included: hence the dictionary name is Normalize. Additionally, scans with image type CT (see later in the tutorial) provided as DICOM are scaled to Hounsfield Units.

                          +

                          Description:

                          + ++++ + + + + + + + + + + + + + +

                          Subkey

                          Description

                          ROI

                          If a mask is supplied and this is set to True, normalize image based on supplied ROI. Otherwise, the full image is used for normalization using the SimpleITK Normalize function. Lastly, setting this to False will result in no normalization being applied.

                          Method

                          Method used for normalization if ROI is supplied. Currently, z-scoring or using the minimum and median of the ROI can be used.

                          +

                          Defaults and Options:

                          + +++++ + + + + + + + + + + + + + + + + +

                          Subkey

                          Default

                          Options

                          ROI

                          Full

                          True, False, Full

                          Method

                          z_score

                          z_score, minmed

                          -

                          Imagefeatures¶

                          +

                          ImageFeatures¶

                          If using the PREDICT toolbox, you can specify some settings for the feature computation here. Also, you can select if the certain features are computed or not.

                          +

                          Description:

                          + ++++ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +

                          Subkey

                          Description

                          shape

                          Determine whether orientation features are computed or not.

                          histogram

                          Determine whether histogram features are computed or not.

                          orientation

                          Determine whether orientation features are computed or not.

                          texture_Gabor

                          Determine whether Gabor texture features are computed or not.

                          texture_LBP

                          Determine whether LBP texture features are computed or not.

                          texture_GLCM

                          Determine whether GLCM texture features are computed or not.

                          texture_GLCMMS

                          Determine whether GLCM Multislice texture features are computed or not.

                          texture_GLRLM

                          Determine whether GLRLM texture features are computed or not.

                          texture_GLSZM

                          Determine whether GLSZM texture features are computed or not.

                          texture_NGTDM

                          Determine whether NGTDM texture features are computed or not.

                          coliage

                          Determine whether coliage features are computed or not.

                          vessel

                          Determine whether vessel features are computed or not.

                          log

                          Determine whether LoG features are computed or not.

                          phase

                          Determine whether local phase features are computed or not.

                          image_type

                          Modality of images supplied. Determines how the image is loaded.

                          gabor_frequencies

                          Frequencies of Gabor filters used: can be a single float or a list.

                          gabor_angles

                          Angles of Gabor filters in degrees: can be a single integer or a list.

                          GLCM_angles

                          Angles used in GLCM computation in radians: can be a single float or a list.

                          GLCM_levels

                          Number of grayscale levels used in discretization before GLCM computation.

                          GLCM_distances

                          Distance(s) used in GLCM computation in pixels: can be a single integer or a list.

                          LBP_radius

                          Radii used for LBP computation: can be a single integer or a list.

                          LBP_npoints

                          Number(s) of points used in LBP computation: can be a single integer or a list.

                          phase_minwavelength

                          Minimal wavelength in pixels used for phase features.

                          phase_nscale

                          Number of scales used in phase feature computation.

                          log_sigma

                          Standard deviation(s) in pixels used in log feature computation: can be a single integer or a list.

                          vessel_scale_range

                          Scale in pixels used for Frangi vessel filter. Given as a minimum and a maximum.

                          vessel_scale_step

                          Step size used to go from minimum to maximum scale on Frangi vessel filter.

                          vessel_radius

                          Radius to determine boundary of between inner part and edge in Frangi vessel filter.

                          +

                          Defaults and Options:

                          + +++++ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +

                          Subkey

                          Default

                          Options

                          shape

                          True

                          True, False

                          histogram

                          True

                          True, False

                          orientation

                          True

                          True, False

                          texture_Gabor

                          False

                          True, False

                          texture_LBP

                          True

                          True, False

                          texture_GLCM

                          True

                          True, False

                          texture_GLCMMS

                          True

                          True, False

                          texture_GLRLM

                          True

                          True, False

                          texture_GLSZM

                          True

                          True, False

                          texture_NGTDM

                          True

                          True, False

                          coliage

                          False

                          True, False

                          vessel

                          False

                          True, False

                          log

                          False

                          True, False

                          phase

                          False

                          True, False

                          image_type

                          CT

                          CT

                          gabor_frequencies

                          0.05, 0.2, 0.5

                          Float(s)

                          gabor_angles

                          0, 45, 90, 135

                          Integer(s)

                          GLCM_angles

                          0, 0.79, 1.57, 2.36

                          Float(s)

                          GLCM_levels

                          16

                          Integer > 0

                          GLCM_distances

                          1, 3

                          Integer(s) > 0

                          LBP_radius

                          3, 8, 15

                          Integer(s) > 0

                          LBP_npoints

                          12, 24, 36

                          Integer(s) > 0

                          phase_minwavelength

                          3

                          Integer > 0

                          phase_nscale

                          5

                          Integer > 0

                          log_sigma

                          1, 5, 10

                          Integer(s)

                          vessel_scale_range

                          1, 10

                          Two integers: min and max.

                          vessel_scale_step

                          2

                          Integer > 0

                          vessel_radius

                          5

                          Integer > 0

                          -

                          Featsel¶

                          +

                          Featsel¶

                          When using the PREDICT toolbox for classification, these settings can be used for feature selection methods. Note that these settings are actually used in the hyperparameter optimization. Hence you can provide @@ -258,107 +767,981 @@

                          Featsel -

                          SelectFeatGroup¶

                          -

                          If the PREDICT feature computation and classification tools are used, -then you can do a gridsearch among the various feature groups for the -optimal combination. If you do not want this, set all fields to a single -value.

                          -

                          Previously, there was a single parameter for the texture features, -selecting all, none or a single group. This is still supported, but not -recommended, and looks as follows:

                          -

                          -
                          -

                          Imputation¶

                          -

                          When using the PREDICT toolbox for classification, these settings are -used for feature imputation.Note that these settings are actually used -in the hyperparameter optimization. Hence you can provide multiple -values per field, of which random samples will be drawn of which finally -the best setting in combination with the other hyperparameters is -selected.

                          -
                          -
                          -

                          Classification¶

                          -

                          When using the PREDICT toolbox for classification, you can specify the -following settings. Almost all of these are used in CASH. Most of the -classifiers are implemented using sklearn; hence descriptions of the -hyperparameters can also be found there.

                          -
                          -
                          -

                          CrossValidation¶

                          -

                          When using the PREDICT toolbox for classification and you specified -using cross validation, specify the following settings.

                          -
                          -
                          -

                          Labels¶

                          -

                          When using the PREDICT toolbox for classification, you have to set the -label used for classification.

                          -

                          This part is really important, as it should match your label file. -Suppose your patientclass.txt file you supplied as source for labels -looks like this:

                          +

                          Description:

                          ---++ - - - + + - - - + + - - - + + - - - + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +

                          Patient

                          Label1

                          Label2

                          Subkey

                          Description

                          patient1

                          1

                          0

                          Variance

                          If True, exclude features which have a variance < 0.01. Based on ` sklearnâ€s VarianceThreshold <https://scikit-learn.org/stable/modules/generated/sklearn.feature_selection.VarianceThreshold.html/>`_.

                          patient2

                          2

                          1

                          GroupwiseSearch

                          Randomly select which feature groups to use. Parameters determined by the SelectFeatGroup config part, see below.

                          patient3

                          1

                          5

                          SelectFromModel

                          Select features by first training a LASSO model. The alpha for the LASSO model is randomly generated. See also sklearnâ€s SelectFromModel.

                          UsePCA

                          If True, Use Principle Component Analysis (PCA) to select features.

                          PCAType

                          Method to select number of components using PCA: Either the number of components that explains 95% of the variance, or use a fixed number of components.95variance

                          StatisticalTestUse

                          If True, use statistical test to select features.

                          StatisticalTestMetric

                          Define the type of statistical test to be used.

                          StatisticalTestThreshold

                          Specify a threshold for the p-value threshold used in the statistical test to select features. The first element defines the lower boundary, the other the upper boundary. Random sampling will occur between the boundaries.

                          ReliefUse

                          If True, use Relief to select features.

                          ReliefNN

                          Min and max of number of nearest neighbors search range in Relief.

                          ReliefSampleSize

                          Min and max of sample size search range in Relief.

                          ReliefDistanceP

                          Min and max of positive distance search range in Relief.

                          ReliefNumFeatures

                          Min and max of number of features that is selected search range in Relief.

                          -

                          You can supply a single label or multiple labels split by commas, for -each of which an estimator will be fit. For example, suppose you simply -want to use Label1 for classification, then set:

                          +

                          Defaults and Options:

                          + +++++ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +

                          Subkey

                          Default

                          Options

                          Variance

                          True

                          Boolean(s)

                          GroupwiseSearch

                          True

                          Boolean(s)

                          SelectFromModel

                          False

                          Boolean(s)

                          UsePCA

                          False

                          Boolean(s)

                          PCAType

                          95variance

                          Inteteger(s), 95variance

                          StatisticalTestUse

                          False

                          Boolean(s)

                          StatisticalTestMetric

                          ttest, Welch, Wilcoxon, MannWhitneyU

                          ttest, Welch, Wilcoxon, MannWhitneyU

                          StatisticalTestThreshold

                          -2, 1.5

                          Two Integers: loc and scale

                          ReliefUse

                          False

                          Boolean(s)

                          ReliefNN

                          2, 4

                          Two Integers: loc and scale

                          ReliefSampleSize

                          1, 1

                          Two Integers: loc and scale

                          ReliefDistanceP

                          1, 3

                          Two Integers: loc and scale

                          ReliefNumFeatures

                          25, 200

                          Two Integers: loc and scale

                          +
                          +
                          +

                          SelectFeatGroup¶

                          +

                          If the PREDICT feature computation and classification tools are used, +then you can do a gridsearch among the various feature groups for the +optimal combination. If you do not want this, set all fields to a single +value.

                          +

                          Previously, there was a single parameter for the texture features, +selecting all, none or a single group. This is still supported, but not +recommended, and looks as follows:

                          +

                          Description:

                          + ++++ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +

                          Subkey

                          Description

                          shape_features

                          If True, use shape features in model.

                          histogram_features

                          If True, use histogram features in model.

                          orientation_features

                          If True, use orientation features in model.

                          texture_Gabor_features

                          If True, use Gabor texture features in model.

                          texture_GLCM_features

                          If True, use GLCM texture features in model.

                          texture_GLCMMS_features

                          If True, use GLCM Multislice texture features in model.

                          texture_GLRLM_features

                          If True, use GLRLM texture features in model.

                          texture_GLSZM_features

                          If True, use GLSZM texture features in model.

                          texture_NGTDM_features

                          If True, use NGTDM texture features in model.

                          texture_LBP_features

                          If True, use LBP texture features in model.

                          patient_features

                          If True, use patient features in model.

                          semantic_features

                          If True, use semantic features in model.

                          coliage_features

                          If True, use coliage features in model.

                          log_features

                          If True, use log features in model.

                          vessel_features

                          If True, use vessel features in model.

                          phase_features

                          If True, use phase features in model.

                          +

                          Defaults and Options:

                          + +++++ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +

                          Subkey

                          Default

                          Options

                          shape_features

                          True, False

                          Boolean(s)

                          histogram_features

                          True, False

                          Boolean(s)

                          orientation_features

                          True, False

                          Boolean(s)

                          texture_Gabor_features

                          False

                          Boolean(s)

                          texture_GLCM_features

                          True, False

                          Boolean(s)

                          texture_GLCMMS_features

                          True, False

                          Boolean(s)

                          texture_GLRLM_features

                          True, False

                          Boolean(s)

                          texture_GLSZM_features

                          True, False

                          Boolean(s)

                          texture_NGTDM_features

                          True, False

                          Boolean(s)

                          texture_LBP_features

                          True, False

                          Boolean(s)

                          patient_features

                          False

                          Boolean(s)

                          semantic_features

                          False

                          Boolean(s)

                          coliage_features

                          False

                          Boolean(s)

                          log_features

                          False

                          Boolean(s)

                          vessel_features

                          False

                          Boolean(s)

                          phase_features

                          False

                          Boolean(s)

                          +
                          +
                          +

                          Imputation¶

                          +

                          When using the PREDICT toolbox for classification, these settings are +used for feature imputation.Note that these settings are actually used +in the hyperparameter optimization. Hence you can provide multiple +values per field, of which random samples will be drawn of which finally +the best setting in combination with the other hyperparameters is +selected.

                          +

                          Description:

                          + ++++ + + + + + + + + + + + + + + + + +

                          Subkey

                          Description

                          use

                          If True, use feature imputation methods to replace NaN values. If False, all NaN features will be set to zero.

                          strategy

                          Method to be used for imputation.

                          n_neighbors

                          When using k-Nearest Neighbors (kNN) for feature imputation, determines the number of neighbors used for imputation. Can be a single integer or a list.

                          +

                          Defaults and Options:

                          + +++++ + + + + + + + + + + + + + + + + + + + + +

                          Subkey

                          Default

                          Options

                          use

                          False

                          Boolean(s)

                          strategy

                          mean, median, most_frequent, constant, knn

                          mean, median, most_frequent, constant, knn

                          n_neighbors

                          5, 5

                          Two Integers: loc and scale

                          +
                          +
                          +

                          Classification¶

                          +

                          When using the PREDICT toolbox for classification, you can specify the +following settings. Almost all of these are used in CASH. Most of the +classifiers are implemented using sklearn; hence descriptions of the +hyperparameters can also be found there.

                          +

                          Description:

                          + ++++ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +

                          Subkey

                          Description

                          fastr

                          Use fastr for the optimization gridsearch (recommended on clusters, default) or if set to False , joblib (recommended for PCs but not on Windows).

                          fastr_plugin

                          Name of execution plugin to be used. Default use the same as the self.fastr_plugin for the WORC object.

                          classifiers

                          Select the estimator(s) to use. Most are implemented using sklearn. For abbreviations, see above.

                          max_iter

                          Maximum number of iterations to use in training an estimator. Only for specific estimators, see sklearn.

                          SVMKernel

                          When using a SVM, specify the kernel type.

                          SVMC

                          Range of the SVM slack parameter. We sample on a uniform log scale: the parameters specify the range of the exponent (a, a + b).

                          SVMdegree

                          Range of the SVM polynomial degree when using a polynomial kernel. We sample on a uniform scale: the parameters specify the range (a, a + b).

                          SVMcoef0

                          Range of SVM homogeneity parameter. We sample on a uniform scale: the parameters specify the range (a, a + b).

                          SVMgamma

                          Range of the SVM gamma parameter. We sample on a uniform log scale: the parameters specify the range of the exponent (a, a + b)

                          RFn_estimators

                          Range of number of trees in a RF. We sample on a uniform scale: the parameters specify the range (a, a + b).

                          RFmin_samples_split

                          Range of minimum number of samples required to split a branch in a RF. We sample on a uniform scale: the parameters specify the range (a, a + b).

                          RFmax_depth

                          Range of maximum depth of a RF. We sample on a uniform scale: the parameters specify the range (a, a + b).

                          LRpenalty

                          Penalty term used in LR.

                          LRC

                          Range of regularization strength in LR. We sample on a uniform scale: the parameters specify the range (a, a + b).

                          LDA_solver

                          Solver used in LDA.

                          LDA_shrinkage

                          Range of the LDA shrinkage parameter. We sample on a uniform log scale: the parameters specify the range of the exponent (a, a + b).

                          QDA_reg_param

                          Range of the QDA regularization parameter. We sample on a uniform log scale: the parameters specify the range of the exponent (a, a + b).

                          ElasticNet_alpha

                          Range of the ElasticNet penalty parameter. We sample on a uniform log scale: the parameters specify the range of the exponent (a, a + b).

                          ElasticNet_l1_ratio

                          Range of l1 ratio in LR. We sample on a uniform scale: the parameters specify the range (a, a + b).

                          SGD_alpha

                          Range of the SGD penalty parameter. We sample on a uniform log scale: the parameters specify the range of the exponent (a, a + b).

                          SGD_l1_ratio

                          Range of l1 ratio in SGD. We sample on a uniform scale: the parameters specify the range (a, a + b).

                          SGD_loss

                          hinge, Loss function of SG

                          SGD_penalty

                          Penalty term in SGD.

                          CNB_alpha

                          Regularization strenght in ComplementNB. We sample on a uniform scale: the parameters specify the range (a, a + b)

                          +

                          Defaults and Options:

                          + +++++ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +

                          Subkey

                          Default

                          Options

                          fastr

                          True

                          True, False

                          fastr_plugin

                          LinearExecution

                          Any fastr execution plugin .

                          classifiers

                          SVM

                          SVM , SVR, SGD, SGDR, RF, LDA, QDA, ComplementND, GaussianNB, LR, RFR, Lasso, ElasticNet. All are estimators from sklearn

                          max_iter

                          100000

                          Integer

                          SVMKernel

                          poly

                          poly, linear, rbf

                          SVMC

                          0, 6

                          Two Integers: loc and scale

                          SVMdegree

                          1, 6

                          Two Integers: loc and scale

                          SVMcoef0

                          0, 1

                          Two Integers: loc and scale

                          SVMgamma

                          -5, 5

                          Two Integers: loc and scale

                          RFn_estimators

                          10, 90

                          Two Integers: loc and scale

                          RFmin_samples_split

                          2, 3

                          Two Integers: loc and scale

                          RFmax_depth

                          5, 5

                          Two Integers: loc and scale

                          LRpenalty

                          l2, l1

                          none, l2, l1

                          LRC

                          0.01, 1.0

                          Two Integers: loc and scale

                          LDA_solver

                          svd, lsqr, eigen

                          svd, lsqr, eigen

                          LDA_shrinkage

                          -5, 5

                          Two Integers: loc and scale

                          QDA_reg_param

                          -5, 5

                          Two Integers: loc and scale

                          ElasticNet_alpha

                          -5, 5

                          Two Integers: loc and scale

                          ElasticNet_l1_ratio

                          0, 1

                          Two Integers: loc and scale

                          SGD_alpha

                          -5, 5

                          Two Integers: loc and scale

                          SGD_l1_ratio

                          0, 1

                          Two Integers: loc and scale

                          SGD_loss

                          hinge, squared_hinge, modified_huber

                          hinge, squared_hinge, modified_huber

                          SGD_penalty

                          none, l2, l1

                          none, l2, l1

                          CNB_alpha

                          0, 1

                          Two Integers: loc and scale

                          +
                          +
                          +

                          CrossValidation¶

                          +

                          When using the PREDICT toolbox for classification and you specified +using cross validation, specify the following settings.

                          +

                          Description:

                          + ++++ + + + + + + + + + + + + + +

                          Subkey

                          Description

                          N_iterations

                          Number of times the data is split in training and test in the outer cross-validation.

                          test_size

                          The percentage of data to be used for testing.

                          +

                          Defaults and Options:

                          + +++++ + + + + + + + + + + + + + + + + +

                          Subkey

                          Default

                          Options

                          N_iterations

                          100

                          Integer

                          test_size

                          0.2

                          Float

                          +
                          +
                          +

                          Labels¶

                          +

                          When using the PREDICT toolbox for classification, you have to set the +label used for classification.

                          +

                          This part is really important, as it should match your label file. +Suppose your patientclass.txt file you supplied as source for labels +looks like this:

                          + +++++ + + + + + + + + + + + + + + + + + + + + +

                          Patient

                          Label1

                          Label2

                          patient1

                          1

                          0

                          patient2

                          2

                          1

                          patient3

                          1

                          5

                          +

                          You can supply a single label or multiple labels split by commas, for +each of which an estimator will be fit. For example, suppose you simply +want to use Label1 for classification, then set:

                          config['Labels']['label_names'] = 'Label1'
                           

                          If you want to first train a classifier on Label1 and then Label2, set: config[Genetics][label_names] = Label1, Label2

                          +

                          Description:

                          + ++++ + + + + + + + + + + + + + + + + + + + +

                          Subkey

                          Description

                          label_names

                          The labels used from your label file for classification.

                          modus

                          Determine whether multilabel or singlelabel classification or regression will be performed.

                          url

                          WIP

                          projectID

                          WIP

                          +

                          Defaults and Options:

                          + +++++ + + + + + + + + + + + + + + + + + + + + + + + + +

                          Subkey

                          Default

                          Options

                          label_names

                          Label1, Label2

                          String(s)

                          modus

                          singlelabel

                          singlelabel, multilabel

                          url

                          WIP

                          Not Supported Yet

                          projectID

                          WIP

                          Not Supported Yet

                          -

                          Hyperoptimization¶

                          +

                          Hyperoptimization¶

                          When using the PREDICT toolbox for classification, you have to supply your hyperparameter optimization procedure here.

                          +

                          Description:

                          + ++++ + + + + + + + + + + + + + + + + + + + + + + + + + + + + +

                          Subkey

                          Description

                          scoring_method

                          Specify the optimization metric for your hyperparameter search.

                          test_size

                          Size of test set in the hyperoptimization cross validation, given as a percentage of the whole dataset.

                          n_splits

                          Number of iterations in train-validation cross-validation used for model optimization.

                          N_iterations

                          Number of iterations used in the hyperparameter optimization. This corresponds to the number of samples drawn from the parameter grid.

                          n_jobspercore

                          Number of jobs assigned to a single core. Only used if fastr is set to true in the classfication.

                          maxlen

                          Number of estimators for which the fitted outcomes and parameters are saved. Increasing this number will increase the memory usage.

                          ranking_score

                          Score used for ranking the performance of the evaluated workflows.

                          +

                          Defaults and Options:

                          + +++++ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +

                          Subkey

                          Default

                          Options

                          scoring_method

                          f1_weighted

                          Any sklearn metric

                          test_size

                          0.15

                          Float

                          n_splits

                          5

                          Integer

                          N_iterations

                          10000

                          Integer

                          n_jobspercore

                          2000

                          Integer

                          maxlen

                          100

                          Integer

                          ranking_score

                          test_score

                          String

                          -

                          FeatureScaling¶

                          +

                          FeatureScaling¶

                          Determines which method is applied to scale each feature.

                          +

                          Description:

                          + ++++ + + + + + + + + + + + + + +

                          Subkey

                          Description

                          scale_features

                          Determine whether to use feature scaling is.

                          scaling_method

                          Determine the scaling method.

                          +

                          Defaults and Options:

                          + +++++ + + + + + + + + + + + + + + + + +

                          Subkey

                          Default

                          Options

                          scale_features

                          True

                          Boolean(s)

                          scaling_method

                          z_score

                          z_score, minmax

                          -

                          SampleProcessing¶

                          +

                          SampleProcessing¶

                          Before performing the hyperoptimization, you can use SMOTE: Synthetic Minority Over-sampling Technique to oversample your data.

                          +

                          Description:

                          + ++++ + + + + + + + + + + + + + + + + + + + +

                          Subkey

                          Description

                          SMOTE

                          Determine whether to use SMOTE oversampling, see also ` imbalanced learn <https://imbalanced-learn.readthedocs.io/en/stable/generated/imblearn.over_sampling.SMOTE.html/>`_.

                          SMOTE_ratio

                          Determine the ratio of oversampling. If 1, the minority class will be oversampled to the same size as the majority class. We sample on a uniform scale: the parameters specify the range (a, a + b).

                          SMOTE_neighbors

                          Number of neighbors used in SMOTE. This should be much smaller than the number of objects/patients you supply. We sample on a uniform scale: the parameters specify the range (a, a + b).

                          Oversampling

                          Determine whether to random oversampling.

                          +

                          Defaults and Options:

                          + +++++ + + + + + + + + + + + + + + + + + + + + + + + + +

                          Subkey

                          Default

                          Options

                          SMOTE

                          True

                          Boolean(s)

                          SMOTE_ratio

                          1, 0

                          Two Integers: loc and scale

                          SMOTE_neighbors

                          5, 15

                          Two Integers: loc and scale

                          Oversampling

                          False

                          Boolean(s)

                          -

                          Ensemble¶

                          +

                          Ensemble¶

                          WORC supports ensembling of workflows. This is not a default approach in radiomics, hence the default is to not use it and select only the best performing workflow.

                          +

                          Description:

                          + ++++ + + + + + + + + + + +

                          Subkey

                          Description

                          Use

                          Determine whether to use ensembling or not. Provide an integer to state how many estimators to include: 1 equals no ensembling.

                          +

                          Defaults and Options:

                          + +++++ + + + + + + + + + + + + +

                          Subkey

                          Default

                          Options

                          Use

                          1

                          Integer

                          +
                          +
                          +

                          Bootstrap¶

                          +

                          Besides cross validation, WORC supports bootstrapping on the test set for performance evaluation.

                          +

                          Description:

                          + ++++ + + + + + + + + + + + + + +

                          Subkey

                          Description

                          Use

                          Determine whether to use bootstrapping or not.

                          N_iterations

                          Number of iterations to use for bootstrapping.

                          +

                          Defaults and Options:

                          + +++++ + + + + + + + + + + + + + + + + +

                          Subkey

                          Default

                          Options

                          Use

                          False

                          Boolean

                          N_iterations

                          1000

                          Integer

                          -
                          -

                          FASTR_bugs¶

                          -

                          Currently, when using XNAT as a source, FASTR can only retrieve DICOM -directories. We made a workaround for this for the images and -segmentations, but this only works if all your files have the same name -and extension. These are provided in this configuration part.

                          diff --git a/WORC/doc/_build/html/static/file_description.html b/WORC/doc/_build/html/static/file_description.html index 72d355d5..accb1f6a 100644 --- a/WORC/doc/_build/html/static/file_description.html +++ b/WORC/doc/_build/html/static/file_description.html @@ -8,7 +8,7 @@ - Resource File Formats — WORC 3.0.0 documentation + Resource File Formats — WORC 3.1.0 documentation @@ -61,7 +61,7 @@
                          - 3.0.0 + 3.1.0
                          diff --git a/WORC/doc/_build/html/static/introduction.html b/WORC/doc/_build/html/static/introduction.html index 235d1752..258e5897 100644 --- a/WORC/doc/_build/html/static/introduction.html +++ b/WORC/doc/_build/html/static/introduction.html @@ -8,7 +8,7 @@ - Introduction — WORC 3.0.0 documentation + Introduction — WORC 3.1.0 documentation @@ -61,7 +61,7 @@
                          - 3.0.0 + 3.1.0
                          diff --git a/WORC/doc/_build/html/static/quick_start.html b/WORC/doc/_build/html/static/quick_start.html index 8ff71f11..5f64c191 100644 --- a/WORC/doc/_build/html/static/quick_start.html +++ b/WORC/doc/_build/html/static/quick_start.html @@ -8,7 +8,7 @@ - Quick start guide — WORC 3.0.0 documentation + Quick start guide — WORC 3.1.0 documentation @@ -61,7 +61,7 @@
                          - 3.0.0 + 3.1.0
                          @@ -91,10 +91,18 @@
                        • Installation +
                        • +
                        • Tutorials
                        • +
                        • Hello World
                        • -
                        • Configuration
                        • -
                        • Tutorial
                      • User Manual
                      • @@ -174,6 +182,10 @@

                        Quick start guide

                        Installation¶

                        You can install WORC either using pip, or from the source code.

                        +
                        +

                        Note

                        +

                        The version of PyRadiomics which WORC currently uses requires numpy to be installed beforehand. Make sure you do so, e.g. pip install numpy.

                        +

                        Installing via pip¶

                        You can simply install WORC using pip:

                        @@ -206,33 +218,235 @@

                        Installing from source code

                        Note

                        -

                        You might want to consider installing WORC in a virtualenv

                        +

                        You might want to consider installing WORC in a +virtualenv

                        +

                        +
                        +

                        Windows installation¶

                        +

                        On Windows, we strongly recommend to install python through the +Anaconda distribution.

                        +

                        Regardless of your installation, you will need Microsoft Visual Studio: the Community +edition can be downloaded and installed for free.

                        +

                        If you still get an error similar to error: Microsoft Visual C++ 14.0 is required. Get it with +Microsoft Visual C++ Build Tools +, please follow the respective link and install the requirements.

                        -
                        -

                        Configuration¶

                        -

                        WORC has defaults for all settings so it can be run out of the box to test the examples. -However, you may want to alter the fastr configuration to your system settings, e.g. -to locate your input and output folders and how much you want to parallelize the execution.

                        -

                        Fastr will search for a config file named config.py in the $FASTRHOME directory -(which defaults to ~/.fastr/ if it is not set). So if $FASTRHOME is set the ~/.fastr/ -will be ignored. Additionally, .py files from the $FASTRHOME/config.d folder will be parsed -as well. You will see that upon installation, WORC has already put a WORC_config.py file in the -config.d folder.

                        -

                        For a sample configuration file and a complete overview of the options in config.py see -the Config file section.

                        -
                        -
                        -

                        Tutorial¶

                        -

                        To start out using WORC, we recommend you to follow the tutorial located in the -[WORCTutorial Github](https://github.com/MStarmans91/WORCTutorial). Besides some more advanced tutorials, -the main tutorial can be found in the WORCTutorial.ipynb Jupyter notebook. Instructions on how -to use the notebook can be found in the Github.

                        +
                        +

                        Tutorials¶

                        +

                        To start out using WORC, we recommend you to follow the tutorials located in the +WORCTutorial Github. This repository +contains tutorials for an introduction to WORC, as well as more advanced workflows.

                        If you run into any issue, you can first debug your network using the fastr trace tool. If you’re stuck, feel free to post an issue on the WORC Github.

                        +
                        +

                        Hello World¶

                        +

                        Below is the same script as found in the SimpleWORC tutorial found in the WORCTutorial Github.

                        +
                        +

                        Import packages¶

                        +

                        First, import WORC and some additional python packages.

                        +
                        from WORC import SimpleWORC
                        +import os
                        +
                        +# These packages are only used in analysing the results
                        +import pandas as pd
                        +import json
                        +import fastr
                        +import glob
                        +
                        +# If you don't want to use your own data, we use the following example set,
                        +# see also the next code block in this example.
                        +from WORC.exampledata.datadownloader import download_HeadAndNeck
                        +
                        +# Define the folder this script is in, so we can easily find the example data
                        +script_path = os.path.dirname(os.path.abspath(__file__))
                        +
                        +
                        +
                        +
                        +

                        Input¶

                        +

                        The minimal inputs to WORC are:

                        +
                        +
                          +
                        1. Images

                        2. +
                        3. Segmentations

                        4. +
                        5. Labels

                        6. +
                        +
                        +

                        In SimpleWORC, we assume you have a folder “datadirâ€, in which there is a +folder for each patient, where in each folder there is a image.nii.gz and a mask.nii.gz:

                        +
                        +
                          +
                        • Datadir

                          +
                            +
                          • Patient_001

                            +
                            +
                              +
                            • image.nii.gz

                            • +
                            • mask.nii.gz

                            • +
                            +
                            +
                          • +
                          • Patient_002

                            +
                            +
                              +
                            • image.nii.gz

                            • +
                            • mask.nii.gz

                            • +
                            +
                            +
                          • +
                          • …

                          • +
                          +
                        • +
                        +
                        +

                        In the example, we will use open source data from the online +BMIA XNAT platform +This dataset consists of CT scans of patients with Head and Neck tumors. We will download +a subset of 20 patients in this folder. You can change this settings if you like.

                        +
                        nsubjects = 20  # use "all" to download all patients
                        +data_path = os.path.join(script_path, 'Data')
                        +download_HeadAndNeck(datafolder=data_path, nsubjects=nsubjects)
                        +
                        +
                        +
                        +

                        Note

                        +

                        You can skip this code block if you use your own data.

                        +
                        +

                        Identify our data structure: change the fields below accordingly if you use your own dataset.

                        +
                        imagedatadir = os.path.join(data_path, 'stwstrategyhn1')
                        +image_file_name = 'image.nii.gz'
                        +segmentation_file_name = 'mask.nii.gz'
                        +
                        +# File in which the labels (i.e. outcome you want to predict) is stated
                        +# Again, change this accordingly if you use your own data.
                        +label_file = os.path.join(data_path, 'Examplefiles', 'pinfo_HN.csv')
                        +
                        +# Name of the label you want to predict
                        +label_name = 'imaginary_label_1'
                        +
                        +# Determine whether we want to do a coarse quick experiment, or a full lengthy
                        +# one. Again, change this accordingly if you use your own data.
                        +coarse = True
                        +
                        +# Give your experiment a name
                        +experiment_name = 'Example_STWStrategyHN4'
                        +
                        +# Instead of the default tempdir, let's but the temporary output in a subfolder
                        +# in the same folder as this script
                        +tmpdir = os.path.join(script_path, 'WORC_' + experiment_name)
                        +
                        +
                        +
                        +
                        +

                        The actual experiment¶

                        +

                        After defining the inputs, the following code can be used to run your first experiment.

                        +
                        # Create a Simple WORC object
                        +network = SimpleWORC(experiment_name)
                        +
                        +# Set the input data according to the variables we defined earlier
                        +network.images_from_this_directory(imagedatadir,
                        +                             image_file_name=image_file_name)
                        +network.segmentations_from_this_directory(imagedatadir,
                        +                                    segmentation_file_name=segmentation_file_name)
                        +network.labels_from_this_file(label_file)
                        +network.predict_labels([label_name])
                        +
                        +# Use the standard workflow for binary classification
                        +network.binary_classification(coarse=coarse)
                        +
                        +# Set the temporary directory
                        +experiment.set_tmpdir(tmpdir)
                        +
                        +# Run the experiment!
                        +network.execute()
                        +
                        +
                        +
                        +

                        Note

                        +

                        Precomputed features can be used instead of images and masks by instead using network.features_from_this_directory() in a similar fashion.

                        +
                        +
                        +
                        +

                        Analysis of the results¶

                        +

                        There are two main outputs: the features for each patient/object, and the overall +performance. These are stored as .hdf5 and .json files, respectively. By +default, they are saved in the so-called “fastr output mountâ€, in a subfolder +named after your experiment name.

                        +
                        # Locate output folder
                        +outputfolder = fastr.config.mounts['output']
                        +experiment_folder = os.path.join(outputfolder, 'WORC_' + experiment_name)
                        +
                        +print(f"Your output is stored in {experiment_folder}.")
                        +
                        +# Read the features for the first patient
                        +# NOTE: we use the glob package for scanning a folder to find specific files
                        +feature_files = glob.glob(os.path.join(experiment_folder,
                        +                                       'Features',
                        +                                       'features_*.hdf5'))
                        +featurefile_p1 = feature_files[0]
                        +features_p1 = pd.read_hdf(featurefile_p1)
                        +
                        +# Read the overall peformance
                        +performance_file = os.path.join(experiment_folder, 'performance_all_0.json')
                        +with open(performance_file, 'r') as fp:
                        +    performance = json.load(fp)
                        +
                        +# Print the feature values and names
                        +print("Feature values:")
                        +for v, l in zip(features_p1.feature_values, features_p1.feature_labels):
                        +    print(f"\t {l} : {v}.")
                        +
                        +# Print the output performance
                        +print("\n Performance:")
                        +stats = performance['Statistics']
                        +del stats['Percentages']  # Omitted for brevity
                        +for k, v in stats.items():
                        +    print(f"\t {k} {v}.")
                        +
                        +
                        +
                        +

                        Note

                        +

                        the performance is probably horrible, which is expected as we ran the experiment on coarse settings. These settings are recommended to only use for testing: see also below.

                        +
                        +
                        +
                        +

                        Tips and Tricks¶

                        +

                        For tips and tricks on running a full experiment instead of this simple +example, adding more evaluation options, debugging a crashed network etcetera, +please go to usermanual-chapter or follow the intermediate +or advanced tutorials on WORCTutorial Github.

                        +

                        Some things we would advice to always do:

                        +
                          +
                        • Run actual experiments on the full settings (coarse=False):

                        • +
                        +
                        coarse = False
                        +network.binary_classification(coarse=coarse)
                        +
                        +
                        +
                        +

                        Note

                        +

                        This will result in more computation time. We therefore recommmend +to run this script on either a cluster or high performance PC. If so, +you may change the execution to use multiple cores to speed up computation +just before before experiment.execute():

                        +
                        +
                        experiment.set_multicore_execution()
                        +
                        +
                        +
                        +
                        +
                          +
                        • Add extensive evaluation: network.add_evaluation() before network.execute():

                        • +
                        +
                        network.add_evaluation()
                        +
                        +
                        +
                        +
                        diff --git a/WORC/doc/_build/html/static/user_manual.html b/WORC/doc/_build/html/static/user_manual.html index 1bedc4e6..8df028f3 100644 --- a/WORC/doc/_build/html/static/user_manual.html +++ b/WORC/doc/_build/html/static/user_manual.html @@ -8,7 +8,7 @@ - User Manual — WORC 3.0.0 documentation + User Manual — WORC 3.1.0 documentation @@ -61,7 +61,7 @@
                        - 3.0.0 + 3.1.0
                        @@ -89,21 +89,25 @@
                      • Introduction
                      • Quick start guide
                      • User Manual
                      • +configuration, as it is listed in a separate page, see the config file section.

                        -

                        Attributes: Sources¶

                        +

                        Attributes: Sources¶

                        There are numerous WORC attributes which serve as source nodes for the FASTR network. These are:

                          @@ -254,31 +257,8 @@

                          Attributes: Sources -

                          Attributes: Settings¶

                          -

                          There are several attributes in WORC which define how your pipeline is -executed:

                          -
                            -
                          • fastr_plugin

                          • -
                          • fastr_tmpdir

                          • -
                          • Tools: additional workflows are stored here. Currently only includes -a pipeline for image registration without any Radiomics.

                          • -
                          • CopyMetadata: Whether to automatically copy the metadata info -(e.g. direction of cosines) from the images to the segmentations -before applying transformix.

                          • -
                          -

                          An explanation of the FASTR settings is given below.

                          -

                        -
                        -

                        Attributes: Functions¶

                        -

                        The WORC.configs() attribute contains the configparser files, which you -can easily edit. The WORC.set() function saves these objects in a -temporary folder and converts the filename into as FASTR source, which -is then put in the WORC.fastrconfigs() objects. Hence you do not need to -edit the fastrconfigs object manually.

                        -

                        Images and segmentations¶

                        +

                        Images and segmentations¶

                        The minimal input for a Radiomics pipeline consists of either images (plus a segmentation if you have not implemented an automatic segmentation tool) or features plus a label file (and a configuration, @@ -288,7 +268,7 @@

                        Images and segmentations -

                        Semantics¶

                        +

                        Semantics¶

                        Semantic features are used in the PREDICT CalcFeatures tool. You can supply these as a .csv listing your features per patient. The first column should always be named Patient and contain the Patient ID. The @@ -330,16 +310,15 @@

                        Semantics -

                        Labels¶

                        +

                        Labels¶

                        The labels are used in classification. For PREDICT, these should be supplied as a .txt file. Similar to the semantics, the first column should head Patient and contain the patient ID. The next columns can contain things you want to predict. Hence the format is similar to the semantics file.

                        -
                        -

                        Masks¶

                        +

                        Masks¶

                        WORC contains a segmentation preprocessing tool, called segmentix. This tool is still under development. The idea is that you can manipulate your segmentation, e.g. using dilation, then use a mask to make sure it @@ -347,14 +326,14 @@

                        Masks radius around your ROI and mask it.

                        -

                        Features¶

                        +

                        Features¶

                        If you already computed your features, e.g. from a previous run, you can directly supply the features instead of the images and segmentations and skip the feature computation step. These should be stored in .hdf5 files matching the PREDICT CalcFeatures format.

                        -

                        Metadata¶

                        +

                        Metadata¶

                        This source can be used if you want to use tags from the DICOM header as features, e.g. patient age and sex. In this case, this source should contain a single DICOM per patient from which the tags that are read. @@ -362,7 +341,7 @@

                        Metadata -

                        Elastix_Para¶

                        +

                        Elastix_Para¶

                        If you have multiple images for each patient, e.g. T1 and T2, but only a single segmentation, you can use image registration to align and transform the segmentation to the other modality. This is done in WORC @@ -373,8 +352,32 @@

                        Elastix_Para +

                        Attributes: Settings¶

                        +

                        There are several attributes in WORC which define how your pipeline is +executed:

                        +
                          +
                        • fastr_plugin

                        • +
                        • fastr_tmpdir

                        • +
                        • Tools: additional workflows are stored here. Currently only includes +a pipeline for image registration without any Radiomics.

                        • +
                        • CopyMetadata: Whether to automatically copy the metadata info +(e.g. direction of cosines) from the images to the segmentations +before applying transformix.

                        • +
                        +

                        An explanation of the FASTR settings is given below.

                        +

                        +
                        +

                        Attributes: Functions¶

                        +

                        The WORC.configs() attribute contains the configparser files, which you +can easily edit. The WORC.set() function saves these objects in a +temporary folder and converts the filename into as FASTR source, which +is then put in the WORC.fastrconfigs() objects. Hence you do not need to +edit the fastrconfigs object manually.

                        +
                        -

                        FASTR settings¶

                        +

                        FASTR settings¶

                        There are two WORC attributes which contain settings on running FASTR. In WORC.fastr_plugin, you can specify which Execution Plugin should be used: see also @@ -383,7 +386,7 @@

                        FASTR settings -

                        Construction and execution commands¶

                        +

                        Construction and execution commands¶

                        After supplying your sources, you need to build the FASTR network. This can be done through the WORC.build() command. Depending on your sources, several nodes will be added and linked. This creates the WORC.network() @@ -398,6 +401,98 @@

                        Construction and execution commands +

                        Evaluation of your network¶

                        +

                        In WORC, there are two options for testing your fitted models:

                        +
                          +
                        1. Single dataset: cross-validation (currently only random-split)

                        2. +
                        3. Separate train and test dataset: bootstrapping on test dataset

                        4. +
                        +

                        Within these evaluation settings, the following performance evaluation methods are used:

                        +
                          +
                        1. Confidence intervals on several metrics:

                          +
                          +

                          For classification:

                          +
                            +
                          1. Area under the curve (AUC) of the receiver operating characteristic (ROC) curve. In a multiclass setting, weuse the multiclass AUC from the TADPOLE Challenge.

                          2. +
                          3. Accuracy.

                          4. +
                          5. Balanced classification accuracy as defined by the TADPOLE Challenge.

                          6. +
                          7. F1-score

                          8. +
                          9. Sensitivity, aka recall or true positive rate

                          10. +
                          11. Specificity, aka true negative rate

                          12. +
                          13. Negative predictive value (NPV)

                          14. +
                          15. Precision, aka Positive predictive value (PPV)

                          16. +
                          +

                          For regression:

                          +
                            +
                          1. R2-score

                          2. +
                          3. Mean Squared Error (MSE)

                          4. +
                          5. Intraclass Correlation Coefficient (ICC)

                          6. +
                          7. Pearson correlation coefficient and p-value

                          8. +
                          9. Spearmand correlation coefficient and p-value

                          10. +
                          +

                          For survival, in addition to the regression scores: +a) Concordance index +b) Cox regression coefficient and p-value

                          +

                          In cross-validation, by default, 95% confidence intervals for the mean performance measures are constructed using +the corrected resampled t-test base on all cross-validation iterations, thereby taking into account that the samples +in the cross-validation splits are not statistically independent. See als +Nadeau C, Bengio Y. Inference for the generalization error. In Advances in Neural Information Processing Systems, 2000; 307–313.

                          +

                          In bootstrapping, 95% confidence intervals are created using the ‘’standard’’ method according to a normal distribution: see Table 6, method 1 in Efron B., Tibshirani R. Bootstrap Methods for Standard Errors, +Confidence Intervals, and Other Measures of Statistical Accuracy, Statistical Science Vol.1, No,1, 54-77, 1986.

                          +
                          +
                        2. +
                        3. ROC curve with 95% confidence intervals using the fixed-width bands method, see Macskassy S. A., Provost F., Rosset S. ROC Confidence Bands: An Empirical Evaluation. In: Proceedings of the 22nd international conference on Machine learning. 2005.

                        4. +
                        5. Univariate statistical testing of the features using:

                          +
                          +
                            +
                          1. A student t-test

                          2. +
                          3. A Welch test

                          4. +
                          5. A Wilcoxon test

                          6. +
                          7. A Mann-Whitney U test

                          8. +
                          +

                          The uncorrected p-values for all these tests are reported in a single excel sheet. Pick the right test and significance +level based on your assumptions. Normally, we make use of the Mann-Whitney U test, as our features do not have to be normally +distributed, it’s nonparametric, and assumes independent samples.

                          +
                          +
                        6. +
                        7. Ranking patients from typical to atypical as determined by the model, based on either:

                          +
                          +

                          a) The percentage of times a patient was classified correctly when occuring in the test set. Patients always correctly classified +can be seen as typical examples; patients always classified incorrectly as atypical. +b) The mean posterior of the patient when occuring in the test set.

                          +

                          These measures can only be used in classification. Besides an Excel with the rankings, snapshots of the middle slice +of the image + segmentation are saved with the ground truth label and the percentage/posterior in the filename. In +this way, one can scroll through the patients from typical to atypical to distinguish a pattern.

                          +
                          +
                        8. +
                        9. A barchart of how often certain features groups were selected in the optimal methods. Only useful when using +groupwise feature selection.

                        10. +
                        +

                        By default, only the first evaluation method, e.g. metric computation, is used. The other methods can simply be added +to WORC by using the add_evaluation() function, either directly in WORC or through the facade:

                        +
                        import WORC
                        +network = WORC.WORC('somename')
                        +label_type = 'name_of_label_predicted_for_evaluation'
                        +...
                        +network.add_evaluation(label_type)
                        +
                        +
                        +
                        import WORC
                        +from WORC import IntermediateFacade
                        +I = IntermediateFacade('somename')
                        +...
                        +I.add_evaluation()
                        +
                        +
                        +

                        +
                        +

                        Debugging¶

                        +

                        As WORC is based on fastr, debugging is similar to debugging a fastr pipeline: see therefore also +the fastr debugging guidelines.

                        +

                        If you run into any issue, please create an issue on the WORC Github.

                        +
                        diff --git a/WORC/doc/autogen/WORC.classification.rst b/WORC/doc/autogen/WORC.classification.rst index 3e0ac848..7a49a362 100644 --- a/WORC/doc/autogen/WORC.classification.rst +++ b/WORC/doc/autogen/WORC.classification.rst @@ -1,6 +1,15 @@ classification Package ====================== +:mod:`classification` Package +----------------------------- + +.. automodule:: WORC.classification + :members: + :undoc-members: + :show-inheritance: + :special-members: + :mod:`AdvancedSampler` Module ----------------------------- @@ -10,6 +19,15 @@ classification Package :show-inheritance: :special-members: +:mod:`ObjectSampler` Module +--------------------------- + +.. automodule:: WORC.classification.ObjectSampler + :members: + :undoc-members: + :show-inheritance: + :special-members: + :mod:`RankedSVM` Module ----------------------- @@ -37,6 +55,15 @@ classification Package :show-inheritance: :special-members: +:mod:`createfixedsplits` Module +------------------------------- + +.. automodule:: WORC.classification.createfixedsplits + :members: + :undoc-members: + :show-inheritance: + :special-members: + :mod:`crossval` Module ---------------------- @@ -82,6 +109,15 @@ classification Package :show-inheritance: :special-members: +:mod:`regressors` Module +------------------------ + +.. automodule:: WORC.classification.regressors + :members: + :undoc-members: + :show-inheritance: + :special-members: + :mod:`trainclassifier` Module ----------------------------- diff --git a/WORC/doc/autogen/WORC.config.rst b/WORC/doc/autogen/WORC.config.rst new file mode 100644 index 00000000..c77d23f6 --- /dev/null +++ b/WORC/doc/autogen/WORC.config.rst @@ -0,0 +1,19 @@ +================= =================================================== +Key Reference +================= =================================================== +Bootstrap :ref:`Bootstrap ` +Classification :ref:`Classification ` +CrossValidation :ref:`CrossValidation ` +Ensemble :ref:`Ensemble ` +Featsel :ref:`Featsel ` +FeatureScaling :ref:`FeatureScaling ` +General :ref:`General ` +HyperOptimization :ref:`HyperOptimization ` +ImageFeatures :ref:`ImageFeatures ` +Imputation :ref:`Imputation ` +Labels :ref:`Labels ` +Normalize :ref:`Normalize ` +SampleProcessing :ref:`SampleProcessing ` +Segmentix :ref:`Segmentix ` +SelectFeatGroup :ref:`SelectFeatGroup ` +================= =================================================== \ No newline at end of file diff --git a/WORC/doc/autogen/WORC.detectors.rst b/WORC/doc/autogen/WORC.detectors.rst new file mode 100644 index 00000000..77c54f1b --- /dev/null +++ b/WORC/doc/autogen/WORC.detectors.rst @@ -0,0 +1,12 @@ +detectors Package +================= + +:mod:`detectors` Module +----------------------- + +.. automodule:: WORC.detectors.detectors + :members: + :undoc-members: + :show-inheritance: + :special-members: + diff --git a/WORC/doc/autogen/WORC.exampledata.rst b/WORC/doc/autogen/WORC.exampledata.rst new file mode 100644 index 00000000..edd6d5b0 --- /dev/null +++ b/WORC/doc/autogen/WORC.exampledata.rst @@ -0,0 +1,12 @@ +exampledata Package +=================== + +:mod:`datadownloader` Module +---------------------------- + +.. automodule:: WORC.exampledata.datadownloader + :members: + :undoc-members: + :show-inheritance: + :special-members: + diff --git a/WORC/doc/autogen/WORC.facade.rst b/WORC/doc/autogen/WORC.facade.rst new file mode 100644 index 00000000..fec9f4e2 --- /dev/null +++ b/WORC/doc/autogen/WORC.facade.rst @@ -0,0 +1,19 @@ +facade Package +============== + +:mod:`facade` Package +--------------------- + +.. automodule:: WORC.facade + :members: + :undoc-members: + :show-inheritance: + :special-members: + +Subpackages +----------- + +.. toctree:: + + WORC.facade.simpleworc + diff --git a/WORC/doc/autogen/WORC.facade.simpleworc.rst b/WORC/doc/autogen/WORC.facade.simpleworc.rst new file mode 100644 index 00000000..b52d6811 --- /dev/null +++ b/WORC/doc/autogen/WORC.facade.simpleworc.rst @@ -0,0 +1,30 @@ +simpleworc Package +================== + +:mod:`configbuilder` Module +--------------------------- + +.. automodule:: WORC.facade.simpleworc.configbuilder + :members: + :undoc-members: + :show-inheritance: + :special-members: + +:mod:`exceptions` Module +------------------------ + +.. automodule:: WORC.facade.simpleworc.exceptions + :members: + :undoc-members: + :show-inheritance: + :special-members: + +:mod:`simpleworc` Module +------------------------ + +.. automodule:: WORC.facade.simpleworc.simpleworc + :members: + :undoc-members: + :show-inheritance: + :special-members: + diff --git a/WORC/doc/autogen/WORC.featureprocessing.rst b/WORC/doc/autogen/WORC.featureprocessing.rst index 29ce3960..eb57f40b 100644 --- a/WORC/doc/autogen/WORC.featureprocessing.rst +++ b/WORC/doc/autogen/WORC.featureprocessing.rst @@ -10,6 +10,15 @@ featureprocessing Package :show-inheritance: :special-members: +:mod:`Decomposition` Module +--------------------------- + +.. automodule:: WORC.featureprocessing.Decomposition + :members: + :undoc-members: + :show-inheritance: + :special-members: + :mod:`Imputer` Module --------------------- diff --git a/WORC/doc/autogen/WORC.plotting.rst b/WORC/doc/autogen/WORC.plotting.rst index 8cec5656..1f866572 100644 --- a/WORC/doc/autogen/WORC.plotting.rst +++ b/WORC/doc/autogen/WORC.plotting.rst @@ -1,6 +1,15 @@ plotting Package ================ +:mod:`plotting` Package +----------------------- + +.. automodule:: WORC.plotting + :members: + :undoc-members: + :show-inheritance: + :special-members: + :mod:`compute_CI` Module ------------------------ @@ -37,15 +46,6 @@ plotting Package :show-inheritance: :special-members: -:mod:`plot_SVR` Module ----------------------- - -.. automodule:: WORC.plotting.plot_SVR - :members: - :undoc-members: - :show-inheritance: - :special-members: - :mod:`plot_barchart` Module --------------------------- diff --git a/WORC/doc/autogen/WORC.resources.fastr_tools.rst b/WORC/doc/autogen/WORC.resources.fastr_tools.rst new file mode 100644 index 00000000..b42ed940 --- /dev/null +++ b/WORC/doc/autogen/WORC.resources.fastr_tools.rst @@ -0,0 +1,12 @@ +fastr_tools Package +=================== + +:mod:`fastr_tools` Package +-------------------------- + +.. automodule:: WORC.resources.fastr_tools + :members: + :undoc-members: + :show-inheritance: + :special-members: + diff --git a/WORC/doc/autogen/WORC.resources.rst b/WORC/doc/autogen/WORC.resources.rst new file mode 100644 index 00000000..c46f113f --- /dev/null +++ b/WORC/doc/autogen/WORC.resources.rst @@ -0,0 +1,11 @@ +resources Package +================= + +Subpackages +----------- + +.. toctree:: + + WORC.resources.fastr_tests + WORC.resources.fastr_tools + diff --git a/WORC/doc/autogen/WORC.rst b/WORC/doc/autogen/WORC.rst index 7a6d477b..ae8eff11 100644 --- a/WORC/doc/autogen/WORC.rst +++ b/WORC/doc/autogen/WORC.rst @@ -35,8 +35,12 @@ Subpackages WORC.IOparser WORC.classification + WORC.detectors + WORC.exampledata + WORC.facade WORC.featureprocessing WORC.plotting WORC.processing + WORC.resources WORC.tools diff --git a/WORC/doc/autogen/WORC.tools.rst b/WORC/doc/autogen/WORC.tools.rst index 7649a737..e2645f5e 100644 --- a/WORC/doc/autogen/WORC.tools.rst +++ b/WORC/doc/autogen/WORC.tools.rst @@ -37,3 +37,12 @@ tools Package :show-inheritance: :special-members: +:mod:`createfixedsplits` Module +------------------------------- + +.. automodule:: WORC.tools.createfixedsplits + :members: + :undoc-members: + :show-inheritance: + :special-members: + diff --git a/WORC/doc/autogen/config/WORC.config_Bootstrap_defopts.rst b/WORC/doc/autogen/config/WORC.config_Bootstrap_defopts.rst new file mode 100644 index 00000000..563b6e84 --- /dev/null +++ b/WORC/doc/autogen/config/WORC.config_Bootstrap_defopts.rst @@ -0,0 +1,6 @@ +============ ======= ======= +Subkey Default Options +============ ======= ======= +Use False Boolean +N_iterations 1000 Integer +============ ======= ======= \ No newline at end of file diff --git a/WORC/doc/autogen/config/WORC.config_Bootstrap_description.rst b/WORC/doc/autogen/config/WORC.config_Bootstrap_description.rst new file mode 100644 index 00000000..4731c8a3 --- /dev/null +++ b/WORC/doc/autogen/config/WORC.config_Bootstrap_description.rst @@ -0,0 +1,6 @@ +============ ============================================== +Subkey Description +============ ============================================== +Use Determine whether to use bootstrapping or not. +N_iterations Number of iterations to use for bootstrapping. +============ ============================================== \ No newline at end of file diff --git a/WORC/doc/autogen/config/WORC.config_Classification_defopts.rst b/WORC/doc/autogen/config/WORC.config_Classification_defopts.rst new file mode 100644 index 00000000..ac2fb74d --- /dev/null +++ b/WORC/doc/autogen/config/WORC.config_Classification_defopts.rst @@ -0,0 +1,28 @@ +=================== ==================================== ================================================================================================================================================================= +Subkey Default Options +=================== ==================================== ================================================================================================================================================================= +fastr True True, False +fastr_plugin LinearExecution Any `fastr execution plugin `_ . +classifiers SVM SVM , SVR, SGD, SGDR, RF, LDA, QDA, ComplementND, GaussianNB, LR, RFR, Lasso, ElasticNet. All are estimators from `sklearn `_ +max_iter 100000 Integer +SVMKernel poly poly, linear, rbf +SVMC 0, 6 Two Integers: loc and scale +SVMdegree 1, 6 Two Integers: loc and scale +SVMcoef0 0, 1 Two Integers: loc and scale +SVMgamma -5, 5 Two Integers: loc and scale +RFn_estimators 10, 90 Two Integers: loc and scale +RFmin_samples_split 2, 3 Two Integers: loc and scale +RFmax_depth 5, 5 Two Integers: loc and scale +LRpenalty l2, l1 none, l2, l1 +LRC 0.01, 1.0 Two Integers: loc and scale +LDA_solver svd, lsqr, eigen svd, lsqr, eigen +LDA_shrinkage -5, 5 Two Integers: loc and scale +QDA_reg_param -5, 5 Two Integers: loc and scale +ElasticNet_alpha -5, 5 Two Integers: loc and scale +ElasticNet_l1_ratio 0, 1 Two Integers: loc and scale +SGD_alpha -5, 5 Two Integers: loc and scale +SGD_l1_ratio 0, 1 Two Integers: loc and scale +SGD_loss hinge, squared_hinge, modified_huber hinge, squared_hinge, modified_huber +SGD_penalty none, l2, l1 none, l2, l1 +CNB_alpha 0, 1 Two Integers: loc and scale +=================== ==================================== ================================================================================================================================================================= \ No newline at end of file diff --git a/WORC/doc/autogen/config/WORC.config_Classification_description.rst b/WORC/doc/autogen/config/WORC.config_Classification_description.rst new file mode 100644 index 00000000..1dd87a7f --- /dev/null +++ b/WORC/doc/autogen/config/WORC.config_Classification_description.rst @@ -0,0 +1,28 @@ +=================== ================================================================================================================================================== +Subkey Description +=================== ================================================================================================================================================== +fastr Use fastr for the optimization gridsearch (recommended on clusters, default) or if set to False , joblib (recommended for PCs but not on Windows). +fastr_plugin Name of execution plugin to be used. Default use the same as the self.fastr_plugin for the WORC object. +classifiers Select the estimator(s) to use. Most are implemented using `sklearn `_. For abbreviations, see above. +max_iter Maximum number of iterations to use in training an estimator. Only for specific estimators, see `sklearn `_. +SVMKernel When using a SVM, specify the kernel type. +SVMC Range of the SVM slack parameter. We sample on a uniform log scale: the parameters specify the range of the exponent (a, a + b). +SVMdegree Range of the SVM polynomial degree when using a polynomial kernel. We sample on a uniform scale: the parameters specify the range (a, a + b). +SVMcoef0 Range of SVM homogeneity parameter. We sample on a uniform scale: the parameters specify the range (a, a + b). +SVMgamma Range of the SVM gamma parameter. We sample on a uniform log scale: the parameters specify the range of the exponent (a, a + b) +RFn_estimators Range of number of trees in a RF. We sample on a uniform scale: the parameters specify the range (a, a + b). +RFmin_samples_split Range of minimum number of samples required to split a branch in a RF. We sample on a uniform scale: the parameters specify the range (a, a + b). +RFmax_depth Range of maximum depth of a RF. We sample on a uniform scale: the parameters specify the range (a, a + b). +LRpenalty Penalty term used in LR. +LRC Range of regularization strength in LR. We sample on a uniform scale: the parameters specify the range (a, a + b). +LDA_solver Solver used in LDA. +LDA_shrinkage Range of the LDA shrinkage parameter. We sample on a uniform log scale: the parameters specify the range of the exponent (a, a + b). +QDA_reg_param Range of the QDA regularization parameter. We sample on a uniform log scale: the parameters specify the range of the exponent (a, a + b). +ElasticNet_alpha Range of the ElasticNet penalty parameter. We sample on a uniform log scale: the parameters specify the range of the exponent (a, a + b). +ElasticNet_l1_ratio Range of l1 ratio in LR. We sample on a uniform scale: the parameters specify the range (a, a + b). +SGD_alpha Range of the SGD penalty parameter. We sample on a uniform log scale: the parameters specify the range of the exponent (a, a + b). +SGD_l1_ratio Range of l1 ratio in SGD. We sample on a uniform scale: the parameters specify the range (a, a + b). +SGD_loss hinge, Loss function of SG +SGD_penalty Penalty term in SGD. +CNB_alpha Regularization strenght in ComplementNB. We sample on a uniform scale: the parameters specify the range (a, a + b) +=================== ================================================================================================================================================== \ No newline at end of file diff --git a/WORC/doc/autogen/config/WORC.config_CrossValidation_defopts.rst b/WORC/doc/autogen/config/WORC.config_CrossValidation_defopts.rst new file mode 100644 index 00000000..144d5983 --- /dev/null +++ b/WORC/doc/autogen/config/WORC.config_CrossValidation_defopts.rst @@ -0,0 +1,6 @@ +============ ======= ======= +Subkey Default Options +============ ======= ======= +N_iterations 100 Integer +test_size 0.2 Float +============ ======= ======= \ No newline at end of file diff --git a/WORC/doc/autogen/config/WORC.config_CrossValidation_description.rst b/WORC/doc/autogen/config/WORC.config_CrossValidation_description.rst new file mode 100644 index 00000000..e7b02055 --- /dev/null +++ b/WORC/doc/autogen/config/WORC.config_CrossValidation_description.rst @@ -0,0 +1,6 @@ +============ ===================================================================================== +Subkey Description +============ ===================================================================================== +N_iterations Number of times the data is split in training and test in the outer cross-validation. +test_size The percentage of data to be used for testing. +============ ===================================================================================== \ No newline at end of file diff --git a/WORC/doc/autogen/config/WORC.config_Ensemble_defopts.rst b/WORC/doc/autogen/config/WORC.config_Ensemble_defopts.rst new file mode 100644 index 00000000..de8e6ad8 --- /dev/null +++ b/WORC/doc/autogen/config/WORC.config_Ensemble_defopts.rst @@ -0,0 +1,5 @@ +====== ======= ======= +Subkey Default Options +====== ======= ======= +Use 1 Integer +====== ======= ======= \ No newline at end of file diff --git a/WORC/doc/autogen/config/WORC.config_Ensemble_description.rst b/WORC/doc/autogen/config/WORC.config_Ensemble_description.rst new file mode 100644 index 00000000..f89ad98a --- /dev/null +++ b/WORC/doc/autogen/config/WORC.config_Ensemble_description.rst @@ -0,0 +1,5 @@ +====== =============================================================================================================================== +Subkey Description +====== =============================================================================================================================== +Use Determine whether to use ensembling or not. Provide an integer to state how many estimators to include: 1 equals no ensembling. +====== =============================================================================================================================== \ No newline at end of file diff --git a/WORC/doc/autogen/config/WORC.config_Featsel_defopts.rst b/WORC/doc/autogen/config/WORC.config_Featsel_defopts.rst new file mode 100644 index 00000000..126545c6 --- /dev/null +++ b/WORC/doc/autogen/config/WORC.config_Featsel_defopts.rst @@ -0,0 +1,17 @@ +======================== ==================================== ==================================== +Subkey Default Options +======================== ==================================== ==================================== +Variance True Boolean(s) +GroupwiseSearch True Boolean(s) +SelectFromModel False Boolean(s) +UsePCA False Boolean(s) +PCAType 95variance Inteteger(s), 95variance +StatisticalTestUse False Boolean(s) +StatisticalTestMetric ttest, Welch, Wilcoxon, MannWhitneyU ttest, Welch, Wilcoxon, MannWhitneyU +StatisticalTestThreshold -2, 1.5 Two Integers: loc and scale +ReliefUse False Boolean(s) +ReliefNN 2, 4 Two Integers: loc and scale +ReliefSampleSize 1, 1 Two Integers: loc and scale +ReliefDistanceP 1, 3 Two Integers: loc and scale +ReliefNumFeatures 25, 200 Two Integers: loc and scale +======================== ==================================== ==================================== \ No newline at end of file diff --git a/WORC/doc/autogen/config/WORC.config_Featsel_description.rst b/WORC/doc/autogen/config/WORC.config_Featsel_description.rst new file mode 100644 index 00000000..3fda201a --- /dev/null +++ b/WORC/doc/autogen/config/WORC.config_Featsel_description.rst @@ -0,0 +1,17 @@ +======================== ================================================================================================================================================================================================================================================ +Subkey Description +======================== ================================================================================================================================================================================================================================================ +Variance If True, exclude features which have a variance < 0.01. Based on ` sklearn"s VarianceThreshold `_. +GroupwiseSearch Randomly select which feature groups to use. Parameters determined by the SelectFeatGroup config part, see below. +SelectFromModel Select features by first training a LASSO model. The alpha for the LASSO model is randomly generated. See also `sklearn"s SelectFromModel `_. +UsePCA If True, Use Principle Component Analysis (PCA) to select features. +PCAType Method to select number of components using PCA: Either the number of components that explains 95% of the variance, or use a fixed number of components.95variance +StatisticalTestUse If True, use statistical test to select features. +StatisticalTestMetric Define the type of statistical test to be used. +StatisticalTestThreshold Specify a threshold for the p-value threshold used in the statistical test to select features. The first element defines the lower boundary, the other the upper boundary. Random sampling will occur between the boundaries. +ReliefUse If True, use Relief to select features. +ReliefNN Min and max of number of nearest neighbors search range in Relief. +ReliefSampleSize Min and max of sample size search range in Relief. +ReliefDistanceP Min and max of positive distance search range in Relief. +ReliefNumFeatures Min and max of number of features that is selected search range in Relief. +======================== ================================================================================================================================================================================================================================================ \ No newline at end of file diff --git a/WORC/doc/autogen/config/WORC.config_FeatureScaling_defopts.rst b/WORC/doc/autogen/config/WORC.config_FeatureScaling_defopts.rst new file mode 100644 index 00000000..ffa829ff --- /dev/null +++ b/WORC/doc/autogen/config/WORC.config_FeatureScaling_defopts.rst @@ -0,0 +1,6 @@ +============== ======= =============== +Subkey Default Options +============== ======= =============== +scale_features True Boolean(s) +scaling_method z_score z_score, minmax +============== ======= =============== \ No newline at end of file diff --git a/WORC/doc/autogen/config/WORC.config_FeatureScaling_description.rst b/WORC/doc/autogen/config/WORC.config_FeatureScaling_description.rst new file mode 100644 index 00000000..b730b395 --- /dev/null +++ b/WORC/doc/autogen/config/WORC.config_FeatureScaling_description.rst @@ -0,0 +1,6 @@ +============== ============================================ +Subkey Description +============== ============================================ +scale_features Determine whether to use feature scaling is. +scaling_method Determine the scaling method. +============== ============================================ \ No newline at end of file diff --git a/WORC/doc/autogen/config/WORC.config_General_defopts.rst b/WORC/doc/autogen/config/WORC.config_General_defopts.rst new file mode 100644 index 00000000..3208f217 --- /dev/null +++ b/WORC/doc/autogen/config/WORC.config_General_defopts.rst @@ -0,0 +1,13 @@ +================== ============================ ================================================================================= +Subkey Default Options +================== ============================ ================================================================================= +cross_validation True True, False +Segmentix False True, False +FeatureCalculator predict/CalcFeatures:1.0 predict/CalcFeatures:1.0, pyradiomics/CF_pyradiomics:1.0, your own tool reference +Preprocessing worc/PreProcess:1.0 worc/PreProcess:1.0, your own tool reference +RegistrationNode 'elastix4.8/Elastix:4.8' 'elastix4.8/Elastix:4.8', your own tool reference +TransformationNode 'elastix4.8/Transformix:4.8' 'elastix4.8/Transformix:4.8', your own tool reference +Joblib_ncores 4 Integer > 0 +Joblib_backend multiprocessing multiprocessing, threading +tempsave False True, False +================== ============================ ================================================================================= \ No newline at end of file diff --git a/WORC/doc/autogen/config/WORC.config_General_description.rst b/WORC/doc/autogen/config/WORC.config_General_description.rst new file mode 100644 index 00000000..b133998f --- /dev/null +++ b/WORC/doc/autogen/config/WORC.config_General_description.rst @@ -0,0 +1,13 @@ +================== ==================================================================================================================================================================== +Subkey Description +================== ==================================================================================================================================================================== +cross_validation Determine whether a cross validation will be performed or not. Obsolete, will be removed. +Segmentix Determine whether to use Segmentix tool for segmentation preprocessing. +FeatureCalculator Specifies which feature calculation tool should be used. +Preprocessing Specifies which tool will be used for image preprocessing. +RegistrationNode Specifies which tool will be used for image registration. +TransformationNode Specifies which tool will be used for applying image transformations. +Joblib_ncores Number of cores to be used by joblib for multicore processing. +Joblib_backend Type of backend to be used by joblib for multicore processing. +tempsave Determines whether after every cross validation iteration the result will be saved, in addition to the result after all iterations. Especially useful for debugging. +================== ==================================================================================================================================================================== \ No newline at end of file diff --git a/WORC/doc/autogen/config/WORC.config_HyperOptimization_defopts.rst b/WORC/doc/autogen/config/WORC.config_HyperOptimization_defopts.rst new file mode 100644 index 00000000..38c4bdb8 --- /dev/null +++ b/WORC/doc/autogen/config/WORC.config_HyperOptimization_defopts.rst @@ -0,0 +1,11 @@ +============== =========== ===================================================================================================================== +Subkey Default Options +============== =========== ===================================================================================================================== +scoring_method f1_weighted Any `sklearn metric `_ +test_size 0.15 Float +n_splits 5 Integer +N_iterations 10000 Integer +n_jobspercore 2000 Integer +maxlen 100 Integer +ranking_score test_score String +============== =========== ===================================================================================================================== \ No newline at end of file diff --git a/WORC/doc/autogen/config/WORC.config_HyperOptimization_description.rst b/WORC/doc/autogen/config/WORC.config_HyperOptimization_description.rst new file mode 100644 index 00000000..00951d6f --- /dev/null +++ b/WORC/doc/autogen/config/WORC.config_HyperOptimization_description.rst @@ -0,0 +1,11 @@ +============== ====================================================================================================================================== +Subkey Description +============== ====================================================================================================================================== +scoring_method Specify the optimization metric for your hyperparameter search. +test_size Size of test set in the hyperoptimization cross validation, given as a percentage of the whole dataset. +n_splits Number of iterations in train-validation cross-validation used for model optimization. +N_iterations Number of iterations used in the hyperparameter optimization. This corresponds to the number of samples drawn from the parameter grid. +n_jobspercore Number of jobs assigned to a single core. Only used if fastr is set to true in the classfication. +maxlen Number of estimators for which the fitted outcomes and parameters are saved. Increasing this number will increase the memory usage. +ranking_score Score used for ranking the performance of the evaluated workflows. +============== ====================================================================================================================================== \ No newline at end of file diff --git a/WORC/doc/autogen/config/WORC.config_ImageFeatures_defopts.rst b/WORC/doc/autogen/config/WORC.config_ImageFeatures_defopts.rst new file mode 100644 index 00000000..f5f8171a --- /dev/null +++ b/WORC/doc/autogen/config/WORC.config_ImageFeatures_defopts.rst @@ -0,0 +1,32 @@ +=================== =================== ========================== +Subkey Default Options +=================== =================== ========================== +shape True True, False +histogram True True, False +orientation True True, False +texture_Gabor False True, False +texture_LBP True True, False +texture_GLCM True True, False +texture_GLCMMS True True, False +texture_GLRLM True True, False +texture_GLSZM True True, False +texture_NGTDM True True, False +coliage False True, False +vessel False True, False +log False True, False +phase False True, False +image_type CT CT +gabor_frequencies 0.05, 0.2, 0.5 Float(s) +gabor_angles 0, 45, 90, 135 Integer(s) +GLCM_angles 0, 0.79, 1.57, 2.36 Float(s) +GLCM_levels 16 Integer > 0 +GLCM_distances 1, 3 Integer(s) > 0 +LBP_radius 3, 8, 15 Integer(s) > 0 +LBP_npoints 12, 24, 36 Integer(s) > 0 +phase_minwavelength 3 Integer > 0 +phase_nscale 5 Integer > 0 +log_sigma 1, 5, 10 Integer(s) +vessel_scale_range 1, 10 Two integers: min and max. +vessel_scale_step 2 Integer > 0 +vessel_radius 5 Integer > 0 +=================== =================== ========================== \ No newline at end of file diff --git a/WORC/doc/autogen/config/WORC.config_ImageFeatures_description.rst b/WORC/doc/autogen/config/WORC.config_ImageFeatures_description.rst new file mode 100644 index 00000000..c7c2241e --- /dev/null +++ b/WORC/doc/autogen/config/WORC.config_ImageFeatures_description.rst @@ -0,0 +1,32 @@ +=================== =================================================================================================== +Subkey Description +=================== =================================================================================================== +shape Determine whether orientation features are computed or not. +histogram Determine whether histogram features are computed or not. +orientation Determine whether orientation features are computed or not. +texture_Gabor Determine whether Gabor texture features are computed or not. +texture_LBP Determine whether LBP texture features are computed or not. +texture_GLCM Determine whether GLCM texture features are computed or not. +texture_GLCMMS Determine whether GLCM Multislice texture features are computed or not. +texture_GLRLM Determine whether GLRLM texture features are computed or not. +texture_GLSZM Determine whether GLSZM texture features are computed or not. +texture_NGTDM Determine whether NGTDM texture features are computed or not. +coliage Determine whether coliage features are computed or not. +vessel Determine whether vessel features are computed or not. +log Determine whether LoG features are computed or not. +phase Determine whether local phase features are computed or not. +image_type Modality of images supplied. Determines how the image is loaded. +gabor_frequencies Frequencies of Gabor filters used: can be a single float or a list. +gabor_angles Angles of Gabor filters in degrees: can be a single integer or a list. +GLCM_angles Angles used in GLCM computation in radians: can be a single float or a list. +GLCM_levels Number of grayscale levels used in discretization before GLCM computation. +GLCM_distances Distance(s) used in GLCM computation in pixels: can be a single integer or a list. +LBP_radius Radii used for LBP computation: can be a single integer or a list. +LBP_npoints Number(s) of points used in LBP computation: can be a single integer or a list. +phase_minwavelength Minimal wavelength in pixels used for phase features. +phase_nscale Number of scales used in phase feature computation. +log_sigma Standard deviation(s) in pixels used in log feature computation: can be a single integer or a list. +vessel_scale_range Scale in pixels used for Frangi vessel filter. Given as a minimum and a maximum. +vessel_scale_step Step size used to go from minimum to maximum scale on Frangi vessel filter. +vessel_radius Radius to determine boundary of between inner part and edge in Frangi vessel filter. +=================== =================================================================================================== \ No newline at end of file diff --git a/WORC/doc/autogen/config/WORC.config_Imputation_defopts.rst b/WORC/doc/autogen/config/WORC.config_Imputation_defopts.rst new file mode 100644 index 00000000..f306a0f2 --- /dev/null +++ b/WORC/doc/autogen/config/WORC.config_Imputation_defopts.rst @@ -0,0 +1,7 @@ +=========== ========================================== ========================================== +Subkey Default Options +=========== ========================================== ========================================== +use False Boolean(s) +strategy mean, median, most_frequent, constant, knn mean, median, most_frequent, constant, knn +n_neighbors 5, 5 Two Integers: loc and scale +=========== ========================================== ========================================== \ No newline at end of file diff --git a/WORC/doc/autogen/config/WORC.config_Imputation_description.rst b/WORC/doc/autogen/config/WORC.config_Imputation_description.rst new file mode 100644 index 00000000..f94bb4d6 --- /dev/null +++ b/WORC/doc/autogen/config/WORC.config_Imputation_description.rst @@ -0,0 +1,7 @@ +=========== ======================================================================================================================================================= +Subkey Description +=========== ======================================================================================================================================================= +use If True, use feature imputation methods to replace NaN values. If False, all NaN features will be set to zero. +strategy Method to be used for imputation. +n_neighbors When using k-Nearest Neighbors (kNN) for feature imputation, determines the number of neighbors used for imputation. Can be a single integer or a list. +=========== ======================================================================================================================================================= \ No newline at end of file diff --git a/WORC/doc/autogen/config/WORC.config_Labels_defopts.rst b/WORC/doc/autogen/config/WORC.config_Labels_defopts.rst new file mode 100644 index 00000000..eb8d4e80 --- /dev/null +++ b/WORC/doc/autogen/config/WORC.config_Labels_defopts.rst @@ -0,0 +1,8 @@ +=========== ============== ======================= +Subkey Default Options +=========== ============== ======================= +label_names Label1, Label2 String(s) +modus singlelabel singlelabel, multilabel +url WIP Not Supported Yet +projectID WIP Not Supported Yet +=========== ============== ======================= \ No newline at end of file diff --git a/WORC/doc/autogen/config/WORC.config_Labels_description.rst b/WORC/doc/autogen/config/WORC.config_Labels_description.rst new file mode 100644 index 00000000..fe6a9f1e --- /dev/null +++ b/WORC/doc/autogen/config/WORC.config_Labels_description.rst @@ -0,0 +1,8 @@ +=========== =========================================================================================== +Subkey Description +=========== =========================================================================================== +label_names The labels used from your label file for classification. +modus Determine whether multilabel or singlelabel classification or regression will be performed. +url WIP +projectID WIP +=========== =========================================================================================== \ No newline at end of file diff --git a/WORC/doc/autogen/config/WORC.config_Normalize_defopts.rst b/WORC/doc/autogen/config/WORC.config_Normalize_defopts.rst new file mode 100644 index 00000000..1ec55702 --- /dev/null +++ b/WORC/doc/autogen/config/WORC.config_Normalize_defopts.rst @@ -0,0 +1,6 @@ +====== ======= ================= +Subkey Default Options +====== ======= ================= +ROI Full True, False, Full +Method z_score z_score, minmed +====== ======= ================= \ No newline at end of file diff --git a/WORC/doc/autogen/config/WORC.config_Normalize_description.rst b/WORC/doc/autogen/config/WORC.config_Normalize_description.rst new file mode 100644 index 00000000..fe4cac34 --- /dev/null +++ b/WORC/doc/autogen/config/WORC.config_Normalize_description.rst @@ -0,0 +1,6 @@ +====== ============================================================================================================================================================================================================================================================== +Subkey Description +====== ============================================================================================================================================================================================================================================================== +ROI If a mask is supplied and this is set to True, normalize image based on supplied ROI. Otherwise, the full image is used for normalization using the SimpleITK Normalize function. Lastly, setting this to False will result in no normalization being applied. +Method Method used for normalization if ROI is supplied. Currently, z-scoring or using the minimum and median of the ROI can be used. +====== ============================================================================================================================================================================================================================================================== \ No newline at end of file diff --git a/WORC/doc/autogen/config/WORC.config_SampleProcessing_defopts.rst b/WORC/doc/autogen/config/WORC.config_SampleProcessing_defopts.rst new file mode 100644 index 00000000..e96b3803 --- /dev/null +++ b/WORC/doc/autogen/config/WORC.config_SampleProcessing_defopts.rst @@ -0,0 +1,8 @@ +=============== ======= =========================== +Subkey Default Options +=============== ======= =========================== +SMOTE True Boolean(s) +SMOTE_ratio 1, 0 Two Integers: loc and scale +SMOTE_neighbors 5, 15 Two Integers: loc and scale +Oversampling False Boolean(s) +=============== ======= =========================== \ No newline at end of file diff --git a/WORC/doc/autogen/config/WORC.config_SampleProcessing_description.rst b/WORC/doc/autogen/config/WORC.config_SampleProcessing_description.rst new file mode 100644 index 00000000..3eb22601 --- /dev/null +++ b/WORC/doc/autogen/config/WORC.config_SampleProcessing_description.rst @@ -0,0 +1,8 @@ +=============== ===================================================================================================================================================================================================== +Subkey Description +=============== ===================================================================================================================================================================================================== +SMOTE Determine whether to use SMOTE oversampling, see also ` imbalanced learn `_. +SMOTE_ratio Determine the ratio of oversampling. If 1, the minority class will be oversampled to the same size as the majority class. We sample on a uniform scale: the parameters specify the range (a, a + b). +SMOTE_neighbors Number of neighbors used in SMOTE. This should be much smaller than the number of objects/patients you supply. We sample on a uniform scale: the parameters specify the range (a, a + b). +Oversampling Determine whether to random oversampling. +=============== ===================================================================================================================================================================================================== \ No newline at end of file diff --git a/WORC/doc/autogen/config/WORC.config_Segmentix_defopts.rst b/WORC/doc/autogen/config/WORC.config_Segmentix_defopts.rst new file mode 100644 index 00000000..67202169 --- /dev/null +++ b/WORC/doc/autogen/config/WORC.config_Segmentix_defopts.rst @@ -0,0 +1,9 @@ +========= ======== ================== +Subkey Default Options +========= ======== ================== +mask subtract subtract, multiply +segtype None None, Ring +segradius 5 Integer > 0 +N_blobs 1 Integer > 0 +fillholes False True, False +========= ======== ================== \ No newline at end of file diff --git a/WORC/doc/autogen/config/WORC.config_Segmentix_description.rst b/WORC/doc/autogen/config/WORC.config_Segmentix_description.rst new file mode 100644 index 00000000..72d6caac --- /dev/null +++ b/WORC/doc/autogen/config/WORC.config_Segmentix_description.rst @@ -0,0 +1,9 @@ +========= ======================================================================================================= +Subkey Description +========= ======================================================================================================= +mask If a mask is supplied, should the mask be subtracted from the contour or multiplied. +segtype If Ring, then a ring around the segmentation will be used as contour. +segradius Define the radius of the ring used if segtype is Ring. +N_blobs How many of the largest blobs are extracted from the segmentation. If None, no blob extraction is used. +fillholes Determines whether hole filling will be used. +========= ======================================================================================================= \ No newline at end of file diff --git a/WORC/doc/autogen/config/WORC.config_SelectFeatGroup_defopts.rst b/WORC/doc/autogen/config/WORC.config_SelectFeatGroup_defopts.rst new file mode 100644 index 00000000..8d35914d --- /dev/null +++ b/WORC/doc/autogen/config/WORC.config_SelectFeatGroup_defopts.rst @@ -0,0 +1,20 @@ +======================= =========== ========== +Subkey Default Options +======================= =========== ========== +shape_features True, False Boolean(s) +histogram_features True, False Boolean(s) +orientation_features True, False Boolean(s) +texture_Gabor_features False Boolean(s) +texture_GLCM_features True, False Boolean(s) +texture_GLCMMS_features True, False Boolean(s) +texture_GLRLM_features True, False Boolean(s) +texture_GLSZM_features True, False Boolean(s) +texture_NGTDM_features True, False Boolean(s) +texture_LBP_features True, False Boolean(s) +patient_features False Boolean(s) +semantic_features False Boolean(s) +coliage_features False Boolean(s) +log_features False Boolean(s) +vessel_features False Boolean(s) +phase_features False Boolean(s) +======================= =========== ========== \ No newline at end of file diff --git a/WORC/doc/autogen/config/WORC.config_SelectFeatGroup_description.rst b/WORC/doc/autogen/config/WORC.config_SelectFeatGroup_description.rst new file mode 100644 index 00000000..b41e3749 --- /dev/null +++ b/WORC/doc/autogen/config/WORC.config_SelectFeatGroup_description.rst @@ -0,0 +1,20 @@ +======================= ======================================================= +Subkey Description +======================= ======================================================= +shape_features If True, use shape features in model. +histogram_features If True, use histogram features in model. +orientation_features If True, use orientation features in model. +texture_Gabor_features If True, use Gabor texture features in model. +texture_GLCM_features If True, use GLCM texture features in model. +texture_GLCMMS_features If True, use GLCM Multislice texture features in model. +texture_GLRLM_features If True, use GLRLM texture features in model. +texture_GLSZM_features If True, use GLSZM texture features in model. +texture_NGTDM_features If True, use NGTDM texture features in model. +texture_LBP_features If True, use LBP texture features in model. +patient_features If True, use patient features in model. +semantic_features If True, use semantic features in model. +coliage_features If True, use coliage features in model. +log_features If True, use log features in model. +vessel_features If True, use vessel features in model. +phase_features If True, use phase features in model. +======================= ======================================================= \ No newline at end of file diff --git a/WORC/doc/conf.py b/WORC/doc/conf.py index ef9be218..5abc15d9 100644 --- a/WORC/doc/conf.py +++ b/WORC/doc/conf.py @@ -26,6 +26,7 @@ print('[conf.py] On Read the Docs') from generate_modules import recurse_tree +from generate_config import generate_config_doc from doc_clean import clean # -- General configuration ----------------------------------------------------- @@ -271,5 +272,8 @@ ] recurse_tree(rootpath, excludes, opts) +print('[conf.py] python generate_config.py') +generate_config_doc() + print('[conf.py] Done...') print('[conf.py] Found files in curdir: {}'.format(os.listdir('.'))) diff --git a/WORC/doc/doc_clean.py b/WORC/doc/doc_clean.py index 30440bd5..b7f72f06 100644 --- a/WORC/doc/doc_clean.py +++ b/WORC/doc/doc_clean.py @@ -27,6 +27,7 @@ def clean(): autogen_path = doc_path / 'autogen' clean_dir(autogen_path) + clean_dir(autogen_path / 'config') def clean_dir(directory): diff --git a/WORC/doc/doc_generate.py b/WORC/doc/doc_generate.py index f2032157..ca5321e0 100644 --- a/WORC/doc/doc_generate.py +++ b/WORC/doc/doc_generate.py @@ -18,11 +18,12 @@ import os os.chdir(os.path.dirname(os.path.abspath(__file__))) -os.system('python3 doc_clean.py') -print('python3 generate_modules.py ..' + os.path.sep + ' -d .' + os.path.sep + ' -s rst -f') -os.system('python3 generate_modules.py ..' + os.path.sep + ' -d .' + os.path.sep + ' -s rst -f') -os.system('python3 generate_config.py') -print('python3 generate_config.py') +# os.system('python3 doc_clean.py') +# print('python3 generate_modules.py ..' + os.path.sep + ' -d .' + os.path.sep + ' -s rst -f') +# os.system('python3 generate_modules.py ..' + os.path.sep + ' -d .' + os.path.sep + ' -s rst -f') +# print('python3 generate_config.py') +# os.system('python3 generate_config.py') + print('make html') os.system('make html') #os.system('make latexpdf') diff --git a/WORC/doc/generate_config.py b/WORC/doc/generate_config.py index 396ee21c..5df0be6c 100644 --- a/WORC/doc/generate_config.py +++ b/WORC/doc/generate_config.py @@ -20,13 +20,8 @@ def generate_config(): for key in config_defaults.keys(): for num, subkey in enumerate(config_defaults[key].keys()): - print(f'[generate_config.py] Documenting field {key}: {subkey}') - if num == 0: - field_key.append(key) - else: - # After the first field of this key is generated, we do not append the key for better readability - field_key.append('') - + # print(f'[generate_config.py] Documenting field {key}: {subkey}') + field_key.append(key) field_subkey.append(subkey) field_default.append(config_defaults[key][subkey]) @@ -34,7 +29,7 @@ def generate_config(): field_description.append(config_descriptions[key][subkey]) except KeyError: print(f'[WARNING] No description for {key}: {subkey}') - field_description.append('') + field_description.append('WIP') try: field_option.append(config_options[key][subkey]) @@ -45,17 +40,63 @@ def generate_config(): data = [field_key, field_subkey, field_description, field_default, field_option] headers = ['Key', 'Subkey', 'Description', 'Default', 'Options',] - return create_rest_table(data, headers) + return data, headers def generate_config_doc(): print('[generate_config.py] Generating config reference...') - filename = os.path.join(os.path.dirname(__file__), 'autogen', 'WORC.config.rst') - + data, headers = generate_config() + unique_keys = list(set(data[0])) + if type(unique_keys) is not list: + # Single number, convert to list + unique_keys = [unique_keys] + + unique_keys.sort() + + # Per main section, create relevant tables + for key in unique_keys: + indices = [i for i, x in enumerate(data[0]) if x == key] + subkeys = [data[1][i] for i in indices] + descriptions = [data[2][i] for i in indices] + defaults = [data[3][i] for i in indices] + options = [data[4][i] for i in indices] + + # Create description table + filename = os.path.join(os.path.dirname(__file__), + 'autogen', + 'config', + f'WORC.config_{key}_description.rst') + headers_temp = ['Subkey', 'Description'] + data_temp = [subkeys, descriptions] + table = create_rest_table(data_temp, headers_temp) + + with open(filename, 'w') as fh_out: + fh_out.write(table) + + # Create defaults and options table + filename = os.path.join(os.path.dirname(__file__), + 'autogen', + 'config', + f'WORC.config_{key}_defopts.rst') + headers_temp = ['Subkey', 'Default', 'Options'] + data_temp = [subkeys, defaults, options] + table = create_rest_table(data_temp, headers_temp) + + with open(filename, 'w') as fh_out: + fh_out.write(table) + + # Create main table + headers = ['Key', 'Reference'] + data = [unique_keys, [f':ref:`{h} `' for h in unique_keys]] + table = create_rest_table(data, headers) + + filename = os.path.join(os.path.dirname(__file__), + 'autogen', + f'WORC.config.rst') with open(filename, 'w') as fh_out: - fh_out.write(generate_config()) + fh_out.write(table) - print(f'[generate_config.py] Config reference saved to {filename}') + print(f'[generate_config.py] Config references saved!') def generate_config_options(): @@ -223,6 +264,9 @@ def generate_config_options(): config['HyperOptimization']['test_size'] = 'Float' config['HyperOptimization']['N_iterations'] = 'Integer' config['HyperOptimization']['n_jobspercore'] = 'Integer' + config['HyperOptimization']['n_splits'] = 'Integer' + config['HyperOptimization']['maxlen'] = 'Integer' + config['HyperOptimization']['ranking_score'] = 'String' # Feature scaling options config['FeatureScaling'] = dict() @@ -238,7 +282,12 @@ def generate_config_options(): # Ensemble options config['Ensemble'] = dict() - config['Ensemble']['Use'] = 'Boolean or Integer' + config['Ensemble']['Use'] = 'Integer' + + # Bootstrap options + config['Bootstrap'] = dict() + config['Bootstrap']['Use'] = 'Boolean' + config['Bootstrap']['N_iterations'] = 'Integer' return config @@ -324,9 +373,9 @@ def generate_config_descriptions(): # Feature selection config['Featsel'] = dict() - config['Featsel']['Variance'] = 'If True, exclude features which have a variance < 0.01. Based on ` sklearn `_.' + config['Featsel']['Variance'] = 'If True, exclude features which have a variance < 0.01. Based on ` sklearn"s VarianceThreshold `_.' config['Featsel']['GroupwiseSearch'] = 'Randomly select which feature groups to use. Parameters determined by the SelectFeatGroup config part, see below.' - config['Featsel']['SelectFromModel'] = 'Select features by first training a LASSO model. The alpha for the LASSO model is randomly generated. See also `sklearn `_.' + config['Featsel']['SelectFromModel'] = 'Select features by first training a LASSO model. The alpha for the LASSO model is randomly generated. See also `sklearn"s SelectFromModel `_.' config['Featsel']['UsePCA'] = 'If True, Use Principle Component Analysis (PCA) to select features.' config['Featsel']['PCAType'] = 'Method to select number of components using PCA: Either the number of components that explains 95% of the variance, or use a fixed number of components.95variance' config['Featsel']['StatisticalTestUse'] = 'If True, use statistical test to select features.' @@ -408,6 +457,9 @@ def generate_config_descriptions(): config['HyperOptimization']['test_size'] = 'Size of test set in the hyperoptimization cross validation, given as a percentage of the whole dataset.' config['HyperOptimization']['N_iterations'] = 'Number of iterations used in the hyperparameter optimization. This corresponds to the number of samples drawn from the parameter grid.' config['HyperOptimization']['n_jobspercore'] = 'Number of jobs assigned to a single core. Only used if fastr is set to true in the classfication.' # only relevant when using fastr in classification + config['HyperOptimization']['n_splits'] = 'Number of iterations in train-validation cross-validation used for model optimization.' + config['HyperOptimization']['maxlen'] = 'Number of estimators for which the fitted outcomes and parameters are saved. Increasing this number will increase the memory usage.' + config['HyperOptimization']['ranking_score'] = 'Score used for ranking the performance of the evaluated workflows.' # Feature scaling options config['FeatureScaling'] = dict() @@ -423,8 +475,12 @@ def generate_config_descriptions(): # Ensemble options config['Ensemble'] = dict() - config['Ensemble']['Use'] = 'Determine whether to use ensembling or not. Either provide an integer to state how many estimators to include, or True, which will use the default ensembling method.' + config['Ensemble']['Use'] = 'Determine whether to use ensembling or not. Provide an integer to state how many estimators to include: 1 equals no ensembling.' + # Bootstrap options + config['Bootstrap'] = dict() + config['Bootstrap']['Use'] = 'Determine whether to use bootstrapping or not.' + config['Bootstrap']['N_iterations'] = 'Number of iterations to use for bootstrapping.' return config diff --git a/WORC/doc/index.rst b/WORC/doc/index.rst index 155c3206..a3569d4c 100644 --- a/WORC/doc/index.rst +++ b/WORC/doc/index.rst @@ -53,7 +53,7 @@ WORC has been used in the following studies: `Jose M. Castillo T., Martijn P. A. Starmans, Ivo Schoots, Wiro J. Niessen, Stefan Klein, Jifke F. Veenland. "CLASSIFICATION OF PROSTATE CANCER: HIGH GRADE VERSUS LOW GRADE USING A RADIOMICS APPROACH." IEEE International Symposium on Biomedical Imaging (ISBI) 2019. `_ -WORC is made possible by contributions from the following people: Martijn Starmans, and Stefan Klein +WORC is made possible by contributions from the following people: Martijn Starmans, Thomas Phil, and Stefan Klein WORC Documentation diff --git a/WORC/doc/static/configuration.rst b/WORC/doc/static/configuration.rst index a46085ab..48d71936 100644 --- a/WORC/doc/static/configuration.rst +++ b/WORC/doc/static/configuration.rst @@ -3,7 +3,23 @@ Configuration ============= +Introduction +------------ +WORC has defaults for all settings so it can be run out of the box to test the examples. +However, you may want to alter the fastr configuration to your system settings, e.g. +to locate your input and output folders and how much you want to parallelize the execution. + +Fastr will search for a config file named ``config.py`` in the ``$FASTRHOME`` directory +(which defaults to ``~/.fastr/`` if it is not set). So if ``$FASTRHOME`` is set the ``~/.fastr/`` +will be ignored. Additionally, .py files from the ``$FASTRHOME/config.d`` folder will be parsed +as well. You will see that upon installation, WORC has already put a ``WORC_config.py`` file in the +``config.d`` folder. + +For a sample configuration file and a complete overview of the options in ``config.py`` see +the :ref:`configuration-chapter` section. + +% Note: Above was originally from quick start As ``WORC`` and the default tools used are mostly Python based, we've chosen to put our configuration in a ``configparser`` object. This has several advantages: @@ -12,6 +28,10 @@ advantages: 2. Second, each tool can be set to parse only specific parts of the configuration, enabling us to supply one file to all tools instead of needing many parameter files. + +Creation and interaction +------------------------- + The default configuration is generated through the :py:meth:`WORC.defaultconfig() ` function. You can then change things as you would in a dictionary and @@ -52,48 +72,87 @@ means that the SVM is 2x more likely to be tested in the model selection than LR list can be created by using commas for separation, e.g. :py:meth:`Network.create_source <'value1, value2, ... ')>`. +Contents +-------- +The config object can be indexed as ``config[key][subkey] = value``. The various keys, subkeys, and the values +(description, defaults and options) can be found below. -General -------- +.. include:: ../autogen/WORC.config.rst +Details on each section of the config can be found below. -PREDICTGeneral --------------- -These fields contain general settings for when using PREDICT. +.. _config-General: + +General +~~~~~~~ +These fields contain general settings for when using WORC. For more info on the Joblib settings, which are used in the Joblib Parallel function, see `here `__. When you run WORC on a cluster with nodes supporting only a single core to be used per node, e.g. the BIGR cluster, use only 1 core and threading as a backend. +**Description:** +.. include:: ../autogen/config/WORC.config_General_description.rst +**Defaults and Options:** + +.. include:: ../autogen/config/WORC.config_General_defopts.rst + + +.. _config-Segmentix: Segmentix ---------- +~~~~~~~~~ These fields are only important if you specified using the segmentix tool in the general configuration. +**Description:** + +.. include:: ../autogen/config/WORC.config_Segmentix_description.rst -Preprocessing -------------- +**Defaults and Options:** + +.. include:: ../autogen/config/WORC.config_Segmentix_defopts.rst + + +.. _config-Normalize: +Normalize +~~~~~~~~~~~~~ The preprocessing node acts before the feature extraction on the image. Currently, only normalization is included: hence the dictionary name is *Normalize*. Additionally, scans with image type CT (see later in the tutorial) provided as DICOM are scaled to Hounsfield Units. +**Description:** + +.. include:: ../autogen/config/WORC.config_Normalize_description.rst -Imagefeatures -------------- +**Defaults and Options:** +.. include:: ../autogen/config/WORC.config_Normalize_defopts.rst + + +.. _config-ImageFeatures: +ImageFeatures +~~~~~~~~~~~~~ If using the PREDICT toolbox, you can specify some settings for the feature computation here. Also, you can select if the certain features are computed or not. +**Description:** -Featsel -------- +.. include:: ../autogen/config/WORC.config_ImageFeatures_description.rst + +**Defaults and Options:** + +.. include:: ../autogen/config/WORC.config_ImageFeatures_defopts.rst + +.. _config-Featsel: +Featsel +~~~~~~~ When using the PREDICT toolbox for classification, these settings can be used for feature selection methods. Note that these settings are actually used in the hyperparameter optimization. Hence you can provide @@ -102,9 +161,18 @@ which finally the best setting in combination with the other hyperparameters is selected. Again, these should be formatted as string containing the actual values, e.g. value1, value2. +**Description:** + +.. include:: ../autogen/config/WORC.config_Featsel_description.rst + +**Defaults and Options:** +.. include:: ../autogen/config/WORC.config_Featsel_defopts.rst + + +.. _config-SelectFeatGroup: SelectFeatGroup ---------------- +~~~~~~~~~~~~~~~ If the PREDICT feature computation and classification tools are used, then you can do a gridsearch among the various feature groups for the optimal combination. If you do not want this, set all fields to a single @@ -114,8 +182,18 @@ Previously, there was a single parameter for the texture features, selecting all, none or a single group. This is still supported, but not recommended, and looks as follows: +**Description:** + +.. include:: ../autogen/config/WORC.config_SelectFeatGroup_description.rst + +**Defaults and Options:** + +.. include:: ../autogen/config/WORC.config_SelectFeatGroup_defopts.rst + + +.. _config-Imputation: Imputation ----------------- +~~~~~~~~~~~~~~~~ When using the PREDICT toolbox for classification, these settings are used for feature imputation.Note that these settings are actually used in the hyperparameter optimization. Hence you can provide multiple @@ -123,22 +201,50 @@ values per field, of which random samples will be drawn of which finally the best setting in combination with the other hyperparameters is selected. +**Description:** + +.. include:: ../autogen/config/WORC.config_Imputation_description.rst +**Defaults and Options:** + +.. include:: ../autogen/config/WORC.config_Imputation_defopts.rst + + +.. _config-Classification: Classification --------------- +~~~~~~~~~~~~~~ When using the PREDICT toolbox for classification, you can specify the following settings. Almost all of these are used in CASH. Most of the classifiers are implemented using sklearn; hence descriptions of the hyperparameters can also be found there. +**Description:** + +.. include:: ../autogen/config/WORC.config_Classification_description.rst + +**Defaults and Options:** +.. include:: ../autogen/config/WORC.config_Classification_defopts.rst + + +.. _config-CrossValidation: CrossValidation ---------------- +~~~~~~~~~~~~~~~ When using the PREDICT toolbox for classification and you specified using cross validation, specify the following settings. +**Description:** + +.. include:: ../autogen/config/WORC.config_CrossValidation_description.rst + +**Defaults and Options:** + +.. include:: ../autogen/config/WORC.config_CrossValidation_defopts.rst + + +.. _config-Labels: Labels --------- +~~~~~~~~ When using the PREDICT toolbox for classification, you have to set the label used for classification. @@ -162,8 +268,6 @@ You can supply a single label or multiple labels split by commas, for each of which an estimator will be fit. For example, suppose you simply want to use Label1 for classification, then set: - - .. code-block:: python config['Labels']['label_names'] = 'Label1' @@ -173,44 +277,86 @@ If you want to first train a classifier on Label1 and then Label2, set: ``config[Genetics][label_names] = Label1, Label2`` +**Description:** + +.. include:: ../autogen/config/WORC.config_Labels_description.rst + +**Defaults and Options:** +.. include:: ../autogen/config/WORC.config_Labels_defopts.rst + +.. _config-HyperOptimization: Hyperoptimization ------------------ +~~~~~~~~~~~~~~~~~ When using the PREDICT toolbox for classification, you have to supply your hyperparameter optimization procedure here. +**Description:** + +.. include:: ../autogen/config/WORC.config_HyperOptimization_description.rst + +**Defaults and Options:** + +.. include:: ../autogen/config/WORC.config_HyperOptimization_defopts.rst + +.. _config-FeatureScaling: FeatureScaling --------------- +~~~~~~~~~~~~~~ Determines which method is applied to scale each feature. +**Description:** + +.. include:: ../autogen/config/WORC.config_FeatureScaling_description.rst + +**Defaults and Options:** + +.. include:: ../autogen/config/WORC.config_FeatureScaling_defopts.rst + +.. _config-SampleProcessing: SampleProcessing ----------------- +~~~~~~~~~~~~~~~~ Before performing the hyperoptimization, you can use SMOTE: Synthetic Minority Over-sampling Technique to oversample your data. +**Description:** + +.. include:: ../autogen/config/WORC.config_SampleProcessing_description.rst +**Defaults and Options:** +.. include:: ../autogen/config/WORC.config_SampleProcessing_defopts.rst +.. _config-Ensemble: Ensemble --------- +~~~~~~~~ WORC supports ensembling of workflows. This is not a default approach in radiomics, hence the default is to not use it and select only the best performing workflow. +**Description:** + +.. include:: ../autogen/config/WORC.config_Ensemble_description.rst + +**Defaults and Options:** + +.. include:: ../autogen/config/WORC.config_Ensemble_defopts.rst + + +.. _config-Bootstrap: +Bootstrap +~~~~~~~~~ +Besides cross validation, WORC supports bootstrapping on the test set for performance evaluation. +**Description:** +.. include:: ../autogen/config/WORC.config_Bootstrap_description.rst -FASTR_bugs ----------- -Currently, when using XNAT as a source, FASTR can only retrieve DICOM -directories. We made a workaround for this for the images and -segmentations, but this only works if all your files have the same name -and extension. These are provided in this configuration part. +**Defaults and Options:** +.. include:: ../autogen/config/WORC.config_Bootstrap_defopts.rst -.. include:: ../autogen/WORC.config.rst \ No newline at end of file diff --git a/WORC/doc/static/quick_start.rst b/WORC/doc/static/quick_start.rst index 47be8c5a..4a5b8106 100644 --- a/WORC/doc/static/quick_start.rst +++ b/WORC/doc/static/quick_start.rst @@ -10,6 +10,9 @@ Installation You can install WORC either using pip, or from the source code. +.. note:: The version of PyRadiomics which WORC currently uses requires numpy to be installed beforehand. Make sure you do so, e.g. ``pip install numpy``. + + Installing via pip `````````````````` @@ -47,35 +50,226 @@ library. For Ubuntu this is in the ``/usr/local/lib/python3.x/dist-packages/`` f .. note:: If you want to develop WORC, you might want to use ``pip install -e .`` to get an editable install -.. note:: You might want to consider installing ``WORC`` in a `virtualenv `_ - - -Configuration -------------- +.. note:: You might want to consider installing ``WORC`` in a + `virtualenv `_ -WORC has defaults for all settings so it can be run out of the box to test the examples. -However, you may want to alter the fastr configuration to your system settings, e.g. -to locate your input and output folders and how much you want to parallelize the execution. +Windows installation +```````````````````` -Fastr will search for a config file named ``config.py`` in the ``$FASTRHOME`` directory -(which defaults to ``~/.fastr/`` if it is not set). So if ``$FASTRHOME`` is set the ``~/.fastr/`` -will be ignored. Additionally, .py files from the ``$FASTRHOME/config.d`` folder will be parsed -as well. You will see that upon installation, WORC has already put a ``WORC_config.py`` file in the -``config.d`` folder. +On Windows, we strongly recommend to install python through the +`Anaconda distribution `_. -For a sample configuration file and a complete overview of the options in ``config.py`` see -the :ref:`Config file ` section. +Regardless of your installation, you will need `Microsoft Visual Studio `_: the Community +edition can be downloaded and installed for free. +If you still get an error similar to error: ``Microsoft Visual C++ 14.0 is required. Get it with`` +`Microsoft Visual C++ Build Tools `_ +, please follow the respective link and install the requirements. -Tutorial --------- -To start out using WORC, we recommend you to follow the tutorial located in the -[WORCTutorial Github](https://github.com/MStarmans91/WORCTutorial). Besides some more advanced tutorials, -the main tutorial can be found in the WORCTutorial.ipynb Jupyter notebook. Instructions on how -to use the notebook can be found in the Github. +Tutorials +--------- +To start out using WORC, we recommend you to follow the tutorials located in the +`WORCTutorial Github `_. This repository +contains tutorials for an introduction to WORC, as well as more advanced workflows. If you run into any issue, you can first debug your network using `the fastr trace tool `_. If you're stuck, feel free to post an issue on the `WORC Github `_. + +Hello World +------------ + +Below is the same script as found in the SimpleWORC tutorial found in the `WORCTutorial Github `_. + +Import packages +``````````````` + +First, import WORC and some additional python packages. + +.. code-block:: python + + from WORC import SimpleWORC + import os + + # These packages are only used in analysing the results + import pandas as pd + import json + import fastr + import glob + + # If you don't want to use your own data, we use the following example set, + # see also the next code block in this example. + from WORC.exampledata.datadownloader import download_HeadAndNeck + + # Define the folder this script is in, so we can easily find the example data + script_path = os.path.dirname(os.path.abspath(__file__)) + +Input +````` +The minimal inputs to WORC are: + + 1. Images + 2. Segmentations + 3. Labels + +In SimpleWORC, we assume you have a folder "datadir", in which there is a +folder for each patient, where in each folder there is a image.nii.gz and a mask.nii.gz: + + * Datadir + + * Patient_001 + + * image.nii.gz + * mask.nii.gz + + * Patient_002 + + * image.nii.gz + * mask.nii.gz + + * ... + +In the example, we will use open source data from the online +`BMIA XNAT platform `_ +This dataset consists of CT scans of patients with Head and Neck tumors. We will download +a subset of 20 patients in this folder. You can change this settings if you like. + +.. code-block:: python + + nsubjects = 20 # use "all" to download all patients + data_path = os.path.join(script_path, 'Data') + download_HeadAndNeck(datafolder=data_path, nsubjects=nsubjects) + +.. note:: You can skip this code block if you use your own data. + +Identify our data structure: change the fields below accordingly if you use your own dataset. + +.. code-block:: python + + imagedatadir = os.path.join(data_path, 'stwstrategyhn1') + image_file_name = 'image.nii.gz' + segmentation_file_name = 'mask.nii.gz' + + # File in which the labels (i.e. outcome you want to predict) is stated + # Again, change this accordingly if you use your own data. + label_file = os.path.join(data_path, 'Examplefiles', 'pinfo_HN.csv') + + # Name of the label you want to predict + label_name = 'imaginary_label_1' + + # Determine whether we want to do a coarse quick experiment, or a full lengthy + # one. Again, change this accordingly if you use your own data. + coarse = True + + # Give your experiment a name + experiment_name = 'Example_STWStrategyHN4' + + # Instead of the default tempdir, let's but the temporary output in a subfolder + # in the same folder as this script + tmpdir = os.path.join(script_path, 'WORC_' + experiment_name) + +The actual experiment +````````````````````` + +After defining the inputs, the following code can be used to run your first experiment. + +.. code-block:: python + + # Create a Simple WORC object + network = SimpleWORC(experiment_name) + + # Set the input data according to the variables we defined earlier + network.images_from_this_directory(imagedatadir, + image_file_name=image_file_name) + network.segmentations_from_this_directory(imagedatadir, + segmentation_file_name=segmentation_file_name) + network.labels_from_this_file(label_file) + network.predict_labels([label_name]) + + # Use the standard workflow for binary classification + network.binary_classification(coarse=coarse) + + # Set the temporary directory + experiment.set_tmpdir(tmpdir) + + # Run the experiment! + network.execute() + +.. note:: Precomputed features can be used instead of images and masks by instead using ``network.features_from_this_directory()`` in a similar fashion. + +Analysis of the results +``````````````````````` +There are two main outputs: the features for each patient/object, and the overall +performance. These are stored as .hdf5 and .json files, respectively. By +default, they are saved in the so-called "fastr output mount", in a subfolder +named after your experiment name. + +.. code-block:: python + + # Locate output folder + outputfolder = fastr.config.mounts['output'] + experiment_folder = os.path.join(outputfolder, 'WORC_' + experiment_name) + + print(f"Your output is stored in {experiment_folder}.") + + # Read the features for the first patient + # NOTE: we use the glob package for scanning a folder to find specific files + feature_files = glob.glob(os.path.join(experiment_folder, + 'Features', + 'features_*.hdf5')) + featurefile_p1 = feature_files[0] + features_p1 = pd.read_hdf(featurefile_p1) + + # Read the overall peformance + performance_file = os.path.join(experiment_folder, 'performance_all_0.json') + with open(performance_file, 'r') as fp: + performance = json.load(fp) + + # Print the feature values and names + print("Feature values:") + for v, l in zip(features_p1.feature_values, features_p1.feature_labels): + print(f"\t {l} : {v}.") + + # Print the output performance + print("\n Performance:") + stats = performance['Statistics'] + del stats['Percentages'] # Omitted for brevity + for k, v in stats.items(): + print(f"\t {k} {v}.") + +.. note:: the performance is probably horrible, which is expected as we ran the experiment on coarse settings. These settings are recommended to only use for testing: see also below. + + +Tips and Tricks +``````````````` + +For tips and tricks on running a full experiment instead of this simple +example, adding more evaluation options, debugging a crashed network etcetera, +please go to :ref:`usermanual-chapter` or follow the intermediate +or advanced tutorials on `WORCTutorial Github `_. + +Some things we would advice to always do: + +* Run actual experiments on the full settings (coarse=False): + +.. code-block:: python + + coarse = False + network.binary_classification(coarse=coarse) + +.. note:: This will result in more computation time. We therefore recommmend + to run this script on either a cluster or high performance PC. If so, + you may change the execution to use multiple cores to speed up computation + just before before ``experiment.execute()``: + + .. code-block:: python + + experiment.set_multicore_execution() + +* Add extensive evaluation: ``network.add_evaluation()`` before ``network.execute()``: + +.. code-block:: python + + network.add_evaluation() \ No newline at end of file diff --git a/WORC/doc/static/user_manual.rst b/WORC/doc/static/user_manual.rst index 1a5494bc..f84191ff 100644 --- a/WORC/doc/static/user_manual.rst +++ b/WORC/doc/static/user_manual.rst @@ -1,3 +1,5 @@ +.. usermanual-chapter: + User Manual =========== @@ -22,14 +24,12 @@ The WORC toolbox consists of one main object, the WORC object: It's attributes are split in a couple of categories. We will not discuss the WORC.defaultconfig() function here, which generates the default -configuration, as it is listed in a separate page, see the :ref:`config file section `. +configuration, as it is listed in a separate page, see the :doc:`config file section `. Attributes: Sources -------------------- - - +~~~~~~~~~~~~~~~~~~~ There are numerous WORC attributes which serve as source nodes for the FASTR network. These are: @@ -97,42 +97,8 @@ appending procedure can be used. did not supply a segmentation. **WORC will always align these sequences with no segmentations to the first sequence, i.e. the first object in the images_train list.** Hence make sure you supply the sequence for which you have a ROI as the first object. - - -Attributes: Settings --------------------- - - -There are several attributes in WORC which define how your pipeline is -executed: - - - -- fastr_plugin -- fastr_tmpdir -- Tools: additional workflows are stored here. Currently only includes - a pipeline for image registration without any Radiomics. -- CopyMetadata: Whether to automatically copy the metadata info - (e.g. direction of cosines) from the images to the segmentations - before applying transformix. - -An explanation of the FASTR settings is given below. - - - -Attributes: Functions ---------------------- - -The WORC.configs() attribute contains the configparser files, which you -can easily edit. The WORC.set() function saves these objects in a -temporary folder and converts the filename into as FASTR source, which -is then put in the WORC.fastrconfigs() objects. Hence you do not need to -edit the fastrconfigs object manually. - - - Images and segmentations -~~~~~~~~~~~~~~~~~~~~~~~~ +^^^^^^^^^^^^^^^^^^^^^^^^ @@ -148,7 +114,7 @@ image formats such as DICOM, NIFTI, TIFF, NRRD and MHD. Semantics -~~~~~~~~~ +^^^^^^^^^ Semantic features are used in the PREDICT CalcFeatures tool. You can supply these as a .csv listing your features per patient. The first @@ -183,7 +149,7 @@ case, your sources should look as following: Labels -~~~~~~ +^^^^^^ The labels are used in classification. For PREDICT, these should be supplied as a .txt file. Similar to the semantics, the first column @@ -193,7 +159,7 @@ semantics file. Masks ------------ +^^^^^ WORC contains a segmentation preprocessing tool, called segmentix. This tool is still under development. The idea is that you can manipulate @@ -204,7 +170,7 @@ radius around your ROI and mask it. Features --------- +^^^^^^^^ If you already computed your features, e.g. from a previous run, you can directly supply the features instead of the images and segmentations and @@ -213,7 +179,7 @@ matching the PREDICT CalcFeatures format. Metadata --------- +^^^^^^^^ This source can be used if you want to use tags from the DICOM header as features, e.g. patient age and sex. In this case, this source should @@ -224,7 +190,7 @@ implemented tags. Elastix_Para ------------- +^^^^^^^^^^^^ If you have multiple images for each patient, e.g. T1 and T2, but only a single segmentation, you can use image registration to align and @@ -237,9 +203,39 @@ is made on the first WORC.images source you supply. The segmentation will be alingned to all other image sources.** +Attributes: Settings +~~~~~~~~~~~~~~~~~~~~ + + +There are several attributes in WORC which define how your pipeline is +executed: + + + +- fastr_plugin +- fastr_tmpdir +- Tools: additional workflows are stored here. Currently only includes + a pipeline for image registration without any Radiomics. +- CopyMetadata: Whether to automatically copy the metadata info + (e.g. direction of cosines) from the images to the segmentations + before applying transformix. + +An explanation of the FASTR settings is given below. + + + +Attributes: Functions +~~~~~~~~~~~~~~~~~~~~~ + +The WORC.configs() attribute contains the configparser files, which you +can easily edit. The WORC.set() function saves these objects in a +temporary folder and converts the filename into as FASTR source, which +is then put in the WORC.fastrconfigs() objects. Hence you do not need to +edit the fastrconfigs object manually. + FASTR settings --------------- +~~~~~~~~~~~~~~ There are two WORC attributes which contain settings on running FASTR. In WORC.fastr_plugin, you can specify which Execution Plugin should be @@ -250,10 +246,8 @@ The default is the ProcessPollExecution plugin. The WORC.fastr_tempdir sets the temporary directory used in your run. - Construction and execution commands ------------------------------------ - +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ After supplying your sources, you need to build the FASTR network. This @@ -273,3 +267,101 @@ WORC.source_data_data and WORC.sink objects. Finally, after completing above steps, you can execute the network through the WORC.execute() command. + + +Evaluation of your network +-------------------------- + +In WORC, there are two options for testing your fitted models: + +1. Single dataset: cross-validation (currently only random-split) +2. Separate train and test dataset: bootstrapping on test dataset + +Within these evaluation settings, the following performance evaluation methods are used: + +1. Confidence intervals on several metrics: + + For classification: + + a) Area under the curve (AUC) of the receiver operating characteristic (ROC) curve. In a multiclass setting, weuse the multiclass AUC from the `TADPOLE Challenge `_. + b) Accuracy. + c) Balanced classification accuracy as defined by the `TADPOLE Challenge `_. + d) F1-score + e) Sensitivity, aka recall or true positive rate + f) Specificity, aka true negative rate + g) Negative predictive value (NPV) + h) Precision, aka Positive predictive value (PPV) + + For regression: + + a) R2-score + b) Mean Squared Error (MSE) + c) Intraclass Correlation Coefficient (ICC) + d) Pearson correlation coefficient and p-value + e) Spearmand correlation coefficient and p-value + + For survival, in addition to the regression scores: + a) Concordance index + b) Cox regression coefficient and p-value + + In cross-validation, by default, 95% confidence intervals for the mean performance measures are constructed using + the corrected resampled t-test base on all cross-validation iterations, thereby taking into account that the samples + in the cross-validation splits are not statistically independent. See als + `Nadeau C, Bengio Y. Inference for the generalization error. In Advances in Neural Information Processing Systems, 2000; 307–313.` + + In bootstrapping, 95% confidence intervals are created using the ''standard'' method according to a normal distribution: see Table 6, method 1 in `Efron B., Tibshirani R. Bootstrap Methods for Standard Errors, + Confidence Intervals, and Other Measures of Statistical Accuracy, Statistical Science Vol.1, No,1, 54-77, 1986`. + +2. ROC curve with 95% confidence intervals using the fixed-width bands method, see `Macskassy S. A., Provost F., Rosset S. ROC Confidence Bands: An Empirical Evaluation. In: Proceedings of the 22nd international conference on Machine learning. 2005.` + +3. Univariate statistical testing of the features using: + + a) A student t-test + b) A Welch test + c) A Wilcoxon test + d) A Mann-Whitney U test + + The uncorrected p-values for all these tests are reported in a single excel sheet. Pick the right test and significance + level based on your assumptions. Normally, we make use of the Mann-Whitney U test, as our features do not have to be normally + distributed, it's nonparametric, and assumes independent samples. + +4. Ranking patients from typical to atypical as determined by the model, based on either: + + a) The percentage of times a patient was classified correctly when occuring in the test set. Patients always correctly classified + can be seen as typical examples; patients always classified incorrectly as atypical. + b) The mean posterior of the patient when occuring in the test set. + + These measures can only be used in classification. Besides an Excel with the rankings, snapshots of the middle slice + of the image + segmentation are saved with the ground truth label and the percentage/posterior in the filename. In + this way, one can scroll through the patients from typical to atypical to distinguish a pattern. + +5. A barchart of how often certain features groups were selected in the optimal methods. Only useful when using + groupwise feature selection. + +By default, only the first evaluation method, e.g. metric computation, is used. The other methods can simply be added +to WORC by using the ``add_evaluation()`` function, either directly in WORC or through the facade: + + +.. code-block:: python + + import WORC + network = WORC.WORC('somename') + label_type = 'name_of_label_predicted_for_evaluation' + ... + network.add_evaluation(label_type) + +.. code-block:: python + + import WORC + from WORC import IntermediateFacade + I = IntermediateFacade('somename') + ... + I.add_evaluation() + +Debugging +--------- + +As WORC is based on fastr, debugging is similar to debugging a fastr pipeline: see therefore also +`the fastr debugging guidelines `_. + +If you run into any issue, please create an issue on the `WORC Github `_. \ No newline at end of file diff --git a/build/lib/WORC/IOparser/__init__.py b/WORC/exampledata/__init__.py similarity index 100% rename from build/lib/WORC/IOparser/__init__.py rename to WORC/exampledata/__init__.py diff --git a/WORC/exampledata/datadownloader.py b/WORC/exampledata/datadownloader.py new file mode 100644 index 00000000..ab705b5e --- /dev/null +++ b/WORC/exampledata/datadownloader.py @@ -0,0 +1,156 @@ +import xnat +import os +import sys +import shutil +from glob import glob + +from xnat.exceptions import XNATResponseError + + +def download_subject(project, subject, datafolder, session, verbose=False): + # Download all data and keep track of resources + download_counter = 0 + resource_labels = list() + for e in subject.experiments: + resmap = {} + experiment = subject.experiments[e] + + # FIXME: Need a way to smartly check whether we have a matching RT struct and image + # Current solution: We only download the CT sessions, no PET / MRI / Other scans + # Specific for STW Strategy BMIA XNAT projects + + if experiment.session_type is None: # some files in project don't have _CT postfix + print(f"\tSkipping patient {subject.label}, experiment {experiment.label}: type is not CT but {experiment.session_type}.") + continue + + if '_CT' not in experiment.session_type: + print(f"\tSkipping patient {subject.label}, experiment {experiment.label}: type is not CT but {experiment.session_type}.") + continue + + for s in experiment.scans: + scan = experiment.scans[s] + print(("\tDownloading patient {}, experiment {}, scan {}.").format(subject.label, experiment.label, + scan.id)) + for res in scan.resources: + resource_label = scan.resources[res].label + if resource_label == 'NIFTI': + # Create output directory + outdir = datafolder + '/{}'.format(subject.label) + if not os.path.exists(outdir): + os.makedirs(outdir) + + resmap[resource_label] = scan + print(f'resource is {resource_label}') + scan.resources[res].download_dir(outdir) + resource_labels.append(resource_label) + download_counter += 1 + + # Parse resources and throw warnings if they not meet the requirements + subject_name = subject.label + if download_counter == 0: + print(f'[WARNING] Skipping subject {subject_name}: no (suitable) resources found.') + return False + + if 'NIFTI' not in resource_labels: + print(f'[WARNING] Skipping subject {subject_name}: no NIFTI resources found.') + return False + + if resource_labels.count('NIFTI') < 2: + print(f'[WARNING] Skipping subject {subject_name}: only one NIFTI resource found, need two (mask and image).') + return False + elif resource_labels.count('NIFTI') > 2: + count = resource_labels.count('NIFTI') + print(f'[WARNING] Skipping subject {subject_name}: {str(count)} NIFTI resources found, need two (mask and image).') + return False + + # Check what the mask and image folders are + NIFTI_folders = glob(os.path.join(outdir, '*', 'scans', '*', 'resources', 'NIFTI', 'files')) + if 'mask' in glob(os.path.join(NIFTI_folders[0], '*.nii.gz'))[0]: + NIFTI_image_folder = NIFTI_folders[1] + NIFTI_mask_folder = NIFTI_folders[0] + else: + NIFTI_image_folder = NIFTI_folders[0] + NIFTI_mask_folder = NIFTI_folders[1] + + NIFTI_files = glob(os.path.join(NIFTI_image_folder, '*')) + if len(NIFTI_files) == 0: + print(f'[WARNING] Skipping subject {subject_name}: image NIFTI resources is empty.') + shutil.rmtree(outdir) + return False + + NIFTI_files = glob(os.path.join(NIFTI_mask_folder, '*')) + if len(NIFTI_files) == 0: + print(f'[WARNING] Skipping subject {subject_name}: mask NIFTI resources is empty.') + shutil.rmtree(outdir) + return False + + # Patient is included, so cleanup folder structure + os.rename(os.path.join(NIFTI_image_folder, 'image.nii.gz'), + os.path.join(outdir, 'image.nii.gz')) + os.rename(os.path.join(NIFTI_mask_folder, 'mask_GTV-1.nii.gz'), + os.path.join(outdir, 'mask.nii.gz')) + + for folder in glob(os.path.join(outdir, '*', 'scans')): + folder = os.path.dirname(folder) + shutil.rmtree(folder) + + return True + + +def download_project(project_name, xnat_url, datafolder, nsubjects=10, + verbose=True): + + # Connect to XNAT and retreive project + session = xnat.connect(xnat_url) + project = session.projects[project_name] + + # Create the data folder if it does not exist yet + datafolder = os.path.join(datafolder, project_name) + if not os.path.exists(datafolder): + os.makedirs(datafolder) + + subjects_len = len(project.subjects) + if nsubjects == 'all': + nsubjects = subjects_len + else: + nsubjects = min(nsubjects, subjects_len) + + subjects_counter = 1 + downloaded_subjects_counter = 0 + for s in range(0, subjects_len): + s = project.subjects[s] + print(f'Working on subject {subjects_counter}/{subjects_len}') + subjects_counter += 1 + + success = download_subject(project_name, s, datafolder, session, verbose) + if success: + downloaded_subjects_counter += 1 + + # Stop downloading if we have reached the required number of subjects + if downloaded_subjects_counter == nsubjects: + break + + # Disconnect the session + session.disconnect() + if downloaded_subjects_counter < nsubjects: + raise ValueError(f'Number of subjects downloaded {downloaded_subjects_counter} is smaller than the number required {nsubjects}.') + + print('Done downloading!') + + +def download_HeadAndNeck(datafolder=None, nsubjects=10): + if datafolder is None: + # Download data to path in which this script is located + Data + cwd = os.getcwd() + datafolder = os.path.join(cwd, 'Data') + if not os.path.exists(datafolder): + os.makedirs(datafolder) + + xnat_url = 'https://xnat.bmia.nl/' + project_name = 'stwstrategyhn1' + download_project(project_name, xnat_url, datafolder, nsubjects=nsubjects, + verbose=True) + + +if __name__ == '__main__': + download_HeadAndNeck() diff --git a/WORC/facade/__init__.py b/WORC/facade/__init__.py new file mode 100644 index 00000000..8d5b0a3c --- /dev/null +++ b/WORC/facade/__init__.py @@ -0,0 +1 @@ +from .simpleworc.simpleworc import SimpleWORC diff --git a/build/lib/WORC/classification/__init__.py b/WORC/facade/simpleworc/__init__.py similarity index 100% rename from build/lib/WORC/classification/__init__.py rename to WORC/facade/simpleworc/__init__.py diff --git a/WORC/facade/simpleworc/configbuilder.py b/WORC/facade/simpleworc/configbuilder.py new file mode 100644 index 00000000..990f9f79 --- /dev/null +++ b/WORC/facade/simpleworc/configbuilder.py @@ -0,0 +1,143 @@ +from WORC.detectors.detectors import BigrClusterDetector, CartesiusClusterDetector, DebugDetector +import configparser +import fastr + + +class ConfigBuilder(): + def __init__(self): + # initalize the main config object and the custom overrids + self._config = configparser.ConfigParser() + self._custom_overrides = {} + + # Detect when using a cluster and override relevant config fields + self._cluster_config_overrides() + + def build_config(self, defaultconfig): + defaultconfig.read_dict({**self._config}) + defaultconfig.read_dict({**self._custom_overrides}) + defaultconfig.read_dict({**self._debug_config_overrides()}) + + self._config = defaultconfig + return defaultconfig + + def custom_config_overrides(self, config): + self._custom_overrides.update(config) + + def _cluster_config_overrides(self): + if BigrClusterDetector().do_detection(): + overrides = { + 'General': {'Joblib_ncores': '1', + 'Joblib_backend': 'threading'}, + 'Classification': {'fastr': 'True', + 'fastr_plugin': 'DRMAAExecution'}, + 'HyperOptimization': {'n_jobspercore': '4000'} + } + elif CartesiusClusterDetector().do_detection(): + overrides = { + 'Classification': {'fastr': 'True', + 'fastr_plugin': 'ProcessPoolExecution'}, + 'HyperOptimization': {'n_jobspercore': '4000'} + } + else: + overrides = {} # not a cluster or unsupported + + self._custom_overrides.update(overrides) + return overrides + + def estimator_scoring_overrides(self, estimators, scoring_method): + overrides = { + 'Classification': {'classifiers': ', '.join(estimators)}, + 'HyperOptimization': {'scoring_method': scoring_method} + } + self._custom_overrides.update(overrides) + return overrides + + def coarse_overrides(self): + overrides = { + 'ImageFeatures': { + 'texture_Gabor': 'False', + 'vessel': 'False', + 'log': 'False', + 'phase': 'False', + }, + 'SelectFeatGroup': { + 'texture_Gabor_features': 'False', + 'log_features': 'False', + 'vessel_features': 'False', + 'phase_features': 'False', + }, + 'CrossValidation': {'N_iterations': '3'}, + 'HyperOptimization': {'N_iterations': '1000', + 'n_jobspercore': '500'}, + 'Ensemble': {'Use': '1'}, + 'SampleProcessing': {'SMOTE': 'False'}, + } + self._custom_overrides.update(overrides) + return overrides + + def full_overrides(self): + overrides = { + 'ImageFeatures': { + 'texture_Gabor': 'True', + 'vessel': 'True', + 'log': 'True', + 'phase': 'True', + }, + 'SelectFeatGroup': { + 'texture_Gabor_features': 'True, False', + 'log_features': 'True, False', + 'vessel_features': 'True, False', + 'phase_features': 'True, False', + }, + 'CrossValidation': {'N_iterations': '100'}, + 'HyperOptimization': {'N_iterations': '100000', + 'n_jobspercore': '4000'}, + 'Ensemble': {'Use': '50'}, + 'SampleProcessing': {'SMOTE': 'True'}, + } + self._custom_overrides.update(overrides) + return overrides + + def fullprint(self): + ''' + Print the full contents of the config to the console. + ''' + for k, v in self._config.items(): + print(f"{k}:") + for k2, v2 in v.items(): + print(f"\t {k2}: {v2}") + print("\n") + + def _debug_config_overrides(self): + if DebugDetector().do_detection(): + overrides = { + 'ImageFeatures': { + 'texture_Gabor': 'False', + 'vessel': 'False', + 'log': 'False', + 'phase': 'False', + 'texture_LBP': 'False', + 'texture_GLCMMS': 'False', + 'texture_GLRLM': 'False', + 'texture_NGTDM': 'False', + }, + 'SelectFeatGroup': { + 'texture_Gabor_features': 'False', + 'log_features': 'False', + 'vessel_features': 'False', + 'phase_features': 'False', + }, + 'CrossValidation': {'N_iterations': '2'}, + 'HyperOptimization': {'N_iterations': '10', + 'n_jobspercore': '10', + 'n_splits': '2'}, + 'Ensemble': {'Use': '1'}, + 'SampleProcessing': {'SMOTE': 'False'}, + } + + # Additionally, turn queue reporting system on + fastr.config.queue_report_interval = 120 + else: + overrides = {} # not a cluster or unsupported + + return overrides diff --git a/WORC/facade/simpleworc/exceptions.py b/WORC/facade/simpleworc/exceptions.py new file mode 100644 index 00000000..0c087c24 --- /dev/null +++ b/WORC/facade/simpleworc/exceptions.py @@ -0,0 +1,21 @@ +class InvalidOrderException(Exception): + def __init__(self, function, execute_first): + super(InvalidOrderException, self).__init__(f'Invalid order for function {path} call {execute_first} before calling this function') + +class InvalidCsvFileException(Exception): + def __init__(self, path): + super(InvalidCsvFileException, self).__init__(f'Invalid or unreadable csv file: {path}') + +class PathNotFoundException(Exception): + def __init__(self, path): + super(PathNotFoundException, self).__init__(f'Path not found: {path}') + + +class NoImagesFoundException(Exception): + def __init__(self, path): + super(NoImagesFoundException, self).__init__(f'No images found in directory {path}') + + +class NoSegmentationsFoundException(Exception): + def __init__(self, path): + super(NoSegmentationsFoundException, self).__init__(f'No segmentations found in directory {path}') diff --git a/WORC/facade/simpleworc/simpleworc.py b/WORC/facade/simpleworc/simpleworc.py new file mode 100644 index 00000000..757f076a --- /dev/null +++ b/WORC/facade/simpleworc/simpleworc.py @@ -0,0 +1,255 @@ +from WORC import WORC +import fastr.exceptions +from pathlib import Path +import inspect +from WORC.detectors.detectors import CsvDetector, BigrClusterDetector, CartesiusClusterDetector +from WORC.facade.simpleworc.configbuilder import ConfigBuilder +from .exceptions import PathNotFoundException, NoImagesFoundException, NoSegmentationsFoundException, \ + InvalidCsvFileException + + +def _for_all_methods(decorator): + def decorate(cls): + for attr in cls.__dict__: # there's propably a better way to do this + if callable(getattr(cls, attr)): + setattr(cls, attr, decorator(getattr(cls, attr))) + return cls + + return decorate + + +def _error_buldozer(func): + _valid_exceptions = [ + PathNotFoundException, NoImagesFoundException, + NoSegmentationsFoundException, InvalidCsvFileException, + TypeError, ValueError, NotImplementedError + ] + _valid_exceptions += [c[1] for c in inspect.getmembers(fastr.exceptions, inspect.isclass)] + + unexpected_exception_exception = Exception('A blackhole to another dimenstion has opened. This exception should never be thrown. Double check your code or make an issue on the WORC github so that we can fix this issue.') + + def dec(*args, **kwargs): + try: + func(*args, **kwargs) + except Exception as e: + if e.__class__ not in _valid_exceptions: + raise unexpected_exception_exception + raise e + return dec + + +@_for_all_methods(_error_buldozer) +class SimpleWORC(): + def __init__(self, name='WORC'): + # Set some config values + self._worc = WORC(name) + + self._images_train = [] + self._images_test = [] + self._segmentations_train = [] + self._segmentations_test = [] + self._semantics_file_train = None + self._semantics_file_test = None + + self._labels_file_train = None + self._labels_file_test = None + self._label_names = [] + + self._method = None + + self._config_builder = ConfigBuilder() + self._add_evaluation = False + + # Detect wether we are on a cluster + if BigrClusterDetector().do_detection(): + self._worc.fastr_plugin = 'DRMAAExecution' + elif CartesiusClusterDetector().do_detection(): + self._worc.fastr_plugin = 'ProcessPoolExecution' + + + def images_from_this_directory(self, directory, image_file_name='image.nii.gz', glob='*/', is_training=True): + directory = Path(directory).expanduser() + if not directory.exists(): + raise PathNotFoundException(directory) + + images = list(directory.glob(f'{glob}{image_file_name}')) + + if len(images) == 0: + raise NoImagesFoundException(f'{directory}{glob}{image_file_name}') + + images_per_subject = {image.parent.name: str(image.absolute()) for image in images} + if is_training: + self._images_train.append(images_per_subject) + else: + self._images_test.append(images_per_subject) + + def segmentations_from_this_directory(self, directory, segmentation_file_name='segmentation.nii.gz', glob='*/', + is_training=True): + directory = Path(directory).expanduser() + if not directory.exists(): + raise PathNotFoundException(directory) + + segmentations = list(directory.glob(f'{glob}{segmentation_file_name}')) + + if len(segmentations) == 0: + raise NoSegmentationsFoundException(str(directory)) + + segmentations_per_subject = {image.parent.name: str(image.absolute()) for image in segmentations} + if is_training: + self._segmentations_train.append(segmentations_per_subject) + else: + self._segmentations_test.append(segmentations_per_subject) + + def labels_from_this_file(self, file_path, is_training=True): + labels_file = Path(file_path).expanduser() + + if not labels_file.is_file(): + raise PathNotFoundException(file_path) + + if not CsvDetector(labels_file.absolute()): + raise InvalidCsvFileException(labels_file.absolute()) + + # TODO: implement sanity check labels file e.g. is it a labels file and are there labels available + if is_training: + self._labels_file_train = labels_file.absolute() + else: + self._labels_file_test = labels_file.absolute() + + def semantics_from_this_file(self, file_path, is_training=True): + semantics_file = Path(file_path).expanduser() + + if not semantics_file.is_file(): + raise PathNotFoundException(file_path) + + if not CsvDetector(semantics_file.absolute()): + raise InvalidCsvFileException(semantics_file.absolute()) + + # TODO: implement sanity check semantics file e.g. is it a semantics file and are there semantics available + if is_training: + self._semantics_file_train = semantics_file.absolute() + else: + self._semantics_file_test = semantics_file.absolute() + + def predict_labels(self, label_names: list): + if not self._labels_file_train: + raise ValueError('No labels file set trough labels_from_this_file') + + if not isinstance(label_names, list): + raise TypeError(f'label_names is of type {type(label_names)} while list is expected') + + for label in label_names: + if len(label.strip()) == 0: + raise ValueError('Invalid label, length = 0') + + # TODO: check if labels is in labels file + + # self._worc.label_names = ', '.join(label_names) + self._label_names = label_names + + def _set_and_validate_estimators(self, estimators, scoring_method, method, coarse): + # validate + if method == 'classification': + valid_estimators = ['SVM', 'RF', 'SGD', 'LR', 'GaussianNB', 'ComplementNB', 'LDA', 'QDA', 'RankedSVM'] + elif method == 'regression': + valid_estimators = ['SVR', 'RFR', 'ElasticNet', 'Lasso', 'SGDR'] + else: + valid_estimators = [] + + for estimator in estimators: + if estimator not in valid_estimators: + raise ValueError( + f'Invalid estimator {estimator} for {method}; must be one of {", ".join(valid_estimators)}') + + # TODO: sanity check scoring method per estimator + + # set + self._config_builder.estimator_scoring_overrides(estimators, scoring_method) + + if coarse: + self._config_builder.coarse_overrides() + else: + self._config_builder.full_overrides() + + self._method = method + + def _validate(self): + if not self._images_train: + pass # TODO: throw exception + + if not self._segmentations_train: + pass # TODO: throw exception + + if not self._labels_file_train: + pass # TODO: throw an exception + + if not self._label_names: + pass # TODO: throw exception + + if not self._method: + pass # TODO: throw exception + + if len(self._images_train) == len(self._segmentations_train): + for index, subjects_dict in enumerate(self._images_train): + try: + if subjects_dict.keys() != self._segmentations_train[index].keys(): + raise ValueError('Subjects in images_train and segmentations_train are not the same') + + # TODO: verify subjects in labels files as well + # TODO: peform same checks on images_test and segmentations_test if those are not None + except IndexError: + # this should never be thrown, but i put it here just in case + raise ValueError( + 'A blackhole to another dimenstion has opened. This exception should never be thrown. Double check your code or make an issue on the WORC github so that we can fix this issue.') + + def execute(self): + # this function is kind of like the build()-function in a builder, except it peforms execute on the object being built as well + self._validate() # do some final sanity checking before we execute the thing + + self._worc.images_train = self._images_train + self._worc.segmentations_train = self._segmentations_train + self._worc.labels_train = self._labels_file_train + self._worc.semantics_train = self._semantics_file_train + + if self._images_test: + self._worc.images_test = self._images_test + + if self._segmentations_test: + self._worc.segmentations_test = self._segmentations_test + + if self._labels_file_test: + self._worc.labels_test = self._labels_file_test + + self._worc.label_names = ', '.join(self._label_names) + self._config_builder._custom_overrides['Labels'] = dict() + self._config_builder._custom_overrides['Labels']['label_names'] = self._worc.label_names + + self._worc.configs = [self._config_builder.build_config(self._worc.defaultconfig())] + self._worc.build() + if self._add_evaluation: + self._worc.add_evaluation(label_type=self._label_names[self._selected_label]) + + self._worc.set() + self._worc.execute() + + def binary_classification(self, estimators=['SVM'], scoring_method='f1', coarse=True): + self._set_and_validate_estimators(estimators, scoring_method, 'classification', coarse) + + def regression(self, estimators=['SVR'], scoring_method='r2', coarse=True): + self._set_and_validate_estimators(estimators, scoring_method, 'regression', coarse) + + def survival(self, estimators, scoring_method, coarse=True): + raise NotImplementedError() + + def add_config_overrides(self, config): + self._config_builder.custom_config_overrides(config) + + def add_evaluation(self, selected_label=0): + self._add_evaluation = True + self._selected_label = 0 + + def set_tmpdir(self, tmpdir): + self._worc.fastr_tmpdir = tmpdir + + def set_multicore_execution(self): + self._worc.fastr_plugin = 'ProcessPoolExecution' + self._config_builder.custom_config_overrides['Classification']['fastr_plugin'] = 'ProcessPoolExecution' diff --git a/WORC/fastrconfig/WORC_config.py b/WORC/fastrconfig/WORC_config.py index 0445195e..51fb6e63 100644 --- a/WORC/fastrconfig/WORC_config.py +++ b/WORC/fastrconfig/WORC_config.py @@ -15,21 +15,15 @@ # See the License for the specific language governing permissions and # limitations under the License. - -import site import os -import sys - +import fastr +import pkg_resources # Get directory in which packages are installed -try: - packagedir = site.getsitepackages()[0] -except AttributeError: - # Inside virtualenvironment, so getsitepackages doesnt work. - paths = sys.path - for p in paths: - if os.path.isdir(p) and os.path.basename(p) == 'site-packages': - packagedir = p +working_set = pkg_resources.working_set +requirement_spec = pkg_resources.Requirement.parse('WORC') +egg_info = working_set.find(requirement_spec) +packagedir = egg_info.location # Add the WORC FASTR tools and type paths tools_path = [os.path.join(packagedir, 'WORC', 'resources', 'fastr_tools')] + tools_path diff --git a/WORC/featureprocessing/Decomposition.py b/WORC/featureprocessing/Decomposition.py new file mode 100644 index 00000000..dc519c00 --- /dev/null +++ b/WORC/featureprocessing/Decomposition.py @@ -0,0 +1,182 @@ +#!/usr/bin/env python + +# Copyright 2016-2019 Biomedical Imaging Group Rotterdam, Departments of +# Medical Informatics and Radiology, Erasmus MC, Rotterdam, The Netherlands +# +# 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 matplotlib +matplotlib.use('agg') +import matplotlib.pyplot as plt + +import numpy as np +import WORC.IOparser.config_io_classifier as config_io +import os +from WORC.trainclassifier import load_features +from sklearn.decomposition import PCA, SparsePCA, KernelPCA +from sklearn.manifold import TSNE + + +def Decomposition(features, patientinfo, config, output, label_type=None): + ''' + Perform a decomposition to two components of the feature space with various methods. + Useage is similar to StatisticalTestFeatures. + + Parameters + ---------- + features: string, mandatory + contains the paths to all .hdf5 feature files used. + modalityname1=file1,file2,file3,... modalityname2=file1,... + Thus, modalities names are always between a space and a equal + sign, files are split by commas. We assume that the lists of + files for each modality has the same length. Files on the + same position on each list should belong to the same patient. + + patientinfo: string, mandatory + Contains the path referring to a .txt file containing the + patient label(s) and value(s) to be used for learning. See + the Github Wiki for the format. + + config: string, mandatory + path referring to a .ini file containing the parameters + used for feature extraction. See the Github Wiki for the possible + fields and their description. + + # TODO: outputs + + verbose: boolean, default True + print final feature values and labels to command line or not. + + ''' + # Load variables from the config file + config = config_io.load_config(config) + + if type(patientinfo) is list: + patientinfo = ''.join(patientinfo) + + if type(config) is list: + config = ''.join(config) + + if type(output) is list: + output = ''.join(output) + + # Create output folder if required + if not os.path.exists(os.path.dirname(output)): + os.makedirs(os.path.dirname(output)) + + if label_type is not None: + label_type = config['Labels']['label_names'] + + # Read the features and classification data + print("Reading features and label data.") + label_data, image_features =\ + load_features(features, patientinfo, label_type) + + # Extract feature labels and put values in an array + feature_labels = image_features[0][1] + feature_values = np.zeros([len(image_features), len(feature_labels)]) + for num, x in enumerate(image_features): + feature_values[num, :] = x[0] + + # ----------------------------------------------------------------------- + # Perform decomposition + print("Performing decompositions.") + label_value = label_data['mutation_label'] + label_name = label_data['mutation_name'] + + # Reduce to two components for plotting + n_components = 2 + + for i_class, i_name in zip(label_value, label_name): + classlabels = i_class.ravel() + + class1 = [i for j, i in enumerate(feature_values) if classlabels[j] == 1] + class2 = [i for j, i in enumerate(feature_values) if classlabels[j] == 0] + + f = plt.figure() + + # ------------------------------------------------------- + # Fit PCA + pca = PCA(n_components=n_components) + pca.fit(feature_values) + explained_variance_ratio = pca.explained_variance_ratio_ + class1_pca = pca.transform(class1) + class2_pca = pca.transform(class2) + + # Plot PCA + ax = plt.subplot(2, 3, 1) + + plt.subplots_adjust(hspace=0.3, wspace=0.2) + ax.scatter(class1_pca[:, 0], class1_pca[:, 1], color='blue') + ax.scatter(class2_pca[:, 0], class2_pca[:, 1], color='green') + ax.set_title(('PCA: {} variance.').format(str(explained_variance_ratio))) + + # ------------------------------------------------------- + # Fit Sparse PCA + pca = SparsePCA(n_components=n_components) + pca.fit(feature_values) + class1_pca = pca.transform(class1) + class2_pca = pca.transform(class2) + + # Plot Sparse PCA + ax = plt.subplot(2, 3, 2) + + plt.subplots_adjust(hspace=0.3, wspace=0.2) + ax.scatter(class1_pca[:, 0], class1_pca[:, 1], color='blue') + ax.scatter(class2_pca[:, 0], class2_pca[:, 1], color='green') + ax.set_title('Sparse PCA.') + + # ------------------------------------------------------- + # Fit Kernel PCA + fnum = 3 + for kernel in ['linear', 'poly', 'rbf']: + pca = KernelPCA(n_components=n_components, kernel=kernel) + pca.fit(feature_values) + class1_pca = pca.transform(class1) + class2_pca = pca.transform(class2) + + # Plot Sparse PCA + ax = plt.subplot(2, 3, fnum) + + plt.subplots_adjust(hspace=0.3, wspace=0.2) + ax.scatter(class1_pca[:, 0], class1_pca[:, 1], color='blue') + ax.scatter(class2_pca[:, 0], class2_pca[:, 1], color='green') + ax.set_title(('Kernel PCA: {} .').format(kernel)) + fnum += 1 + + # ------------------------------------------------------- + # Fit t-SNE + tSNE = TSNE(n_components=n_components) + class_all = class1 + class2 + class_all_tsne = tSNE.fit_transform(class_all) + + class1_tSNE = class_all_tsne[0:len(class1)] + class2_tSNE = class_all_tsne[len(class1):] + + # Plot Sparse tSNE + ax = plt.subplot(2, 3, 6) + + plt.subplots_adjust(hspace=0.3, wspace=0.2) + ax.scatter(class1_tSNE[:, 0], class1_tSNE[:, 1], color='blue') + ax.scatter(class2_tSNE[:, 0], class2_tSNE[:, 1], color='green') + ax.set_title('t-SNE.') + + # ------------------------------------------------------- + # Maximize figure to get correct spacings + mng = plt.get_current_fig_manager() + mng.resize(*mng.window.maxsize()) + + # High DTI to make sure we save the maximized image + f.savefig(output, dpi=600) + print(("Decomposition saved as {} !").format(output)) + diff --git a/WORC/featureprocessing/StatisticalTestFeatures.py b/WORC/featureprocessing/StatisticalTestFeatures.py index 72437bef..8c2079f7 100644 --- a/WORC/featureprocessing/StatisticalTestFeatures.py +++ b/WORC/featureprocessing/StatisticalTestFeatures.py @@ -15,17 +15,16 @@ # See the License for the specific language governing permissions and # limitations under the License. - -import numpy as np -import PREDICT.IOparser.config_io_classifier as config_io import os -from scipy.stats import ttest_ind, ranksums, mannwhitneyu import csv -from PREDICT.trainclassifier import load_features +import numpy as np +from scipy.stats import ttest_ind, ranksums, mannwhitneyu +import WORC.IOparser.config_io_classifier as config_io +from WORC.classification.trainclassifier import load_features def StatisticalTestFeatures(features, patientinfo, config, output=None, - verbose=True): + verbose=True, label_type=None): ''' Perform several statistical tests on features, such as a student t-test. Useage is similar to trainclassifier. @@ -72,7 +71,8 @@ def StatisticalTestFeatures(features, patientinfo, config, output=None, if not os.path.exists(os.path.dirname(output)): os.makedirs(os.path.dirname(output)) - label_type = config['Genetics']['label_names'] + if label_type is None: + label_type = config['Labels']['label_names'] # Read the features and classification data print("Reading features and label data.") @@ -88,8 +88,8 @@ def StatisticalTestFeatures(features, patientinfo, config, output=None, # ----------------------------------------------------------------------- # Perform statistical tests print("Performing statistical tests.") - label_value = label_data['mutation_label'] - label_name = label_data['mutation_name'] + label_value = label_data['label'] + label_name = label_data['label_name'] header = list() subheader = list() @@ -110,7 +110,7 @@ def StatisticalTestFeatures(features, patientinfo, config, output=None, # Open the output file if output is not None: - myfile = open(output, 'wb') + myfile = open(output, 'w') wr = csv.writer(myfile, quoting=csv.QUOTE_ALL) wr.writerow(header) wr.writerow(subheader) @@ -140,10 +140,10 @@ def StatisticalTestFeatures(features, patientinfo, config, output=None, pvaluesmw.append(1) # Sort based on p-values: - pvalues = np.asarray(pvalues) - indices = np.argsort(pvalues) - pvalues = pvalues[indices].tolist() + indices = np.argsort(np.asarray(pvaluesmw)) feature_labels_o = np.asarray(feature_labels)[indices].tolist() + + pvalues = np.asarray(pvalues)[indices].tolist() pvalueswelch = np.asarray(pvalueswelch)[indices].tolist() pvalueswil = np.asarray(pvalueswil)[indices].tolist() pvaluesmw = np.asarray(pvaluesmw)[indices].tolist() diff --git a/WORC/featureprocessing/StatisticalTestThreshold.py b/WORC/featureprocessing/StatisticalTestThreshold.py index db551fc0..8e2bcf5a 100644 --- a/WORC/featureprocessing/StatisticalTestThreshold.py +++ b/WORC/featureprocessing/StatisticalTestThreshold.py @@ -71,17 +71,40 @@ def fit(self, X_train, Y_train): self.parameters = {} # Perform the statistical test for each feature + multilabel = type(Y_train[0]) is np.ndarray for n_feat in range(0, X_train.shape[1]): - fv = X_train[:, n_feat] - - class1 = [i for j, i in enumerate(fv) if Y_train[j] == 1] - class2 = [i for j, i in enumerate(fv) if Y_train[j] == 0] + # Select only this specific feature for all objects - try: - metric_value = self.metric_function(class1, class2, **self.parameters)[1] - except ValueError as e: - print("[PREDICT Warning] " + str(e) + '. Replacing metric value by 1.') - metric_value = 1 + fv = X_train[:, n_feat] + if multilabel: + # print('Multilabel: take minimum p-value for all label tests.') + # We do a statistical test per label and take the minimum p-value + n_label = Y_train[0].shape[0] + metric_values = list() + for i in range(n_label): + class1 = [i for j, i in enumerate(fv) if np.argmax(Y_train[j]) == n_label] + class2 = [i for j, i in enumerate(fv) if np.argmax(Y_train[j]) != n_label] + + try: + metric_value_temp = self.metric_function(class1, class2, **self.parameters)[1] + except ValueError as e: + print("[PREDICT Warning] " + str(e) + '. Replacing metric value by 1.') + metric_value_temp + + metric_values.append(metric_value_temp) + + metric_value = np.min(metric_values) + + else: + # Singlelabel + class1 = [i for j, i in enumerate(fv) if Y_train[j] == 1] + class2 = [i for j, i in enumerate(fv) if Y_train[j] == 0] + + try: + metric_value = self.metric_function(class1, class2, **self.parameters)[1] + except ValueError as e: + print("[PREDICT Warning] " + str(e) + '. Replacing metric value by 1.') + metric_value = 1 self.metric_values.append(metric_value) if metric_value < self.threshold: diff --git a/WORC/index.rst b/WORC/index.rst index 155c3206..a3569d4c 100644 --- a/WORC/index.rst +++ b/WORC/index.rst @@ -53,7 +53,7 @@ WORC has been used in the following studies: `Jose M. Castillo T., Martijn P. A. Starmans, Ivo Schoots, Wiro J. Niessen, Stefan Klein, Jifke F. Veenland. "CLASSIFICATION OF PROSTATE CANCER: HIGH GRADE VERSUS LOW GRADE USING A RADIOMICS APPROACH." IEEE International Symposium on Biomedical Imaging (ISBI) 2019. `_ -WORC is made possible by contributions from the following people: Martijn Starmans, and Stefan Klein +WORC is made possible by contributions from the following people: Martijn Starmans, Thomas Phil, and Stefan Klein WORC Documentation diff --git a/WORC/plotting/__init__.py b/WORC/plotting/__init__.py index e69de29b..3cbf9ef7 100644 --- a/WORC/plotting/__init__.py +++ b/WORC/plotting/__init__.py @@ -0,0 +1,2 @@ +import WORC.plotting.compute_CI, WORC.plotting.plot_barchart, WORC.plotting.plot_boxplot, WORC.plotting.plot_images, WORC.plotting.plot_ranked_scores +import WORC.plotting.plot_ROC, WORC.plotting.plot_SVM, WORC.plotting.scatterplot diff --git a/WORC/plotting/compute_CI.py b/WORC/plotting/compute_CI.py index 49253538..07075a9e 100644 --- a/WORC/plotting/compute_CI.py +++ b/WORC/plotting/compute_CI.py @@ -21,17 +21,35 @@ from scipy.special import logit, expit +def compute_confidence_bootstrap(bootstrap_metric, test_metric, N_1, alpha=0.95): + """ + Function to calculate confidence interval for bootstrapped samples. + metric: numpy array containing the result for a metric for the different bootstrap iterations + test_metric: the value of the metric evaluated on the true, full test set + alpha: float ranging from 0 to 1 to calculate the alpha*100% CI, default 0.95 + """ + metric_std = np.std(bootstrap_metric) + CI = st.norm.interval(alpha, loc=test_metric, scale=metric_std) + return CI + + def compute_confidence(metric, N_train, N_test, alpha=0.95): """ - Function to calculate the adjusted confidence interval + Function to calculate the adjusted confidence interval for cross-validation. metric: numpy array containing the result for a metric for the different cross validations (e.g. If 20 cross-validations are performed it is a list of length 20 with the calculated accuracy for each cross validation) N_train: Integer, number of training samples N_test: Integer, number of test_samples - alpha: float ranging from 0 to 1 to calculate the alpha*100% CI, default 95% + alpha: float ranging from 0 to 1 to calculate the alpha*100% CI, default 0.95 """ + # Remove NaN values if they are there + if np.isnan(metric).any(): + print('[WORC Warning] Array contains nan: removing.') + metric = np.asarray(metric) + metric = metric[np.logical_not(np.isnan(metric))] + # Convert to floats, as python 2 rounds the divisions if we have integers N_train = float(N_train) N_test = float(N_test) diff --git a/WORC/plotting/plot_ROC.py b/WORC/plotting/plot_ROC.py index 8591d0a1..da2f6414 100644 --- a/WORC/plotting/plot_ROC.py +++ b/WORC/plotting/plot_ROC.py @@ -52,7 +52,19 @@ def plot_single_ROC(y_truth, y_score, verbose=False): fprev = -np.inf i = 0 N = float(np.bincount(y_truth)[0]) - P = float(np.bincount(y_truth)[1]) + if len(np.bincount(y_truth)) == 1: + # No class = 1 present. + P = 0 + else: + P = float(np.bincount(y_truth)[1]) + + if N == 0: + print('[WORC Warning] No negative class samples found, cannot determine ROC. Skipping iteration.') + return fpr, tpr, thresholds + elif P == 0: + print('[WORC Warning] No positive class samples found, cannot determine ROC. Skipping iteration.') + return fpr, tpr, thresholds + while i < len(y_truth_sorted): if y_score[i] != fprev: fpr.append(1 - FP/N) @@ -130,10 +142,11 @@ def plot_ROC_CIc(y_truth, y_score, N_1, N_2, plot='default', alpha=0.95, thresholds = list() for yt, ys in zip(y_truth, y_score): fpr_temp, tpr_temp, thresholds_temp = plot_single_ROC(yt, ys) - roc_auc.append(roc_auc_score(yt, ys)) - fprt.append(fpr_temp) - tprt.append(tpr_temp) - thresholds.append(thresholds_temp) + if fpr_temp: + roc_auc.append(roc_auc_score(yt, ys)) + fprt.append(fpr_temp) + tprt.append(tpr_temp) + thresholds.append(thresholds_temp) # Sample FPR and TPR at numerous points fpr, tpr, th = ROC_thresholding(fprt, tprt, thresholds, tsamples) @@ -348,7 +361,7 @@ def plot_ROC(prediction, pinfo, ensemble=1, label_type=None, # Determine the predicted score per patient print('Determining score per patient.') - y_truths, y_scores, _, _ = plot_SVM(prediction, pinfo, label_type, + y_truths, y_scores, _, _ = plot_SVM(prediction, pinfo, [label_type], show_plots=False, alpha=0.95, ensemble=ensemble, output='decision') @@ -372,7 +385,7 @@ def plot_ROC(prediction, pinfo, ensemble=1, label_type=None, # Save ROC values as JSON if output_csv is not None: - with open(output_csv, 'wb') as csv_file: + with open(output_csv, 'w') as csv_file: writer = csv.writer(csv_file) writer.writerow(['FPR', 'TPR']) for i in range(0, len(fpr)): diff --git a/WORC/plotting/plot_SVM.py b/WORC/plotting/plot_SVM.py index 32c6593b..10b05634 100644 --- a/WORC/plotting/plot_SVM.py +++ b/WORC/plotting/plot_SVM.py @@ -18,19 +18,72 @@ import numpy as np import sys -import WORC.plotting.compute_CI as compute_CI +from WORC.plotting.compute_CI import compute_confidence +from WORC.plotting.compute_CI import compute_confidence_bootstrap import pandas as pd import os +import lifelines as ll import WORC.processing.label_processing as lp from WORC.classification import metrics import WORC.addexceptions as ae from sklearn.base import is_regressor +from collections import OrderedDict + + +def fit_thresholds(thresholds, estimator, X_train, Y_train, ensemble, ensemble_scoring): + print('Fitting thresholds on validation set') + if not hasattr(estimator, 'cv_iter'): + cv_iter = list(estimator.cv.split(X_train, Y_train)) + estimator.cv_iter = cv_iter + + p_est = estimator.cv_results_['params'][0] + p_all = estimator.cv_results_['params_all'][0] + n_iter = len(estimator.cv_iter) + + thresholds_low = list() + thresholds_high = list() + for it, (train, valid) in enumerate(estimator.cv_iter): + print(' - iteration {it + 1} / {n_iter}.') + # NOTE: Explicitly exclude validation set, elso refit and score + # somehow still seems to use it. + X_train_temp = [X_train[i] for i in train] + Y_train_temp = [Y_train[i] for i in train] + train_temp = range(0, len(train)) + + # Refit a SearchCV object with the provided parameters + if ensemble: + estimator.create_ensemble(X_train_temp, Y_train_temp, + method=ensemble, verbose=False, + scoring=ensemble_scoring) + else: + estimator.refit_and_score(X_train_temp, Y_train_temp, p_all, + p_est, train_temp, train_temp, + verbose=False) + + # Predict and save scores + X_train_values = [x[0] for x in X_train] # Throw away labels + X_train_values_valid = [X_train_values[i] for i in valid] + Y_valid_score_temp = estimator.predict_proba(X_train_values_valid) + + # Only take the probabilities for the second class + Y_valid_score_temp = Y_valid_score_temp[:, 1] + + # Select thresholds + thresholds_low.append(np.percentile(Y_valid_score_temp, thresholds[0]*100.0)) + thresholds_high.append(np.percentile(Y_valid_score_temp, thresholds[1]*100.0)) + + thresholds_val = [np.mean(thresholds_low), np.mean(thresholds_high)] + print(f'Thresholds {thresholds} converted to {thresholds_val}.') + return thresholds_val def plot_SVM(prediction, label_data, label_type, show_plots=False, alpha=0.95, ensemble=False, verbose=True, ensemble_scoring=None, output='stats', - modus='singlelabel'): + modus='singlelabel', + thresholds=None, survival=False, + generalization=False, shuffle_estimators=False, + bootstrap=False, bootstrap_N=1000): ''' Plot the output of a single binary estimator, e.g. a SVM. @@ -73,6 +126,11 @@ def plot_SVM(prediction, label_data, label_type, show_plots=False, Determine which results are put out. If stats, the statistics of the estimator will be returned. If scores, the scores will be returned. + thresholds: list of integer(s), default None + If None, use default threshold of sklearn (0.5) on posteriors to + converge to a binary prediction. If one integer is provided, use that one. + If two integers are provided, posterior < thresh[0] = 0, posterior > thresh[1] = 1. + Returns ---------- Depending on the output parameters, the following outputs are returned: @@ -93,7 +151,7 @@ def plot_SVM(prediction, label_data, label_type, show_plots=False, y_predictions: list Contains the predicted label for each object. - PIDs: list + pids: list Contains the patient ID/name for each object. ''' @@ -118,12 +176,14 @@ def plot_SVM(prediction, label_data, label_type, show_plots=False, label_type = [[label_type]] label_data = lp.load_labels(label_data, label_type) + n_labels = len(label_type) patient_IDs = label_data['patient_IDs'] labels = label_data['label'] if type(label_type) is list: # FIXME: Support for multiple label types not supported yet. print('[WORC Warning] Support for multiple label types not supported yet. Taking first label for plot_SVM.') + original_label_type = label_type[:] label_type = keys[0] # Extract the estimators, features and labels @@ -136,35 +196,98 @@ def plot_SVM(prediction, label_data, label_type, show_plots=False, feature_labels = prediction[label_type]['feature_labels'] # Create lists for performance measures - sensitivity = list() - specificity = list() - precision = list() - accuracy = list() - auc = list() - f1_score_list = list() + if not regression: + sensitivity = list() + specificity = list() + precision = list() + npv = list() + accuracy = list() + bca = list() + auc = list() + f1_score_list = list() + + if modus == 'multilabel': + acc_av = list() + + # Also add scoring measures for all single label scores + sensitivity_single = list() + specificity_single = list() + precision_single = list() + npv_single = list() + accuracy_single = list() + bca_single = list() + auc_single = list() + f1_score_list_single = list() + + else: + r2score = list() + MSE = list() + coefICC = list() + PearsonC = list() + PearsonP = list() + SpearmanC = list() + SpearmanP = list() + cindex = list() + coxcoef = list() + coxp = list() + patient_classification_list = dict() + percentages_selected = list() + if output in ['scores', 'decision']: # Keep track of all groundth truths and scores y_truths = list() y_scores = list() y_predictions = list() - PIDs = list() + pids = list() - # Loop over the test sets, which probably correspond with cross validation - # iterations - for i in range(0, len(Y_test)): + # Loop over the test sets, which correspond to cross-validation + # or bootstrapping iterations + if bootstrap: + iterobject = range(0, bootstrap_N) + else: + iterobject = range(0, len(Y_test)) + + for i in iterobject: print("\n") - print(("Cross validation {} / {}.").format(str(i + 1), str(len(Y_test)))) - test_patient_IDs = prediction[label_type]['patient_ID_test'][i] - train_patient_IDs = prediction[label_type]['patient_ID_train'][i] - X_test_temp = X_test[i] - X_train_temp = X_train[i] - Y_train_temp = Y_train[i] - Y_test_temp = Y_test[i] + if bootstrap: + print(f"Bootstrap {i + 1} / {bootstrap_N}.") + else: + print(f"Cross validation {i + 1} / {len(Y_test)}.") + test_indices = list() + # When bootstrapping, there is only a single train/test set. + if bootstrap: + X_test_temp = X_test[0] + X_train_temp = X_train[0] + Y_train_temp = Y_train[0] + Y_test_temp = Y_test[0] + test_patient_IDs = prediction[label_type]['patient_ID_test'][0] + train_patient_IDs = prediction[label_type]['patient_ID_train'][0] + fitted_model = SVMs[0] + else: + X_test_temp = X_test[i] + X_train_temp = X_train[i] + Y_train_temp = Y_train[i] + Y_test_temp = Y_test[i] + test_patient_IDs = prediction[label_type]['patient_ID_test'][i] + train_patient_IDs = prediction[label_type]['patient_ID_train'][i] + fitted_model = SVMs[i] + + # If bootstrap, generate a bootstrapped sample + if bootstrap: + X_test_temp, Y_test_temp, test_patient_IDs = resample(X_test_temp, Y_test_temp, test_patient_IDs) + # Check which patients are in the test set. for i_ID in test_patient_IDs: + if i_ID not in patient_IDs: + print(f'[WORC WARNING] Patient {i_ID} is not found the patient labels, removing underscore.') + i_ID = np.where(patient_IDs == i_ID.split("_")[0]) + if i_ID not in patient_IDs: + print(f'[WORC WARNING] Did not help, excluding patient {i_ID}.') + continue + test_indices.append(np.where(patient_IDs == i_ID)[0][0]) # Initiate counting how many times a patient is classified correctly @@ -179,26 +302,81 @@ def plot_SVM(prediction, label_data, label_type, show_plots=False, # Extract ground truth y_truth = Y_test_temp + # If required, shuffle estimators for "Random" ensembling + if shuffle_estimators: + # Compute generalization score + print('Shuffling estimators for random ensembling.') + shuffle(fitted_model.cv_results_['params']) + shuffle(fitted_model.cv_results_['params_all']) + + # If required, rank according to generalization score instead of mean_validation_score + if generalization: + # Compute generalization score + print('Using generalization score for estimator ranking.') + difference_score = abs(fitted_model.cv_results_['mean_train_score'] - fitted_model.cv_results_['mean_test_score']) + generalization_score = fitted_model.cv_results_['mean_test_score'] - difference_score + + # Rerank based on score + indices = np.argsort(generalization_score) + fitted_model.cv_results_['params'] = [fitted_model.cv_results_['params'][i] for i in indices[::-1]] + fitted_model.cv_results_['params_all'] = [fitted_model.cv_results_['params_all'][i] for i in indices[::-1]] + # If requested, first let the SearchCV object create an ensemble - if ensemble: + if bootstrap and i > 0: + # For bootstrapping, only do this at the first iteration + pass + elif ensemble > 1: # NOTE: Added for backwards compatability - if not hasattr(SVMs[i], 'cv_iter'): - cv_iter = list(SVMs[i].cv.split(X_train_temp, Y_train_temp)) - SVMs[i].cv_iter = cv_iter + if not hasattr(fitted_model, 'cv_iter'): + cv_iter = list(fitted_model.cv.split(X_train_temp, Y_train_temp)) + fitted_model.cv_iter = cv_iter # Create the ensemble X_train_temp = [(x, feature_labels) for x in X_train_temp] - SVMs[i].create_ensemble(X_train_temp, Y_train_temp, + fitted_model.create_ensemble(X_train_temp, Y_train_temp, method=ensemble, verbose=verbose, scoring=ensemble_scoring) # Create prediction - y_prediction = SVMs[i].predict(X_test_temp) + y_prediction = fitted_model.predict(X_test_temp) if regression: y_score = y_prediction + elif modus == 'multilabel': + y_score = fitted_model.predict_proba(X_test_temp) else: - y_score = SVMs[i].predict_proba(X_test_temp)[:, 1] + y_score = fitted_model.predict_proba(X_test_temp)[:, 1] + + # Create a new binary score based on the thresholds if given + if thresholds is not None: + if len(thresholds) == 1: + y_prediction = y_score >= thresholds[0] + elif len(thresholds) == 2: + # X_train_temp = [x[0] for x in X_train_temp] + + y_score_temp = list() + y_prediction_temp = list() + y_truth_temp = list() + test_patient_IDs_temp = list() + + thresholds_val = fit_thresholds(thresholds, fitted_model, X_train_temp, Y_train_temp, ensemble, + ensemble_scoring) + for pnum in range(len(y_score)): + if y_score[pnum] <= thresholds_val[0] or y_score[pnum] > thresholds_val[1]: + y_score_temp.append(y_score[pnum]) + y_prediction_temp.append(y_prediction[pnum]) + y_truth_temp.append(y_truth[pnum]) + test_patient_IDs_temp.append(test_patient_IDs[pnum]) + + perc = float(len(y_prediction_temp))/float(len(y_prediction)) + percentages_selected.append(perc) + print(f"Selected {len(y_prediction_temp)} from {len(y_prediction)} ({perc}%) patients using two thresholds.") + y_score = y_score_temp + y_prediction = y_prediction_temp + y_truth = y_truth_temp + test_patient_IDs = test_patient_IDs_temp + else: + raise ae.WORCValueError(f"Need None, one or two thresholds on the posterior; got {len(thresholds)}.") print("Truth: " + str(y_truth)) print("Prediction: " + str(y_prediction)) @@ -215,21 +393,19 @@ def plot_SVM(prediction, label_data, label_type, show_plots=False, else: patient_classification_list[i_test_ID]['N_wrong'] += 1 - y_score = SVMs[i].predict_proba(X_test_temp)[:, 1] - if output == 'decision': # Output the posteriors y_scores.append(y_score) y_truths.append(y_truth) y_predictions.append(y_prediction) - PIDs.append(test_patient_IDs) + pids.append(test_patient_IDs) elif output == 'scores': # Output the posteriors y_scores.append(y_score) y_truths.append(y_truth) y_predictions.append(y_prediction) - PIDs.append(test_patient_IDs) + pids.append(test_patient_IDs) elif output == 'stats': # Compute statistics @@ -237,15 +413,17 @@ def plot_SVM(prediction, label_data, label_type, show_plots=False, if modus == 'singlelabel': # Compute singlelabel performance metrics if not regression: - accuracy_temp, sensitivity_temp, specificity_temp,\ - precision_temp, f1_score_temp, auc_temp =\ + accuracy_temp, bca_temp, sensitivity_temp,\ + specificity_temp,\ + precision_temp, npv_temp, f1_score_temp, auc_temp =\ metrics.performance_singlelabel(y_truth, y_prediction, y_score, regression) else: - r2score, MSE, coefICC, PearsonC, PearsonP, SpearmanC,\ - SpearmanP =\ + r2score_temp, MSE_temp, coefICC_temp, PearsonC_temp,\ + PearsonP_temp, SpearmanC_temp,\ + SpearmanP_temp =\ metrics.performance_singlelabel(y_truth, y_prediction, y_score, @@ -269,157 +447,297 @@ def plot_SVM(prediction, label_data, label_type, show_plots=False, # Compute multilabel performance metrics accuracy_temp, sensitivity_temp, specificity_temp,\ - precision_temp, f1_score_temp, auc_temp =\ + precision_temp, npv_temp, f1_score_temp, auc_temp, acc_av_temp =\ metrics.performance_multilabel(y_truth, y_prediction, y_score) + # Compute all single label performance metrics as well + for i_label in range(n_labels): + y_truth_single = [i == i_label for i in y_truth] + y_prediction_single = [i == i_label for i in y_prediction] + y_score_single = y_score[:, i_label] + + accuracy_temp_single, bca_temp_single, sensitivity_temp_single, specificity_temp_single,\ + precision_temp_single, npv_temp_single, f1_score_temp_single, auc_temp_single =\ + metrics.performance_singlelabel(y_truth_single, + y_prediction_single, + y_score_single, + regression) + else: - raise ae.WORCKeyError('{} is not a valid modus!').format(modus) + raise ae.WORCKeyError('{modus} is not a valid modus!') # Print AUC to keep you up to date - print('AUC: ' + str(auc_temp)) + if not regression: + print('AUC: ' + str(auc_temp)) + + # Append performance to lists for all cross validations + accuracy.append(accuracy_temp) + bca.append(bca_temp) + sensitivity.append(sensitivity_temp) + specificity.append(specificity_temp) + auc.append(auc_temp) + f1_score_list.append(f1_score_temp) + precision.append(precision_temp) + npv.append(npv_temp) + + if modus == 'multilabel': + acc_av.append(acc_av_temp) + + accuracy_single.append(accuracy_temp_single) + bca_single.append(bca_temp_single) + sensitivity_single.append(sensitivity_temp_single) + specificity_single.append(specificity_temp_single) + auc_single.append(auc_temp_single) + f1_score_list_single.append(f1_score_temp_single) + precision_single.append(precision_temp_single) + npv_single.append(npv_temp_single) + + else: + print('R2 Score: ' + str(r2score_temp)) + + r2score.append(r2score_temp) + MSE.append(MSE_temp) + coefICC.append(coefICC_temp) + PearsonC.append(PearsonC_temp) + PearsonP.append(PearsonP_temp) + SpearmanC.append(SpearmanC_temp) + SpearmanP.append(SpearmanP_temp) + + if survival: + # Extract time to event and event from label data + E_truth = np.asarray([labels[1][k][0] for k in test_indices]) + T_truth = np.asarray([labels[2][k][0] for k in test_indices]) + + # Concordance index + cindex.append(1 - ll.utils.concordance_index(T_truth, y_prediction, E_truth)) + + # Fit Cox model using SVR output, time to event and event + data = {'predict': y_prediction, 'E': E_truth, 'T': T_truth} + data = pd.DataFrame(data=data, index=test_patient_IDs) + + cph = ll.CoxPHFitter() + cph.fit(data, duration_col='T', event_col='E') - # Append performance to lists for all cross validations - accuracy.append(accuracy_temp) - sensitivity.append(sensitivity_temp) - specificity.append(specificity_temp) - auc.append(auc_temp) - f1_score_list.append(f1_score_temp) - precision.append(precision_temp) + coxcoef.append(cph.summary['coef']['predict']) + coxp.append(cph.summary['p']['predict']) if output in ['scores', 'decision']: # Return the scores and true values of all patients - return y_truths, y_scores, y_predictions, PIDs + return y_truths, y_scores, y_predictions, pids elif output == 'stats': # Compute statistics # Extract sample size N_1 = float(len(train_patient_IDs)) N_2 = float(len(test_patient_IDs)) - # Compute alpha confidence intervallen + # Compute alpha confidence intervals (CIs) stats = dict() - stats["Accuracy 95%:"] = str(compute_CI.compute_confidence(accuracy, N_1, N_2, alpha)) - - stats["AUC 95%:"] = str(compute_CI.compute_confidence(auc, N_1, N_2, alpha)) - - stats["F1-score 95%:"] = str(compute_CI.compute_confidence(f1_score_list, N_1, N_2, alpha)) - - stats["Precision 95%:"] = str(compute_CI.compute_confidence(precision, N_1, N_2, alpha)) + if not regression: + if bootstrap: + # Compute once for the real test set the performance + X_test_temp = X_test[0] + y_truth = Y_test[0] + y_prediction = fitted_model.predict(X_test_temp) + + if regression: + y_score = y_prediction + else: + y_score = fitted_model.predict_proba(X_test_temp)[:, 1] + + accuracy_test, bca_test, sensitivity_test, specificity_test,\ + precision_test, npv_test, f1_score_test, auc_test =\ + metrics.performance_singlelabel(y_truth, + y_prediction, + y_score, + regression) + + stats["Accuracy 95%:"] = f"{accuracy_test} {str(compute_confidence_bootstrap(accuracy, accuracy_test, N_1, alpha))}" + stats["BCA 95%:"] = f"{bca_test} {str(compute_confidence_bootstrap(bca, bca_test, N_1, alpha))}" + stats["AUC 95%:"] = f"{auc_test} {str(compute_confidence_bootstrap(auc, auc_test, N_1, alpha))}" + stats["F1-score 95%:"] = f"{f1_score_list_test} {str(compute_confidence_bootstrap(f1_score_list, f1_score_test, N_1, alpha))}" + stats["Precision 95%:"] = f"{precision_test} {str(compute_confidence_bootstrap(precision, precision_test, N_1, alpha))}" + stats["NPV 95%:"] = f"{npv_test} {str(compute_confidence_bootstrap(npv, npv_test, N_1, alpha))}" + stats["Sensitivity 95%: "] = f"{sensitivity_test} {str(compute_confidence_bootstrap(sensitivity, sensitivity_test, N_1, alpha))}" + stats["Specificity 95%:"] = f"{specificity_test} {str(compute_confidence_bootstrap(specificity, specificity_test, N_1, alpha))}" + else: + stats["Accuracy 95%:"] = f"{np.nanmean(accuracy)} {str(compute_confidence(accuracy, N_1, N_2, alpha))}" + stats["BCA 95%:"] = f"{np.nanmean(bca)} {str(compute_confidence(bca, N_1, N_2, alpha))}" + stats["AUC 95%:"] = f"{np.nanmean(auc)} {str(compute_confidence(auc, N_1, N_2, alpha))}" + stats["F1-score 95%:"] = f"{np.nanmean(f1_score_list)} {str(compute_confidence(f1_score_list, N_1, N_2, alpha))}" + stats["Precision 95%:"] = f"{np.nanmean(precision)} {str(compute_confidence(precision, N_1, N_2, alpha))}" + stats["NPV 95%:"] = f"{np.nanmean(npv)} {str(compute_confidence(npv, N_1, N_2, alpha))}" + stats["Sensitivity 95%: "] = f"{np.nanmean(sensitivity)} {str(compute_confidence(sensitivity, N_1, N_2, alpha))}" + stats["Specificity 95%:"] = f"{np.nanmean(specificity)} {str(compute_confidence(specificity, N_1, N_2, alpha))}" - stats["Sensitivity 95%: "] = str(compute_CI.compute_confidence(sensitivity, N_1, N_2, alpha)) + if modus == 'multilabel': + stats["Average Accuracy 95%:"] = f"{np.nanmean(acc_av)} {str(compute_confidence(acc_av, N_1, N_2, alpha))}" + + if thresholds is not None: + if len(thresholds) == 2: + # Compute percentage of patients that was selected + stats["Percentage Selected 95%:"] = f"{np.nanmean(percentages_selected)} {str(compute_confidence(percentages_selected, N_1, N_2, alpha))}" + + # Extract statistics on how often patients got classified correctly + alwaysright = dict() + alwayswrong = dict() + percentages = dict() + for i_ID in patient_classification_list: + percentage_right = patient_classification_list[i_ID]['N_correct'] / float(patient_classification_list[i_ID]['N_test']) + + if i_ID in patient_IDs: + label = labels[0][np.where(i_ID == patient_IDs)] + else: + # Multiple instance of one patient + label = labels[0][np.where(i_ID.split('_')[0] == patient_IDs)] + + label = label[0][0] + percentages[i_ID] = str(label) + ': ' + str(round(percentage_right, 2) * 100) + '%' + if percentage_right == 1.0: + alwaysright[i_ID] = label + print(f"Always Right: {i_ID}, label {label}.") + + elif percentage_right == 0: + alwayswrong[i_ID] = label + print(f"Always Wrong: {i_ID}, label {label}.") + + stats["Always right"] = alwaysright + stats["Always wrong"] = alwayswrong + stats['Percentages'] = percentages + else: + # Regression + stats['R2-score 95%: '] = f"{np.nanmean(r2_score)} {str(compute_confidence(r2score, N_1, N_2, alpha))}" + stats['MSE 95%: '] = f"{np.nanmean(MSE)} {str(compute_confidence(MSE, N_1, N_2, alpha))}" + stats['ICC 95%: '] = f"{np.nanmean(coefICC)} {str(compute_confidence(coefICC, N_1, N_2, alpha))}" + stats['PearsonC 95%: '] = f"{np.nanmean(PearsonC)} {str(compute_confidence(PearsonC, N_1, N_2, alpha))}" + stats['PearsonP 95%: '] = f"{np.nanmean(PearsonP)} {str(compute_confidence(PearsonP, N_1, N_2, alpha))}" + stats['SpearmanC 95%: '] = f"{np.nanmean(SpearmanC)} {str(compute_confidence(SpearmanC, N_1, N_2, alpha))}" + stats['SpearmanP 95%: '] = f"{np.nanmean(SpearmanP)} {str(compute_confidence(SpearmanP, N_1, N_2, alpha))}" + + if survival: + stats["Concordance 95%:"] = f"{np.nanmean(cindex)} {str(compute_confidence(cindex, N_1, N_2, alpha))}" + stats["Cox coef. 95%:"] = f"{np.nanmean(coxcoef)} {str(compute_confidence(coxcoef, N_1, N_2, alpha))}" + stats["Cox p 95%:"] = f"{np.nanmean(coxp)} {str(compute_confidence(coxp, N_1, N_2, alpha))}" + + # Print all CI's + stats = OrderedDict(sorted(stats.items())) + for k, v in stats.items(): + print(f"{k} : {v}.") - stats["Specificity 95%:"] = str(compute_CI.compute_confidence(specificity, N_1, N_2, alpha)) + return stats - print("Accuracy 95%:" + str(compute_CI.compute_confidence(accuracy, N_1, N_2, alpha))) - print("AUC 95%:" + str(compute_CI.compute_confidence(auc, N_1, N_2, alpha))) +def combine_multiple_estimators(predictions, label_data, multilabel_type, label_types, + ensemble=1, strategy='argmax', alpha=0.95): + ''' + Combine multiple estimators in a single model. - print("F1-score 95%:" + str(compute_CI.compute_confidence(f1_score_list, N_1, N_2, alpha))) + Note: the multilabel_type labels should correspond to the ordering in label_types. + Hence, if multilabel_type = 0, the prediction is label_type[0] etc. + ''' - print("Precision 95%:" + str(compute_CI.compute_confidence(precision, N_1, N_2, alpha))) + # Load the multilabel label data + label_data = lp.load_labels(label_data, multilabel_type) + patient_IDs = label_data['patient_IDs'] + labels = label_data['label'] - print("Sensitivity 95%: " + str(compute_CI.compute_confidence(sensitivity, N_1, N_2, alpha))) + # Initialize some objects + y_truths = list() + y_scores = list() + y_predictions = list() + pids = list() - print("Specificity 95%:" + str(compute_CI.compute_confidence(specificity, N_1, N_2, alpha))) + y_truths_train = list() + y_scores_train = list() + y_predictions_train = list() + pids_train = list() - # Extract statistics on how often patients got classified correctly - alwaysright = dict() - alwayswrong = dict() - percentages = dict() - for i_ID in patient_classification_list: - percentage_right = patient_classification_list[i_ID]['N_correct'] / float(patient_classification_list[i_ID]['N_test']) + accuracy = list() + sensitivity = list() + specificity = list() + auc = list() + f1_score_list = list() + precision = list() + npv = list() + acc_av = list() + + # Extract all the predictions from the estimators + for prediction, label_type in zip(predictions, label_types): + y_truth, y_score, y_prediction, pid,\ + y_truth_train, y_score_train, y_prediction_train, pid_train =\ + plot_SVM(prediction, label_data, label_type, + ensemble=ensemble, output='allscores') + y_truths.append(y_truth) + y_scores.append(y_score) + y_predictions.append(y_prediction) + pids.append(pid) + + y_truths_train.append(y_truth_train) + y_scores_train.append(y_score_train) + y_predictions_train.append(y_prediction_train) + pids_train.append(pid_train) + + # Combine the predictions + for i_crossval in range(0, len(y_truths[0])): + # Extract all values for this cross validation iteration from all objects + y_truth = [t[i_crossval] for t in y_truths] + y_score = [t[i_crossval] for t in y_scores] + pid = [t[i_crossval] for t in pids] + + if strategy == 'argmax': + # For each patient, take the maximum posterior + y_prediction = np.argmax(y_score, axis=0) + y_score = np.max(y_score, axis=0) + elif strategy == 'decisiontree': + # Fit a decision tree on the training set + a = 1 + else: + raise ae.WORCValueError(f"{strategy} is not a valid estimation combining strategy! Should be one of [argmax].") - if i_ID in patient_IDs: - label = labels[0][np.where(i_ID == patient_IDs)] - else: - # Multiple instance of one patient - label = labels[0][np.where(i_ID.split('_')[0] == patient_IDs)] - - label = label[0][0] - percentages[i_ID] = str(label) + ': ' + str(round(percentage_right, 2) * 100) + '%' - if percentage_right == 1.0: - alwaysright[i_ID] = label - print(("Always Right: {}, label {}").format(i_ID, label)) - - elif percentage_right == 0: - alwayswrong[i_ID] = label - print(("Always Wrong: {}, label {}").format(i_ID, label)) - - stats["Always right"] = alwaysright - stats["Always wrong"] = alwayswrong - stats['Percentages'] = percentages - - if show_plots: - # Plot some characteristics in boxplots - import matplotlib.pyplot as plt - - plt.figure() - plt.boxplot(accuracy) - plt.ylim([-0.05, 1.05]) - plt.ylabel('Accuracy') - plt.tick_params( - axis='x', # changes apply to the x-axis - which='both', # both major and minor ticks are affected - bottom='off', # ticks along the bottom edge are off - top='off', # ticks along the top edge are off - labelbottom='off') # labels along the bottom edge are off - plt.tight_layout() - plt.show() - - plt.figure() - plt.boxplot(auc) - plt.ylim([-0.05, 1.05]) - plt.ylabel('AUC') - plt.tick_params( - axis='x', # changes apply to the x-axis - which='both', # both major and minor ticks are affected - bottom='off', # ticks along the bottom edge are off - top='off', # ticks along the top edge are off - labelbottom='off') # labels along the bottom edge are off - plt.tight_layout() - plt.show() - - plt.figure() - plt.boxplot(precision) - plt.ylim([-0.05, 1.05]) - plt.ylabel('Precision') - plt.tick_params( - axis='x', # changes apply to the x-axis - which='both', # both major and minor ticks are affected - bottom='off', # ticks along the bottom edge are off - top='off', # ticks along the top edge are off - labelbottom='off') # labels along the bottom edge are off - plt.tight_layout() - plt.show() - - plt.figure() - plt.boxplot(sensitivity) - plt.ylim([-0.05, 1.05]) - plt.ylabel('Sensitivity') - plt.tick_params( - axis='x', # changes apply to the x-axis - which='both', # both major and minor ticks are affected - bottom='off', # ticks along the bottom edge are off - top='off', # ticks along the top edge are off - labelbottom='off') # labels along the bottom edge are off - plt.tight_layout() - plt.show() - - plt.figure() - plt.boxplot(specificity) - plt.ylim([-0.05, 1.05]) - plt.ylabel('Specificity') - plt.tick_params( - axis='x', # changes apply to the x-axis - which='both', # both major and minor ticks are affected - bottom='off', # ticks along the bottom edge are off - top='off', # ticks along the top edge are off - labelbottom='off') # labels along the bottom edge are off - plt.tight_layout() - plt.show() + # Compute multilabel performance metrics + y_truth = np.argmax(y_truth, axis=0) + accuracy_temp, sensitivity_temp, specificity_temp, \ + precision_temp, npv_temp, f1_score_temp, auc_temp, accav_temp = \ + metrics.performance_multilabel(y_truth, + y_prediction, + y_score) - return stats + print("Truth: " + str(y_truth)) + print("Prediction: " + str(y_prediction)) + print('AUC: ' + str(auc_temp)) + + # Append performance to lists for all cross validations + accuracy.append(accuracy_temp) + sensitivity.append(sensitivity_temp) + specificity.append(specificity_temp) + auc.append(auc_temp) + f1_score_list.append(f1_score_temp) + precision.append(precision_temp) + npv.append(npv_temp) + acc_av.append(acc_av_temp) + + # Extract sample size + N_1 = float(len(train_patient_IDs)) + N_2 = float(len(test_patient_IDs)) + + # Compute confidence intervals + stats = dict() + stats["Accuracy 95%:"] = f"{np.nanmean(accuracy)} {str(compute_confidence(accuracy, N_1, N_2, alpha))}" + stats["Average Accuracy 95%:"] = f"{np.nanmean(acc_av)} {str(compute_confidence(accuracy, N_1, N_2, alpha))}" + stats["AUC 95%:"] = f"{np.nanmean(auc)} {str(compute_confidence(auc, N_1, N_2, alpha))}" + stats["F1-score 95%:"] = f"{np.nanmean(f1_score_list)} {str(compute_confidence(f1_score_list, N_1, N_2, alpha))}" + stats["Precision 95%:"] = f"{np.nanmean(precision)} {str(compute_confidence(precision, N_1, N_2, alpha))}" + stats["NPV 95%:"] = f"{np.nanmean(npv)} {str(compute_confidence(npv, N_1, N_2, alpha))}" + stats["Sensitivity 95%: "] = f"{np.nanmean(sensitivity)} {str(compute_confidence(sensitivity, N_1, N_2, alpha))}" + stats["Specificity 95%:"] = f"{np.nanmean(specificity)} {str(compute_confidence(specificity, N_1, N_2, alpha))}" + + # Print all CI's + stats = OrderedDict(sorted(stats.items())) + for k, v in stats.items(): + print(f"{k} : {v}.") + + return stats def main(): diff --git a/WORC/plotting/plot_SVR.py b/WORC/plotting/plot_SVR.py deleted file mode 100644 index 69ee4500..00000000 --- a/WORC/plotting/plot_SVR.py +++ /dev/null @@ -1,226 +0,0 @@ -#!/usr/bin/env python - -# Copyright 2016-2019 Biomedical Imaging Group Rotterdam, Departments of -# Medical Informatics and Radiology, Erasmus MC, Rotterdam, The Netherlands -# -# 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 numpy as np -from sklearn.metrics import r2_score, mean_squared_error -import sys -import WORC.plotting.compute_CI -import pandas as pd -import os -import lifelines as ll -import WORC.processing.label_processing as lp -from scipy.stats import pearsonr, spearmanr -from WORC.classification.metrics import ICC - - -def plot_single_SVR(prediction, label_data, label_type, survival=False, - show_plots=False, alpha=0.95): - if type(prediction) is not pd.core.frame.DataFrame: - if os.path.isfile(prediction): - prediction = pd.read_hdf(prediction) - - keys = prediction.keys() - SVRs = list() - label = keys[0] - SVRs = prediction[label]['classifiers'] - - Y_test = prediction[label]['Y_test'] - X_test = prediction[label]['X_test'] - Y_train = prediction[label]['X_train'] - - if survival: - # Also extract time to event and if event occurs from label data - labels = [[label_type], ['E'], ['T']] - else: - labels = [[label_type]] - - if type(label_data) is not dict: - if os.path.isfile(label_data): - label_data = lp.load_labels(label_data, labels) - - patient_IDs = label_data['patient_IDs'] - labels = label_data['label'] - - # Initialize scoring metrics - r2score = list() - MSE = list() - coefICC = list() - PearsonC = list() - PearsonP = list() - SpearmanC = list() - SpearmanP = list() - - if survival: - cindex = list() - coxp = list() - coxcoef = list() - - patient_MSE = dict() - - for i in range(0, len(Y_test)): - test_patient_IDs = prediction[label]['patient_ID_test'][i] - - # FIXME: Put some wrong patient IDs in test files - for num in range(0, len(test_patient_IDs)): - if 'features_' in test_patient_IDs[num]: - test_patient_IDs[num] = test_patient_IDs[num][9::] - - if '__tpl.hdf5' in test_patient_IDs[num]: - test_patient_IDs[num] = test_patient_IDs[num][0:-10] - - test_patient_IDs = np.asarray(test_patient_IDs) - - X_temp = X_test[i] - - test_indices = list() - for i_ID in test_patient_IDs: - # FIXME: Error in specific study - if i_ID == '112_recurrence-preop': - i_ID = '112_recurrence_preop' - test_indices.append(np.where(patient_IDs == i_ID)[0][0]) - - y_truth = [labels[0][k][0] for k in test_indices] - - if type(SVRs) == list or type(SVRs) == tuple: - estimator = SVRs[i] - else: - estimator = SVRs - - scaler = estimator.best_scaler - try: - y_prediction = estimator.predict(scaler.transform(X_temp)) - except ValueError: - y_prediction = estimator.predict(X_temp) - - y_truth = np.asarray(y_truth) - - # if survival: - # # Normalize the scores - # y_prediction = np.subtract(1.01, np.divide(y_prediction, np.max(y_prediction))) - - print("Truth: " + y_truth) - print("Prediction: " + y_prediction) - - # Compute error per patient - for i_truth, i_predict, i_test_ID in zip(y_truth, y_prediction, test_patient_IDs): - if i_test_ID not in patient_MSE.keys(): - patient_MSE[i_test_ID] = list() - patient_MSE[i_test_ID].append((i_truth - i_predict)**2) - - # Compute evaluation metrics - r2score.append(r2_score(y_truth, y_prediction)) - MSE.append(mean_squared_error(y_truth, y_prediction)) - coefICC.append(ICC(np.column_stack((y_prediction, y_truth)))) - C = pearsonr(y_prediction, y_truth) - PearsonC.append(C[0]) - PearsonP.append(C[1]) - C = spearmanr(y_prediction, y_truth) - SpearmanC.append(C.correlation) - SpearmanP.append(C.pvalue) - - if survival: - # Extract time to event and event from label data - E_truth = np.asarray([labels[1][k][0] for k in test_indices]) - T_truth = np.asarray([labels[2][k][0] for k in test_indices]) - - # Concordance index - cindex.append(1 - ll.utils.concordance_index(T_truth, y_prediction, E_truth)) - - # Fit Cox model using SVR output, time to event and event - data = {'predict': y_prediction, 'E': E_truth, 'T': T_truth} - data = pd.DataFrame(data=data, index=test_patient_IDs) - - cph = ll.CoxPHFitter() - cph.fit(data, duration_col='T', event_col='E') - - coxcoef.append(cph.summary['coef']['predict']) - coxp.append(cph.summary['p']['predict']) - - # Compute confidence intervals for given metrics - N_1 = float(len(Y_train[0])) - N_2 = float(len(Y_test[0])) - - if len(r2score) == 1: - # No confidence intevals, just take the scores - stats = dict() - stats["r2_score:"] = str(r2score[0]) - stats["MSE:"] = str(MSE[0]) - stats["ICC:"] = str(coefICC[0]) - stats["PearsonC:"] = str(PearsonC[0]) - stats["SpearmanC: "] = str(SpearmanC[0]) - stats["PearsonP:"] = str(PearsonP[0]) - stats["SpearmanP: "] = str(SpearmanP[0]) - - if survival: - stats["Concordance:"] = str(cindex[0]) - stats["Cox coef.:"] = str(coxcoef[0]) - stats["Cox p:"] = str(coxp[0]) - else: - # Compute confidence intervals from cross validations - stats = dict() - stats["r2_score 95%:"] = str(compute_CI.compute_confidence(r2score, N_1, N_2, alpha)) - stats["MSE 95%:"] = str(compute_CI.compute_confidence(MSE, N_1, N_2, alpha)) - stats["ICC 95%:"] = str(compute_CI.compute_confidence(coefICC, N_1, N_2, alpha)) - stats["PearsonC 95%:"] = str(compute_CI.compute_confidence(PearsonC, N_1, N_2, alpha)) - stats["SpearmanC 95%: "] = str(compute_CI.compute_confidence(SpearmanC, N_1, N_2, alpha)) - stats["PearsonP 95%:"] = str(compute_CI.compute_confidence(PearsonP, N_1, N_2, alpha)) - stats["SpearmanP 95%: "] = str(compute_CI.compute_confidence(SpearmanP, N_1, N_2, alpha)) - - if survival: - stats["Concordance 95%:"] = str(compute_CI.compute_confidence(cindex, N_1, N_2, alpha)) - stats["Cox coef. 95%:"] = str(compute_CI.compute_confidence(coxcoef, N_1, N_2, alpha)) - stats["Cox p 95%:"] = str(compute_CI.compute_confidence(coxp, N_1, N_2, alpha)) - - for k, v in stats.iteritems(): - print(k, v) - - # Calculate and sort individual patient MSE - patient_MSE = {k: np.mean(v) for k, v in patient_MSE.iteritems()} - order = np.argsort(patient_MSE.values()) - sortedkeys = np.asarray(patient_MSE.keys())[order].tolist() - sortedvalues = np.asarray(patient_MSE.values())[order].tolist() - patient_MSE = [(k, v) for k, v in zip(sortedkeys, sortedvalues)] - - for p in patient_MSE: - print(p[0], p[1]) - - stats["Patient_MSE"] = patient_MSE - - if show_plots: - # TODO: Plot metrics, see also plot_SVM - pass - - return stats - - -def main(): - if len(sys.argv) == 1: - prediction = '/media/martijn/DATA/CLM_MICCAI/Results/classification_all_SVR.hdf5' - label_data = '/home/martijn/git/RadTools/CLM_MICCAI/pinfo_CLM_MICCAI_test_months.txt' - label_type = 'KM' - survival = True - elif len(sys.argv) != 3: - raise IOError("This function accepts two arguments") - else: - prediction = sys.argv[1] - label_data = sys.argv[2] - plot_single_SVR(prediction, label_data, label_type, survival) - - -if __name__ == '__main__': - main() diff --git a/WORC/plotting/plot_barchart.py b/WORC/plotting/plot_barchart.py index d277927f..d51ca627 100644 --- a/WORC/plotting/plot_barchart.py +++ b/WORC/plotting/plot_barchart.py @@ -93,11 +93,11 @@ def plot_barchart(prediction, estimators=10, label_type=None, output_tex=None, # Save the output if output_tex is not None: - print('Saving barchart to {}.').format(output_tex) + print(f'Saving barchart to {output_tex}.') tikz_save(output_tex) if output_png is not None: - print('Saving barchart to {}.').format(output_png) + print(f'Saving barchart to {output_png}.') fig.savefig(output_png, bbox_inches='tight', pad_inches=0, dpi=50) @@ -200,7 +200,7 @@ def plot_bars(params, normalization_factor=None, figwidth=20, fontsize=20): def count_parameters(parameters): # Count for every parameter how many times a setting occurs output = dict() - for setting, values in parameters.iteritems(): + for setting, values in parameters.items(): output[setting] = dict() c = Counter(values) for k, v in zip(c.keys(), c.values()): diff --git a/WORC/plotting/plot_images.py b/WORC/plotting/plot_images.py index 59bd42c6..3116e343 100644 --- a/WORC/plotting/plot_images.py +++ b/WORC/plotting/plot_images.py @@ -25,8 +25,8 @@ import SimpleITK as sitk -def slicer(image, mask, output_name, output_name_zoom, thresholds=[-240, 160], - zoomfactor=4): +def slicer(image, mask, output_name, output_name_zoom=None, thresholds=[-240, 160], + zoomfactor=4, dpi=500, normalize=False, expand=False): ''' image and mask should both be arrays ''' @@ -35,8 +35,6 @@ def slicer(image, mask, output_name, output_name_zoom, thresholds=[-240, 160], spacing = float(image.GetSpacing()[0]) imsize = [float(image.GetSize()[0]), float(image.GetSize()[1])] figsize = (imsize[0]*spacing/100.0, imsize[1]*spacing/100.0) - # dpi = int(200/spacing) - dpi = 100.0 # Convert images to numpy arrays image = sitk.GetArrayFromImage(image) @@ -48,6 +46,29 @@ def slicer(image, mask, output_name, output_name_zoom, thresholds=[-240, 160], imslice = image[max_ind, :, :] maskslice = mask[max_ind, :, :] + if expand: + print('\t Expanding.') + imslice = sitk.GetImageFromArray(imslice) + maskslice = sitk.GetImageFromArray(maskslice) + + newsize = (4, 4) + imslice = sitk.Expand(imslice, newsize) + maskslice = sitk.Expand(maskslice, newsize) + + # Adjust the size + spacing = float(imslice.GetSpacing()[0]) + imsize = [float(imslice.GetSize()[0]), float(imslice.GetSize()[1])] + figsize = (imsize[0]*spacing/100.0, imsize[1]*spacing/100.0) + + imslice = sitk.GetArrayFromImage(imslice) + maskslice = sitk.GetArrayFromImage(maskslice) + + if normalize: + print('\t Normalizing.') + imslice = sitk.GetImageFromArray(imslice) + imslice = sitk.Normalize(imslice) + imslice = sitk.GetArrayFromImage(imslice) + # Threshold the image if desired if thresholds: imslice[imslice < thresholds[0]] = thresholds[0] @@ -62,23 +83,25 @@ def slicer(image, mask, output_name, output_name_zoom, thresholds=[-240, 160], # Save some memory del fig - # Create a bounding box and save zoomed image - imslice, maskslice = bbox_2D(imslice, maskslice, padding=[20, 20]) - imsize = [float(imslice.shape[0]), float(imslice.shape[1])] + if output_name_zoom is not None: + # Create a bounding box and save zoomed image + imslice, maskslice = bbox_2D(imslice, maskslice, padding=[20, 20]) + imsize = [float(imslice.shape[0]), float(imslice.shape[1])] - # NOTE: As these zoomed images get small, we double the spacing - spacing = spacing * zoomfactor - figsize = (imsize[0]*spacing/100.0, imsize[1]*spacing/100.0) - fig = plot_im_and_overlay(imslice, maskslice, figsize=figsize) - fig.savefig(output_name_zoom, bbox_inches='tight', pad_inches=0, dpi=dpi) - plt.close('all') + # NOTE: As these zoomed images get small, we double the spacing + spacing = spacing * zoomfactor + figsize = (imsize[0]*spacing/100.0, imsize[1]*spacing/100.0) + fig = plot_im_and_overlay(imslice, maskslice, figsize=figsize) + fig.savefig(output_name_zoom, bbox_inches='tight', pad_inches=0, dpi=dpi) + plt.close('all') + + # Save some memory + del fig, image, mask - # Save some memory - del fig, image, mask return imslice, maskslice -def plot_im_and_overlay(image, mask, figsize=(3, 3), alpha=0.15): +def plot_im_and_overlay(image, mask, figsize=(3, 3), alpha=0.40): ''' Plot an image in a matplotlib figure and overlay with a mask. ''' diff --git a/WORC/plotting/plot_ranked_scores.py b/WORC/plotting/plot_ranked_scores.py index f32be162..55842123 100644 --- a/WORC/plotting/plot_ranked_scores.py +++ b/WORC/plotting/plot_ranked_scores.py @@ -23,7 +23,7 @@ import numpy as np import csv import os -import WORC.plotting.plot_images as pi +from WORC.plotting import plot_images as pi import SimpleITK as sitk from WORC.addexceptions import WORCKeyError import zipfile @@ -114,16 +114,16 @@ def plot_ranked_percentages(estimator, pinfo, label_type=None, print('Determining score per patient.') stats = plot_SVM(prediction, pinfo, - label_type, + [label_type], show_plots=False, alpha=0.95, ensemble=ensemble, output='stats') percentages = stats['Percentages'] - ranking = np.argsort(percentages.values()) - ranked_percentages_temp = [percentages.values()[r] for r in ranking] - ranked_PIDs = [percentages.keys()[r] for r in ranking] + ranking = np.argsort(list(percentages.values())) + ranked_percentages_temp = [list(percentages.values())[r] for r in ranking] + ranked_PIDs = [list(percentages.keys())[r] for r in ranking] ranked_percentages = list() ranked_truths = list() @@ -136,7 +136,7 @@ def plot_ranked_percentages(estimator, pinfo, label_type=None, if output_csv is not None: print("Writing output scores to CSV.") header = ['PatientID', 'TrueLabel', 'Percentage'] - with open(output_csv, 'wb') as csv_file: + with open(output_csv, 'w') as csv_file: writer = csv.writer(csv_file) writer.writerow(header) @@ -155,12 +155,12 @@ def plot_ranked_images(pinfo, label_type, images, segmentations, ranked_truths, print(images) label_data, images =\ lp.findlabeldata(pinfo, - [[label_type]], + [label_type], images, images) _, segmentations =\ lp.findlabeldata(pinfo, - [[label_type]], + [label_type], segmentations, segmentations) @@ -204,7 +204,9 @@ def plot_ranked_images(pinfo, label_type, images, segmentations, ranked_truths, im = sitk.ReadImage(images[idx]) seg = sitk.ReadImage(segmentations[idx]) pid = PIDs_images[idx] - fname = str(int(ranked_scores[idx])) + '_' + pid + '_TrueLabel_' + str(ranked_truths[idx]) + '_slice.png' + fname = str(abs(int(ranked_scores[idx]))) + '_' + pid + '_TrueLabel_' + str(ranked_truths[idx]) + '_slice.png' + if int(ranked_scores[idx]) < 0: + fname = 'min' + fname if output_zip is not None: output_name = os.path.join(os.path.dirname(output_zip), fname) @@ -243,7 +245,7 @@ def plot_ranked_posteriors(estimator, pinfo, label_type=None, y_truths, y_scores, y_predictions, PIDs_scores =\ plot_SVM(prediction, pinfo, - label_type, + [label_type], show_plots=False, alpha=0.95, ensemble=ensemble, @@ -271,8 +273,8 @@ def plot_ranked_posteriors(estimator, pinfo, label_type=None, if len(scores[pid]) > maxlen: maxlen = len(scores[pid]) - ranking = np.argsort(scores_means.values()) - ranked_PIDs = [scores_means.keys()[r] for r in ranking] + ranking = np.argsort(list(scores_means.values())) + ranked_PIDs = [list(scores_means.keys())[r] for r in ranking] ranked_mean_scores = [scores_means[r] for r in ranked_PIDs] ranked_scores = [scores[r] for r in ranked_PIDs] @@ -285,7 +287,7 @@ def plot_ranked_posteriors(estimator, pinfo, label_type=None, for i in range(0, maxlen): header.append('Score' + str(i+1)) - with open(output_csv, 'wb') as csv_file: + with open(output_csv, 'w') as csv_file: writer = csv.writer(csv_file) writer.writerow(header) diff --git a/WORC/plotting/plotminmaxresponse.py b/WORC/plotting/plotminmaxresponse.py index 3eef97f9..9405d7af 100644 --- a/WORC/plotting/plotminmaxresponse.py +++ b/WORC/plotting/plotminmaxresponse.py @@ -17,7 +17,7 @@ import pandas as pd import argparse -import WORC.labels.label_processing as lp +import WORC.processing.label_processing as lp import os import glob from natsort import natsorted @@ -135,8 +135,6 @@ def main(): features = featvect[fl]['all'] maxind = np.argmax(features) minind = np.argmin(features) - print fl, 'min', patient_IDs[minind] - print fl, 'max', patient_IDs[maxind] if args.im is not None: im_min = glob.glob(os.path.join(args.im, patient_IDs[minind]) + imname) diff --git a/WORC/plotting/scatterplot.py b/WORC/plotting/scatterplot.py index 27b6e18d..d8c67704 100644 --- a/WORC/plotting/scatterplot.py +++ b/WORC/plotting/scatterplot.py @@ -18,11 +18,11 @@ try: import matplotlib.pyplot as plt except ImportError: - print("[PREDICT Warning] Cannot use scatterplot function, as _tkinter is not installed") + print("[WORC Warning] Cannot use scatterplot function, as _tkinter is not installed") import pandas as pd import argparse -import genetics.genetic_processing as gp +import WORC.processing.label_processing as lp import os import glob from natsort import natsorted @@ -57,27 +57,25 @@ def main(): args.feat = glob.glob(args.feat + '/features_*.hdf5') args.feat = natsorted(args.feat) - # Read and stack the features - image_features_temp = list() - for i_feat in range(len(args.feat)): - feat = dict() - feat_temp = pd.read_hdf(args.feat[i_feat]) - feat_temp = feat_temp.image_features + make_scatterplot(args.feat, args.classs, args.lab[0], args.lab[1], + args.out) - for feattype in feat_temp.keys(): - feat_type = feat_temp[feattype] - for subtype in feat_type.keys(): - subfeat = feat_type[subtype] - for k in subfeat.keys(): - feat[k] = subfeat[k] - image_features_temp.append(feat) +def make_scatterplot(features, label_file, feature_label_1, feature_label_2, + output): + # Read and stack the features + featname = [feature_label_1, feature_label_2] + image_features_temp = list() + for i_feat in range(len(features)): + feat_temp = pd.read_hdf(features[i_feat]) + feat_temp = {k: v for k, v in zip(feat_temp.feature_labels, feat_temp.feature_values) if k in featname} + image_features_temp.append(feat_temp) # Get the mutation labels and patient IDs - mutation_type = [['GP']] - mutation_data, image_features = gp.findmutationdata(args.classs, + mutation_type = [['MDM2']] + mutation_data, image_features = gp.findmutationdata(label_file, mutation_type, - args.feat, + features, image_features_temp) image_features = image_features.tolist() @@ -86,17 +84,16 @@ def main(): feat2_c0 = list() feat1_c1 = list() feat2_c1 = list() - mutation_label = mutation_data['mutation_label'].tolist()[0] + mutation_label = mutation_data['label'].tolist()[0] patient_IDs = mutation_data['patient_IDs'].tolist() for imfeat, label, pid in zip(image_features, mutation_label, patient_IDs): - print imfeat[args.lab[0]], pid if label[0] == 0: - feat1_c0.append(imfeat[args.lab[0]]) - feat2_c0.append(imfeat[args.lab[1]]) + feat1_c0.append(imfeat[feature_label_1]) + feat2_c0.append(imfeat[feature_label_2]) else: - feat1_c1.append(imfeat[args.lab[0]]) - feat2_c1.append(imfeat[args.lab[1]]) + feat1_c1.append(imfeat[feature_label_1]) + feat2_c1.append(imfeat[feature_label_2]) # Make a scatter plot f = plt.figure() @@ -104,17 +101,17 @@ def main(): subplot.plot(feat1_c0, feat2_c0, linestyle='', ms=12, marker='o', color='navy') subplot.plot(feat1_c1, feat2_c1, linestyle='', ms=12, marker='x', color='red') # NOTE: arbitrary limits! - plt.xlim([0, 10]) - plt.ylim([0, 10]) - plt.xlabel(args.lab[0]) - plt.ylabel(args.lab[1]) + # plt.xlim([0, 10]) + # plt.ylim([0, 10]) + plt.xlabel(feature_label_1) + plt.ylabel(feature_label_2) plt.title('Feature scatter plot') plt.legend() - plt.show() + # plt.show() - f.savefig(args.out) - print(("Snapshot saved as {} !").format(args.out)) + f.savefig(output) + print(("Scatterplot saved as {} !").format(output)) if __name__ == '__main__': - main() + main() \ No newline at end of file diff --git a/WORC/processing/ExtractNLargestBlobsn.pyc b/WORC/processing/ExtractNLargestBlobsn.pyc deleted file mode 100644 index 68f058ad..00000000 Binary files a/WORC/processing/ExtractNLargestBlobsn.pyc and /dev/null differ diff --git a/WORC/processing/__init__.pyc b/WORC/processing/__init__.pyc deleted file mode 100644 index d164ad82..00000000 Binary files a/WORC/processing/__init__.pyc and /dev/null differ diff --git a/WORC/processing/label_processing.py b/WORC/processing/label_processing.py index 6d7b67e8..97a22534 100644 --- a/WORC/processing/label_processing.py +++ b/WORC/processing/label_processing.py @@ -37,6 +37,9 @@ def load_labels(label_file, label_type): dict: A dict containing 'patient_IDs', 'label' and 'label_type' """ + if not os.path.exists(label_file): + raise ae.WORCKeyError(f'File {label_file} does not exist!') + _, extension = os.path.splitext(label_file) if extension == '.txt': label_names, patient_IDs, label_status = load_label_txt( diff --git a/build/lib/WORC/plotting/__init__.py b/WORC/resources/__init__.py similarity index 100% rename from build/lib/WORC/plotting/__init__.py rename to WORC/resources/__init__.py diff --git a/WORC/resources/fastr_tools/__init__.py b/WORC/resources/fastr_tools/__init__.py new file mode 100644 index 00000000..a10fe72e --- /dev/null +++ b/WORC/resources/fastr_tools/__init__.py @@ -0,0 +1,2 @@ +import os +print(os.path.dirname(os.path.abspath(__file__))) \ No newline at end of file diff --git a/WORC/resources/fastr_tools/pyradiomics/bin/CF_pyradiomics.py b/WORC/resources/fastr_tools/pyradiomics/bin/CF_pyradiomics.py index 4d0ff591..e85ff0f0 100644 --- a/WORC/resources/fastr_tools/pyradiomics/bin/CF_pyradiomics.py +++ b/WORC/resources/fastr_tools/pyradiomics/bin/CF_pyradiomics.py @@ -19,6 +19,7 @@ import SimpleITK as sitk import radiomics from radiomics import featureextractor +import collections def AllFeatures(image, mask): @@ -30,15 +31,25 @@ def AllFeatures(image, mask): kwargs['interpolator'] = sitk.sitkBSpline kwargs['verbose'] = True + # Specific MR Settings: see https://github.com/Radiomics/pyradiomics/blob/master/examples/exampleSettings/exampleMR_NoResampling.yaml + kwargs['normalize'] = True + kwargs['normalizeScale'] = 100 + kwargs['preCrop'] = True + kwargs['force2D'] = True + kwargs['force2Ddimension'] = 0 # axial slices, for coronal slices, use dimension 1 and for sagittal, dimension 2. + kwargs['binWidth'] = 5 + kwargs['voxelArrayShift'] = 300 + kwargs['label'] = 1 + + # NOTE: A little more tolerance may be required on matching the dimensions + kwargs['geometryTolerance'] = 1E-3 + # Initialize wrapperClass to generate signature extractor = featureextractor.RadiomicsFeaturesExtractor(**kwargs) # Disable all classes except firstorder extractor.enableAllFeatures() - # Enable writing out the log using radiomics logger - radiomics.debug() # Switch on radiomics logging from level=DEBUG (default level=WARNING) - # Prevent radiomics logger from printing out log entries with level < WARNING to the console logger = logging.getLogger('radiomics') logger.handlers[0].setLevel(logging.WARNING) @@ -50,18 +61,56 @@ def AllFeatures(image, mask): handler.setFormatter(formatter) logger.addHandler(handler) - print("Active features:") - for cls, features in extractor.enabledFeatures.iteritems(): - if len(features) == 0: - features = extractor.getFeatureNames(cls) - for f in features: - print(f) - print(eval('extractor.featureClasses["%s"].get%sFeatureValue.__doc__' % (cls, f))) - print("Calculating features") + featureVector = extractor.execute(image, mask) + # Split center of mass features in the three dimensions + # Save as orientation features + COM_index = featureVector['diagnostics_Mask-original_CenterOfMassIndex'] + featureVector['of_original_COM_Index_x'] = COM_index[0] + featureVector['of_original_COM_Index_y'] = COM_index[1] + featureVector['of_original_COM_Index_z'] = COM_index[2] + + COM = featureVector['diagnostics_Mask-original_CenterOfMass'] + featureVector['of_original_COM_x'] = COM[0] + featureVector['of_original_COM_y'] = COM[1] + featureVector['of_original_COM_z'] = COM[2] + + # Delete all diagnostics features: + for k in featureVector.keys(): + if 'diagnostics' in k: + del featureVector[k] + + # Change label to be similar to PREDICT + new_featureVector = collections.OrderedDict() + texture_features = ['_glcm_', '_gldm_', '_glrlm_', '_glszm_', '_ngtdm'] + for k in featureVector.keys(): + if any(t in k for t in texture_features): + kn = 'tf_' + k + elif '_shape_' in k: + kn = 'sf_' + k + elif '_firstorder_' in k: + kn = 'hf_' + k + elif '_of_' in k: + # COM + kn = k + else: + message = ('Key {} is unknown!').format(k) + raise ValueError(message) + + # Add PyRadiomics to the key + kn = 'PyRadiomics_' + kn + + # Add to new feature Vector + new_featureVector[kn] = featureVector[k] + + featureVector = new_featureVector + + # Print the values and keys + nfeat = len(featureVector.keys()) + print(('Total of {} feature computed:').format(str(nfeat))) for featureName in featureVector.keys(): print("Computed %s: %s" % (featureName, featureVector[featureName])) - return featureVector + return featureVector, kwargs diff --git a/WORC/resources/fastr_tools/pyradiomics/bin/CF_pyradiomics_tool.py b/WORC/resources/fastr_tools/pyradiomics/bin/CF_pyradiomics_tool.py index 73a7674d..a75cea67 100644 --- a/WORC/resources/fastr_tools/pyradiomics/bin/CF_pyradiomics_tool.py +++ b/WORC/resources/fastr_tools/pyradiomics/bin/CF_pyradiomics_tool.py @@ -16,6 +16,7 @@ # limitations under the License. import argparse +import pandas as pd from CF_pyradiomics import AllFeatures as CalcFeatures @@ -50,7 +51,7 @@ def main(): if type(args.out) is list: args.out = ''.join(args.out) - featureVector = CalcFeatures(image=args.im, mask=args.seg) + featureVector, settings = CalcFeatures(image=args.im, mask=args.seg) if 'rdf' in args.out: # Write output to rdf @@ -59,9 +60,9 @@ def main(): from rdflib.namespace import RDF, FOAF # convert python object to RDF - print "-----------------------------------------------------------" - print " RDF Output:" - print "" + print("-----------------------------------------------------------") + print(" RDF Output:") + print("") Img = Graph() lung1_image = URIRef("http://example.org/CT-Image") Img.add((lung1_image, RDF.type, FOAF.Image)) @@ -73,86 +74,25 @@ def main(): tmp_name = list_key[i] Img.add((lung1_image, FOAF.tmp_name, tmp_value)) - print Img.serialize(format='turtle') + print(Img.serialize(format='turtle')) # Create a rdf file for storing output Img.serialize(args.out, format="pretty-xml") elif 'hdf5' in args.out: # Write output to hdf5 - import numpy as np - import pandas as pd - - # Assign features to corresponding groups - shape_labels = list() - shape_features = list() - histogram_labels = list() - histogram_features = list() - GLCM_labels = list() - GLCM_features = list() - GLRLM_labels = list() - GLRLM_features = list() - GLSZM_labels = list() - GLSZM_features = list() - - for featureName in featureVector.keys(): - if 'shape' in featureName: - shape_labels.append(featureName) - shape_features.append(featureVector[featureName]) - if 'firstorder' in featureName: - histogram_labels.append(featureName) - histogram_features.append(featureVector[featureName]) - if 'glcm' in featureName: - GLCM_labels.append(featureName) - GLCM_features.append(featureVector[featureName]) - if 'glrlm' in featureName: - GLRLM_labels.append(featureName) - GLRLM_features.append(featureVector[featureName]) - if 'glszm' in featureName: - GLSZM_labels.append(featureName) - GLSZM_features.append(featureVector[featureName]) - - # Convert feature to single dictionary containing PD series - features = dict() - pandas_dict = dict(zip(shape_labels, shape_features)) - shape_dict = dict() - shape_dict['all'] = pd.Series(pandas_dict) - shape_features = pd.Series(shape_dict) - features['shape_features'] = shape_features - - pandas_dict = dict(zip(histogram_labels, histogram_features)) - histogram_dict = dict() - histogram_dict['all'] = pd.Series(pandas_dict) - histogram_features = pd.Series(histogram_dict) - features['histogram_features'] = histogram_features - - GLCM_dict = dict(zip(GLCM_labels, GLCM_features)) - GLRLM_dict = dict(zip(GLRLM_labels, GLRLM_features)) - GLSZM_dict = dict(zip(GLSZM_labels, GLSZM_features)) - - texture_features = dict() - texture_features['GLCM'] = pd.Series(GLCM_dict) - texture_features['GLRLM'] = pd.Series(GLRLM_dict) - texture_features['GLSZM'] = pd.Series(GLSZM_dict) - - texture_features = pd.Series(texture_features) - features['texture_features'] = texture_features - - # We also return just the arrray - image_feature_array = list() - - for _, feattype in features.iteritems(): - for _, imfeatures in feattype.iteritems(): - image_feature_array.extend(imfeatures.values) - - image_feature_array = np.asarray(image_feature_array) - image_feature_array = image_feature_array.ravel() - - panda_labels = ['image_features', 'image_features_array'] - panda_data = pd.Series([features, image_feature_array], + image_type = 'MR' + feature_values = featureVector.values() + feature_labels = featureVector.keys() + panda_labels = ['image_type', 'parameters', 'feature_values', + 'feature_labels'] + + panda_data = pd.Series([image_type, settings, feature_values, + feature_labels], index=panda_labels, name='Image features' ) + print('Saving image features') panda_data.to_hdf(args.out, 'image_features') diff --git a/WORC/resources/fastr_tools/segmentix/bin/segmentix.py b/WORC/resources/fastr_tools/segmentix/bin/segmentix.py index a3acc53f..fbb84afc 100644 --- a/WORC/resources/fastr_tools/segmentix/bin/segmentix.py +++ b/WORC/resources/fastr_tools/segmentix/bin/segmentix.py @@ -72,12 +72,12 @@ def segmentix(parameters=None, image=None, segmentation=None, segmentation = ''.join(segmentation) # Convert to binary image and clean up small errors/areas - contour = sitk.ReadImage(segmentation) - contour = sitk.GetArrayFromImage(contour) + contour_original = sitk.ReadImage(segmentation) + contour = sitk.GetArrayFromImage(contour_original) # BUG: remove first and last slice, fault in liver segmentations - contour[:,:,-1] = np.zeros([contour.shape[0], contour.shape[1]]) - contour[:,:, 0] = np.zeros([contour.shape[0], contour.shape[1]]) + contour[:, :, -1] = np.zeros([contour.shape[0], contour.shape[1]]) + contour[:, :, 0] = np.zeros([contour.shape[0], contour.shape[1]]) if config['Segmentix']['fillholes']: contour = nd.binary_fill_holes(contour) @@ -94,11 +94,11 @@ def segmentix(parameters=None, image=None, segmentation=None, radius = int(config['Segmentix']['radius']) disk = morphology.disk(radius) - # Dilation with radius - for ind in range(contour.shape[2]): - contour_d = morphology.binary_dilation(contour[:, :, ind], disk) - contour_e = morphology.binary_erosion(contour[:, :, ind], disk) - contour[:, :, ind] = np.bitwise_xor(contour_d, contour_e) + # Dilation with radius in axial direction + for ind in range(contour.shape[0]): + contour_d = morphology.binary_dilation(contour[ind, :, :], disk) + contour_e = morphology.binary_erosion(contour[ind, :, :], disk) + contour[ind, :, :] = np.bitwise_xor(contour_d, contour_e) # Mask the segmentation if necessary if mask is not None: @@ -118,6 +118,7 @@ def segmentix(parameters=None, image=None, segmentation=None, # Output contour contour = contour.astype(np.uint8) contour = sitk.GetImageFromArray(contour) + contour.CopyInformation(contour_original) if output is not None: sitk.WriteImage(contour, output) else: diff --git a/build/lib/WORC/resources/fastr_tools/worc/StatisticalTestFeatures.xml b/WORC/resources/fastr_tools/worc/Decomposition.xml similarity index 73% rename from build/lib/WORC/resources/fastr_tools/worc/StatisticalTestFeatures.xml rename to WORC/resources/fastr_tools/worc/Decomposition.xml index ff46013b..ac9b98ae 100644 --- a/build/lib/WORC/resources/fastr_tools/worc/StatisticalTestFeatures.xml +++ b/WORC/resources/fastr_tools/worc/Decomposition.xml @@ -1,11 +1,11 @@ - - A wrapper around PREDICT's Radiomics statistical test function for funtion. + + A wrapper around the statistical test function for fastr. - + WIP @@ -22,7 +22,7 @@ - + diff --git a/WORC/resources/fastr_tools/worc/PlotRankedScores.xml b/WORC/resources/fastr_tools/worc/PlotRankedScores.xml index adce5719..6b8bfb0d 100644 --- a/WORC/resources/fastr_tools/worc/PlotRankedScores.xml +++ b/WORC/resources/fastr_tools/worc/PlotRankedScores.xml @@ -23,8 +23,8 @@ - - + + diff --git a/WORC/resources/fastr_tools/worc/StatisticalTestFeatures.xml b/WORC/resources/fastr_tools/worc/StatisticalTestFeatures.xml index ff46013b..d4d71d33 100644 --- a/WORC/resources/fastr_tools/worc/StatisticalTestFeatures.xml +++ b/WORC/resources/fastr_tools/worc/StatisticalTestFeatures.xml @@ -1,5 +1,5 @@ - A wrapper around PREDICT's Radiomics statistical test function for funtion. + A wrapper around the statistical test function for fastr. @@ -17,7 +17,7 @@ - + diff --git a/build/lib/WORC/resources/fastr_tools/worc/bin/StatisticalTestFeatures_tool.py b/WORC/resources/fastr_tools/worc/bin/Decomposition_tool.py similarity index 74% rename from build/lib/WORC/resources/fastr_tools/worc/bin/StatisticalTestFeatures_tool.py rename to WORC/resources/fastr_tools/worc/bin/Decomposition_tool.py index 7ac7d8e7..7afd52e5 100644 --- a/build/lib/WORC/resources/fastr_tools/worc/bin/StatisticalTestFeatures_tool.py +++ b/WORC/resources/fastr_tools/worc/bin/Decomposition_tool.py @@ -16,7 +16,7 @@ # limitations under the License. import argparse -from WORC.featureprocessing.StatisticalTestFeatures import StatisticalTestFeatures +from WORC.featureprocessing.Decomposition import Decomposition def main(): @@ -31,16 +31,16 @@ def main(): parser.add_argument('-cf', '--conf', metavar='config', nargs='+', dest='cf', type=str, required=True, help='Configuration') - parser.add_argument('-perf', '--perf', metavar='performance', - dest='perf', type=str, required=True, nargs='+', - help='Performance (JSON)') + parser.add_argument('-output', '--output', metavar='output', + dest='output', type=str, required=True, nargs='+', + help='Output (Zip)') args = parser.parse_args() - StatisticalTestFeatures(features=args.feat, - patientinfo=args.pc, - config=args.cf, - output=args.perf, - verbose=False) + Decomposition(features=args.feat, + patientinfo=args.pc, + config=args.cf, + output=args.perf, + verbose=False) if __name__ == '__main__': diff --git a/WORC/resources/fastr_tools/worc/bin/PlotSVM.py b/WORC/resources/fastr_tools/worc/bin/PlotSVM.py index 203c336c..8de06685 100644 --- a/WORC/resources/fastr_tools/worc/bin/PlotSVM.py +++ b/WORC/resources/fastr_tools/worc/bin/PlotSVM.py @@ -53,8 +53,8 @@ def main(): if type(args.output_json) is list: args.output_json = ''.join(args.output_json) - if type(args.label_type) is list: - args.label_type = ''.join(args.label_type) + # if type(args.label_type) is list: + # args.label_type = ''.join(args.label_type) # Plot the statistics stats = plot_SVM(prediction=args.prediction, diff --git a/WORC/resources/fastr_tools/worc/bin/combineresults.py b/WORC/resources/fastr_tools/worc/bin/combineresults.py index b625706d..d09e1f74 100644 --- a/WORC/resources/fastr_tools/worc/bin/combineresults.py +++ b/WORC/resources/fastr_tools/worc/bin/combineresults.py @@ -50,7 +50,6 @@ def main(): args.perf = ''.join(args.perf) # If input is dir, use glob - print args.svm if os.path.isdir(args.svm): args.svm = glob.glob(args.svm + '/svm_*.hdf5') args.svm = natsorted(args.svm) @@ -85,7 +84,6 @@ def main(): if 'Too Few Features.' in svm.keys() or ' Too Few Features.' in svm.keys(): print(("Too few features in {}.").format(svmfile)) else: - print svm labels = svm[svm.keys()[0]].ix['feature_labels'] # .tolist() feature_labels.append(labels) all_feature_labels = all_feature_labels + list(set(labels) - set(all_feature_labels)) diff --git a/WORC/resources/fastr_tools/worc/bin/preprocessing.py b/WORC/resources/fastr_tools/worc/bin/preprocessing.py index baac6038..f2903dfb 100644 --- a/WORC/resources/fastr_tools/worc/bin/preprocessing.py +++ b/WORC/resources/fastr_tools/worc/bin/preprocessing.py @@ -89,6 +89,7 @@ def main(): # Cast to float to allow proper processing image = sitk.Cast(image, 9) + mask = sitk.Cast(mask, 0) LabelFilter = sitk.LabelStatisticsImageFilter() LabelFilter.Execute(image, mask) @@ -101,6 +102,7 @@ def main(): elif config['Normalize']['Method'] == 'minmed': print('Apply scaling using the minimum and mean of the ROI') image = sitk.Cast(image, 9) + mask = sitk.Cast(mask, 0) LabelFilter = sitk.LabelStatisticsImageFilter() LabelFilter.Execute(image, mask) diff --git a/WORC/resources/fastr_tools/worc/bin/slicer.py b/WORC/resources/fastr_tools/worc/bin/slicer.py index 2ec530ad..8d9444f0 100644 --- a/WORC/resources/fastr_tools/worc/bin/slicer.py +++ b/WORC/resources/fastr_tools/worc/bin/slicer.py @@ -26,7 +26,7 @@ def slicer(image, mask, output_name, output_name_zoom, thresholds=[-240, 160], - zoomfactor=4): + zoomfactor=4, reverse=True, flipud=True): ''' image and mask should both be arrays ''' @@ -42,6 +42,15 @@ def slicer(image, mask, output_name, output_name_zoom, thresholds=[-240, 160], image = sitk.GetArrayFromImage(image) mask = sitk.GetArrayFromImage(mask) + # Manipulate mask if required + if reverse: + print('Reversing mask in zero axis.') + mask = mask[::-1, :, :] + + if flipud: + print("Flipping scan on first axis.") + mask = np.flip(mask, 1) + # Determine which axial slice has the largest area areas = np.sum(mask, axis=1).tolist() max_ind = areas.index(max(areas)) diff --git a/WORC/resources/fastr_tools/worc/bin/worccastconvert.py b/WORC/resources/fastr_tools/worc/bin/worccastconvert.py index 15b68e74..ec6bfce1 100644 --- a/WORC/resources/fastr_tools/worc/bin/worccastconvert.py +++ b/WORC/resources/fastr_tools/worc/bin/worccastconvert.py @@ -17,6 +17,8 @@ import argparse import SimpleITK as sitk +import os +import shutil def main(): @@ -35,8 +37,20 @@ def main(): if type(args.out) is list: args.out = ''.join(args.out) - image = sitk.ReadImage(args.im) - sitk.WriteImage(image, args.out) + # Check if input and output have the same format + extension_input = os.path.splitext(args.im)[-1] + extension_output = os.path.splitext(args.out)[-1] + if extension_input == extension_output: + # Make link + try: + os.symlink(args.im, args.out) + except (OSError, AttributeError): + print('[WORC WARNING] Cannot symlink, fallback to copying.') + shutil.copy2(args.im, args.out) + else: + # Read and Write file using SimpleITK + image = sitk.ReadImage(args.im) + sitk.WriteImage(image, args.out) if __name__ == '__main__': diff --git a/WORC/resources/fastr_types/BValueFile.pyc b/WORC/resources/fastr_types/BValueFile.pyc deleted file mode 100644 index beff568b..00000000 Binary files a/WORC/resources/fastr_types/BValueFile.pyc and /dev/null differ diff --git a/WORC/resources/fastr_types/BVectorFile.pyc b/WORC/resources/fastr_types/BVectorFile.pyc deleted file mode 100644 index 8abbf3ed..00000000 Binary files a/WORC/resources/fastr_types/BVectorFile.pyc and /dev/null differ diff --git a/WORC/resources/fastr_types/CSVFile.pyc b/WORC/resources/fastr_types/CSVFile.pyc deleted file mode 100644 index 92dcdc5a..00000000 Binary files a/WORC/resources/fastr_types/CSVFile.pyc and /dev/null differ diff --git a/WORC/resources/fastr_types/ConfigFile.pyc b/WORC/resources/fastr_types/ConfigFile.pyc deleted file mode 100644 index 3d77b3aa..00000000 Binary files a/WORC/resources/fastr_types/ConfigFile.pyc and /dev/null differ diff --git a/WORC/resources/fastr_types/DataFile.pyc b/WORC/resources/fastr_types/DataFile.pyc deleted file mode 100644 index ffe2eced..00000000 Binary files a/WORC/resources/fastr_types/DataFile.pyc and /dev/null differ diff --git a/WORC/resources/fastr_types/DicomImageDirectory.pyc b/WORC/resources/fastr_types/DicomImageDirectory.pyc deleted file mode 100644 index 675df523..00000000 Binary files a/WORC/resources/fastr_types/DicomImageDirectory.pyc and /dev/null differ diff --git a/WORC/resources/fastr_types/DicomImageFile.pyc b/WORC/resources/fastr_types/DicomImageFile.pyc deleted file mode 100644 index 14b485e8..00000000 Binary files a/WORC/resources/fastr_types/DicomImageFile.pyc and /dev/null differ diff --git a/WORC/resources/fastr_types/ElastixInput.pyc b/WORC/resources/fastr_types/ElastixInput.pyc deleted file mode 100644 index be9b35c9..00000000 Binary files a/WORC/resources/fastr_types/ElastixInput.pyc and /dev/null differ diff --git a/WORC/resources/fastr_types/ElastixLogFile.pyc b/WORC/resources/fastr_types/ElastixLogFile.pyc deleted file mode 100644 index 4efb3032..00000000 Binary files a/WORC/resources/fastr_types/ElastixLogFile.pyc and /dev/null differ diff --git a/WORC/resources/fastr_types/ElastixParameterFile.pyc b/WORC/resources/fastr_types/ElastixParameterFile.pyc deleted file mode 100644 index d9e40723..00000000 Binary files a/WORC/resources/fastr_types/ElastixParameterFile.pyc and /dev/null differ diff --git a/WORC/resources/fastr_types/ElastixTransformFile.pyc b/WORC/resources/fastr_types/ElastixTransformFile.pyc deleted file mode 100644 index b66c0c8a..00000000 Binary files a/WORC/resources/fastr_types/ElastixTransformFile.pyc and /dev/null differ diff --git a/WORC/resources/fastr_types/HDF5.pyc b/WORC/resources/fastr_types/HDF5.pyc deleted file mode 100644 index 9a31d2d1..00000000 Binary files a/WORC/resources/fastr_types/HDF5.pyc and /dev/null differ diff --git a/WORC/resources/fastr_types/MIGRASParameterFile.pyc b/WORC/resources/fastr_types/MIGRASParameterFile.pyc deleted file mode 100644 index 012710cf..00000000 Binary files a/WORC/resources/fastr_types/MIGRASParameterFile.pyc and /dev/null differ diff --git a/WORC/resources/fastr_types/MatlabFile.pyc b/WORC/resources/fastr_types/MatlabFile.pyc deleted file mode 100644 index 0a37fff7..00000000 Binary files a/WORC/resources/fastr_types/MatlabFile.pyc and /dev/null differ diff --git a/WORC/resources/fastr_types/MetaData.pyc b/WORC/resources/fastr_types/MetaData.pyc deleted file mode 100644 index 611b63f1..00000000 Binary files a/WORC/resources/fastr_types/MetaData.pyc and /dev/null differ diff --git a/WORC/resources/fastr_types/PREDICTParameterFile.pyc b/WORC/resources/fastr_types/PREDICTParameterFile.pyc deleted file mode 100644 index 22c9b549..00000000 Binary files a/WORC/resources/fastr_types/PREDICTParameterFile.pyc and /dev/null differ diff --git a/WORC/resources/fastr_types/ParameterFile.pyc b/WORC/resources/fastr_types/ParameterFile.pyc deleted file mode 100644 index 3ec0c800..00000000 Binary files a/WORC/resources/fastr_types/ParameterFile.pyc and /dev/null differ diff --git a/WORC/resources/fastr_types/PatientInfoFile.pyc b/WORC/resources/fastr_types/PatientInfoFile.pyc deleted file mode 100644 index fb508f67..00000000 Binary files a/WORC/resources/fastr_types/PatientInfoFile.pyc and /dev/null differ diff --git a/WORC/resources/fastr_types/RDF.pyc b/WORC/resources/fastr_types/RDF.pyc deleted file mode 100644 index 5d6cfc47..00000000 Binary files a/WORC/resources/fastr_types/RDF.pyc and /dev/null differ diff --git a/WORC/resources/fastr_types/Shelve.pyc b/WORC/resources/fastr_types/Shelve.pyc deleted file mode 100644 index a66481cf..00000000 Binary files a/WORC/resources/fastr_types/Shelve.pyc and /dev/null differ diff --git a/WORC/resources/fastr_types/TextFile.pyc b/WORC/resources/fastr_types/TextFile.pyc deleted file mode 100644 index 6a13abdc..00000000 Binary files a/WORC/resources/fastr_types/TextFile.pyc and /dev/null differ diff --git a/WORC/resources/fastr_types/TransformixLogFile.pyc b/WORC/resources/fastr_types/TransformixLogFile.pyc deleted file mode 100644 index 1fdc97c0..00000000 Binary files a/WORC/resources/fastr_types/TransformixLogFile.pyc and /dev/null differ diff --git a/WORC/resources/fastr_types/TransformixOutputPointFile.pyc b/WORC/resources/fastr_types/TransformixOutputPointFile.pyc deleted file mode 100644 index e8270c4f..00000000 Binary files a/WORC/resources/fastr_types/TransformixOutputPointFile.pyc and /dev/null differ diff --git a/WORC/resources/fastr_types/TransformixParam.pyc b/WORC/resources/fastr_types/TransformixParam.pyc deleted file mode 100644 index 4c4b961e..00000000 Binary files a/WORC/resources/fastr_types/TransformixParam.pyc and /dev/null differ diff --git a/WORC/resources/fastr_types/TransformixPointFile.pyc b/WORC/resources/fastr_types/TransformixPointFile.pyc deleted file mode 100644 index 602ad161..00000000 Binary files a/WORC/resources/fastr_types/TransformixPointFile.pyc and /dev/null differ diff --git a/WORC/tools/Elastix.py b/WORC/tools/Elastix.py index 844b2752..1fe53b53 100644 --- a/WORC/tools/Elastix.py +++ b/WORC/tools/Elastix.py @@ -17,6 +17,7 @@ import SimpleITK as sitk import fastr +from fastr.api import ResourceLimit import numpy as np import os import WORC.addexceptions as WORCexceptions @@ -87,20 +88,20 @@ def getparametermap(self, model='affine', size=(512, 512, 128)): def create_network(self, nettype): if nettype == 'pairwise': # Create the network - self.network = fastr.Network(id_="elastix_pair") + self.network = fastr.create_network(id="elastix_pair") # Create Sources - self.FixedImageSource = self.network.create_source('ITKImageFile', id_='FixedImage') - self.FixedMaskSource = self.network.create_source('ITKImageFile', id_='FixedMask') - self.MovingImageSource = self.network.create_source('ITKImageFile', id_='MovingImage') - self.MovingMaskSource = self.network.create_source('ITKImageFile', id_='MovingMask') - self.ToTransformSource = self.network.create_source('ITKImageFile', id_='ToTransform') - self.ParameterMapSource = self.network.create_source('ElastixParameterFile', id_='ParameterMaps', nodegroup='par') + self.FixedImageSource = self.network.create_source('ITKImageFile', id='FixedImage') + self.FixedMaskSource = self.network.create_source('ITKImageFile', id='FixedMask') + self.MovingImageSource = self.network.create_source('ITKImageFile', id='MovingImage') + self.MovingMaskSource = self.network.create_source('ITKImageFile', id='MovingMask') + self.ToTransformSource = self.network.create_source('ITKImageFile', id='ToTransform') + self.ParameterMapSource = self.network.create_source('ElastixParameterFile', id='ParameterMaps', node_group='par') # Elastix requires the output folder as a sink # self.OutputFolderSource = self.network.create_sink('Directory', id_='Out') # Create Elastix node and links - self.elastix_node = self.network.create_node(self.elastix_toolname, id_='elastix') + self.elastix_node = self.network.create_node('self.elastix_toolname', tool_version='unknown', id='elastix') self.elastix_node.inputs['fixed_image'] = self.FixedImageSource.output self.elastix_node.inputs['fixed_mask'] = self.FixedMaskSource.output self.elastix_node.inputs['moving_image'] = self.MovingImageSource.output @@ -110,48 +111,48 @@ def create_network(self, nettype): self.link_param.collapse = 'par' # Create Sinks - self.outtrans = self.network.create_sink('ElastixTransformFile', id_='sink_trans') - self.outimage = self.network.create_sink('ITKImageFile', id_='sink_image') - self.outseg = self.network.create_sink('ITKImageFile', id_='sink_seg') + self.outtrans = self.network.create_sink('ElastixTransformFile', id='sink_trans') + self.outimage = self.network.create_sink('ITKImageFile', id='sink_image') + self.outseg = self.network.create_sink('ITKImageFile', id='sink_seg') self.outtrans.inputs['input'] = self.elastix_node.outputs['transform'] # Transform output image - self.transformix_node = self.network.create_node(self.transformix_toolname, id_='transformix') + self.transformix_node = self.network.create_node('self.transformix_toolname', tool_version='unknown', id='transformix') self.transformix_node.inputs['image'] = self.MovingImageSource.output self.transformix_node.inputs['transform'] = self.elastix_node.outputs['transform'][-1] self.outimage.inputs['input'] = self.transformix_node.outputs['image'] # First change the FinalBSplineInterpolationOrder to 0 for the segmentation - self.changeorder_node = self.network.create_node('EditElastixTransformFile', id_='editelpara') + self.changeorder_node = self.network.create_node('elastixtools/EditElastixTransformFile:0.1', tool_version='0.1', id='editelpara') self.link_trans = self.network.create_link(self.elastix_node.outputs['transform'][-1], self.changeorder_node.inputs['transform']) # self.link_trans.converge = 0 # self.link_trans.collapse = 'FixedImage' # self.link_trans.expand = True # Co[y metadata from image to segmentation as Elastix uses this - self.copymetadata_node = self.network.create_node('CopyMetadata', id_='copymetadata') + self.copymetadata_node = self.network.create_node('itktools/0.3.2/CopyMetadata:1.0', tool_version='1.0', id='copymetadata') self.copymetadata_node.inputs['source'] = self.MovingImageSource.output self.copymetadata_node.inputs['destination'] = self.ToTransformSource.output # Then transform the segmentation - self.transformix_node_seg = self.network.create_node(self.transformix_toolname, id_='transformix_seg') + self.transformix_node_seg = self.network.create_node('self.transformix_toolname', tool_version='unknown', id='transformix_seg') self.transformix_node_seg.inputs['image'] = self.copymetadata_node.outputs['output'] self.transformix_node_seg.inputs['transform'] = self.changeorder_node.outputs['transform'][-1] self.outseg.inputs['input'] = self.transformix_node_seg.outputs['image'] else: # Create the network - self.network = fastr.Network(id_="elastix_group") + self.network = fastr.create_network(id="elastix_group") # Create Sources - self.FixedImageSource = self.network.create_source('ITKImageFile', id_='FixedImage') - self.FixedMaskSource = self.network.create_source('ITKImageFile', id_='FixedMask') - self.ToTransformSource = self.network.create_source('ITKImageFile', id_='ToTransform') - self.ParameterMapSource = self.network.create_source('ElastixParameterFile', id_='ParameterMaps', nodegroup='par') + self.FixedImageSource = self.network.create_source('ITKImageFile', id='FixedImage') + self.FixedMaskSource = self.network.create_source('ITKImageFile', id='FixedMask') + self.ToTransformSource = self.network.create_source('ITKImageFile', id='ToTransform') + self.ParameterMapSource = self.network.create_source('ElastixParameterFile', id='ParameterMaps', node_group='par') # Elastix requires the output folder as a sink # self.OutputFolderSource = self.network.create_sink('Directory', id_='Out') # Create Elastix node and links - self.elastix_node = self.network.create_node(self.elastix_toolname, id_='elastix') + self.elastix_node = self.network.create_node('self.elastix_toolname', tool_version='unknown', id='elastix') self.elastix_node.inputs['fixed_image'] = self.FixedImageSource.output self.elastix_node.inputs['fixed_mask'] = self.FixedMaskSource.output self.elastix_node.inputs['moving_image'] = self.FixedImageSource.output @@ -161,19 +162,19 @@ def create_network(self, nettype): self.link_param.collapse = 'par' # Create Sinks - self.outtrans = self.network.create_sink('ElastixTransformFile', id_='sink_trans') - self.outimage = self.network.create_sink('ITKImageFile', id_='sink_image') - self.outseg = self.network.create_sink('ITKImageFile', id_='sink_seg') + self.outtrans = self.network.create_sink('ElastixTransformFile', id='sink_trans') + self.outimage = self.network.create_sink('ITKImageFile', id='sink_image') + self.outseg = self.network.create_sink('ITKImageFile', id='sink_seg') self.outtrans.inputs['input'] = self.elastix_node.outputs['transform'] # Transform output image - self.transformix_node = self.network.create_node(self.transformix_toolname, id_='transformix') + self.transformix_node = self.network.create_node('self.transformix_toolname', tool_version='unknown', id='transformix') self.transformix_node.inputs['image'] = self.MovingImageSource.output self.transformix_node.inputs['transform'] = self.elastix_node.outputs['transform'][-1] self.outimage.inputs['input'] = self.transformix_node.outputs['image'] # First change the FinalBSplineInterpolationOrder to 0 for the segmentation - self.changeorder_node = self.network.create_node('EditElastixTransformFile', id_='editelpara') + self.changeorder_node = self.network.create_node('elastixtools/EditElastixTransformFile:0.1', tool_version='0.1', id='editelpara') self.changeorder_node.inputs['set'] = ["FinalBSplineInterpolationOrder=0"] self.link_trans = self.network.create_link(self.elastix_node.outputs['transform'], self.changeorder_node.inputs['transform'][-1]) # self.link_trans.converge = 0 @@ -181,12 +182,12 @@ def create_network(self, nettype): # self.link_trans.expand = True # Co[y metadata from image to segmentation as Elastix uses this - self.copymetadata_node = self.network.create_node('CopyMetadata', id_='copymetadata') + self.copymetadata_node = self.network.create_node('itktools/0.3.2/CopyMetadata:1.0', tool_version='1.0', id='copymetadata') self.copymetadata_node.inputs['source'] = self.MovingImageSource.output self.copymetadata_node.inputs['destination'] = self.ToTransformSource.output # Then transform the segmentation - self.transformix_node_seg = self.network.create_node(self.transformix_toolname, id_='transformix_seg') + self.transformix_node_seg = self.network.create_node('self.transformix_toolname', tool_version='unknown', id='transformix_seg') self.transformix_node_seg.inputs['image'] = self.copymetadata_node.outputs['output'] self.transformix_node_seg.inputs['transform'] = self.changeorder_node.outputs['transform'][-1] self.outseg.inputs['input'] = self.transformix_node_seg.outputs['image'] @@ -305,7 +306,7 @@ def execute(self): # print self.sink_data['Out'] # Execute the network - self.network.draw_network('WORC_Elastix', img_format='svg', draw_dimension=True) + self.network.draw(file_path='WORC_Elastix.svg', img_format='svg') self.network.dumpf('{}.json'.format(self.network.id), indent=2) self.network.execute(self.source_data, self.sink_data, tmpdir=self.fastr_tmpdir) diff --git a/WORC/tools/Evaluate.py b/WORC/tools/Evaluate.py index 0e98e75a..84b5e746 100644 --- a/WORC/tools/Evaluate.py +++ b/WORC/tools/Evaluate.py @@ -17,15 +17,17 @@ import WORC.addexceptions as WORCexceptions import fastr +from fastr.api import ResourceLimit import os +import graphviz # NOTE: Very important to give images and segmentations as dict with patient names! class Evaluate(object): def __init__(self, label_type, ensemble=50, scores='percentages', - network=None, features=None, - fastr_plugin='ProcessPoolExecution', + parent=None, features=None, + fastr_plugin='LinearExecution', name='Example'): ''' Build a network that evaluates the performance of an estimator. @@ -38,23 +40,26 @@ def __init__(self, label_type, ensemble=50, scores='percentages', to the existing network. ''' - if network is not None: - self.network = network + if parent is not None: + self.parent = parent + self.network = parent.network self.mode = 'WORC' + self.name = parent.network.id + self.ensemble = parent.configs[0]['Ensemble']['Use'] else: self.mode = 'StandAlone' self.fastr_plugin = fastr_plugin self.name = 'WORC_Evaluate_' + name - self.network = fastr.Network(id_=self.name) + self.network = fastr.create_network(id=self.name) self.fastr_tmpdir = os.path.join(fastr.config.mounts['tmp'], self.name) + self.ensemble = ensemble if features is None and self.mode == 'StandAlone': - raise WORCexceptions.IOError('Either features as input or a WORC network is required for the Evaluate network.') + raise WORCexceptions.WORCIOError('Either features as input or a WORC network is required for the Evaluate network.') self.features = features self.label_type = label_type - self.ensemble = ensemble self.create_network() @@ -64,141 +69,200 @@ def create_network(self): ''' # Create all nodes - self.network.node_ROC =\ - self.network.create_node('PlotROC', memory='20G', id_='plot_ROC') - self.network.node_SVM =\ - self.network.create_node('PlotSVM', memory='20G', id_='plot_SVM') - self.network.node_Barchart =\ - self.network.create_node('PlotBarchart', memory='4G', id_='plot_Barchart') - self.network.node_STest =\ - self.network.create_node('StatisticalTestFeatures', memory='4G', id_='statistical_test_features') - self.network.node_Ranked_Percentages =\ - self.network.create_node('PlotRankedScores', memory='20G', id_='plot_ranked_percentages') - self.network.node_Ranked_Posteriors =\ - self.network.create_node('PlotRankedScores', memory='20G', id_='plot_ranked_posteriors') + self.node_ROC =\ + self.network.create_node('worc/PlotROC:1.0', tool_version='1.0', id='plot_ROC', resources=ResourceLimit(memory='20G')) + self.node_SVM =\ + self.network.create_node('worc/PlotSVM:1.0', tool_version='1.0', id='plot_SVM', resources=ResourceLimit(memory='20G')) + self.node_Barchart =\ + self.network.create_node('worc/PlotBarchart:1.0', tool_version='1.0', id='plot_Barchart', resources=ResourceLimit(memory='4G')) + self.node_STest =\ + self.network.create_node('worc/StatisticalTestFeatures:1.0', tool_version='1.0', id='statistical_test_features', resources=ResourceLimit(memory='4G')) + self.node_Ranked_Percentages =\ + self.network.create_node('worc/PlotRankedScores:1.0', tool_version='1.0', id='plot_ranked_percentages', resources=ResourceLimit(memory='20G')) + self.node_Ranked_Posteriors =\ + self.network.create_node('worc/PlotRankedScores:1.0', tool_version='1.0', id='plot_ranked_posteriors', resources=ResourceLimit(memory='20G')) # Create sinks - self.network.sink_ROC_PNG =\ - self.network.create_sink('PNGFile', id_='ROC_PNG') - self.network.sink_ROC_Tex =\ - self.network.create_sink('TexFile', id_='ROC_Tex') - self.network.sink_ROC_CSV =\ - self.network.create_sink('CSVFile', id_='ROC_CSV') - - self.network.sink_SVM_Json =\ - self.network.create_sink('JsonFile', id_='SVM_Json') - - self.network.sink_Barchart_PNG =\ - self.network.create_sink('PNGFile', id_='Barchart_PNG') - self.network.sink_Barchart_Tex =\ - self.network.create_sink('TexFile', id_='Barchart_Tex') - - self.network.sink_STest_CSV =\ - self.network.create_sink('CSVFile', id_='StatisticalTestFeatures_CSV') - - self.network.sink_Ranked_Percentages_Zip =\ - self.network.create_sink('ZipFile', id_='RankedPercentages_Zip') - self.network.sink_Ranked_Percentages_CSV =\ - self.network.create_sink('CSVFile', id_='RankedPercentages_CSV') - - self.network.sink_Ranked_Posteriors_Zip =\ - self.network.create_sink('ZipFile', id_='RankedPosteriors_Zip') - self.network.sink_Ranked_Posteriors_CSV =\ - self.network.create_sink('CSVFile', id_='RankedPosteriors_CSV') + self.sink_ROC_PNG =\ + self.network.create_sink('PNGFile', id='ROC_PNG') + self.sink_ROC_Tex =\ + self.network.create_sink('TexFile', id='ROC_Tex') + self.sink_ROC_CSV =\ + self.network.create_sink('CSVFile', id='ROC_CSV') + + self.sink_SVM_Json =\ + self.network.create_sink('JsonFile', id='SVM_Json') + + self.sink_Barchart_PNG =\ + self.network.create_sink('PNGFile', id='Barchart_PNG') + self.sink_Barchart_Tex =\ + self.network.create_sink('TexFile', id='Barchart_Tex') + + self.sink_STest_CSV =\ + self.network.create_sink('CSVFile', id='StatisticalTestFeatures_CSV') + + self.sink_Ranked_Percentages_Zip =\ + self.network.create_sink('ZipFile', id='RankedPercentages_Zip') + self.sink_Ranked_Percentages_CSV =\ + self.network.create_sink('CSVFile', id='RankedPercentages_CSV') + + self.sink_Ranked_Posteriors_Zip =\ + self.network.create_sink('ZipFile', id='RankedPosteriors_Zip') + self.sink_Ranked_Posteriors_CSV =\ + self.network.create_sink('CSVFile', id='RankedPosteriors_CSV') # Create links to sinks - self.network.sink_ROC_PNG.input = self.network.node_ROC.outputs['output_png'] - self.network.sink_ROC_Tex.input = self.network.node_ROC.outputs['output_tex'] - self.network.sink_ROC_CSV.input = self.network.node_ROC.outputs['output_csv'] + self.sink_ROC_PNG.input = self.node_ROC.outputs['output_png'] + self.sink_ROC_Tex.input = self.node_ROC.outputs['output_tex'] + self.sink_ROC_CSV.input = self.node_ROC.outputs['output_csv'] - self.network.sink_SVM_Json.input = self.network.node_SVM.outputs['output_json'] + self.sink_SVM_Json.input = self.node_SVM.outputs['output_json'] - self.network.sink_Barchart_PNG.input = self.network.node_Barchart.outputs['output_png'] - self.network.sink_Barchart_Tex.input = self.network.node_Barchart.outputs['output_tex'] + self.sink_Barchart_PNG.input = self.node_Barchart.outputs['output_png'] + self.sink_Barchart_Tex.input = self.node_Barchart.outputs['output_tex'] - self.network.sink_STest_CSV.input = self.network.node_STest.outputs['performance'] + self.sink_STest_CSV.input = self.node_STest.outputs['performance'] - self.network.sink_Ranked_Percentages_Zip.input = self.network.node_Ranked_Percentages.outputs['output_zip'] - self.network.sink_Ranked_Percentages_CSV.input = self.network.node_Ranked_Percentages.outputs['output_csv'] + self.sink_Ranked_Percentages_Zip.input = self.node_Ranked_Percentages.outputs['output_zip'] + self.sink_Ranked_Percentages_CSV.input = self.node_Ranked_Percentages.outputs['output_csv'] - self.network.sink_Ranked_Posteriors_Zip.input = self.network.node_Ranked_Posteriors.outputs['output_zip'] - self.network.sink_Ranked_Posteriors_CSV.input = self.network.node_Ranked_Posteriors.outputs['output_csv'] + self.sink_Ranked_Posteriors_Zip.input = self.node_Ranked_Posteriors.outputs['output_zip'] + self.sink_Ranked_Posteriors_CSV.input = self.node_Ranked_Posteriors.outputs['output_csv'] # Create two constant nodes - self.network.node_Ranked_Percentages.inputs['scores'] = ['percentages'] - self.network.node_Ranked_Posteriors.inputs['scores'] = ['posteriors'] + self.node_Ranked_Percentages.inputs['scores'] = ['percentages'] + self.node_Ranked_Posteriors.inputs['scores'] = ['posteriors'] # Create sources that are not in WORC and set them - self.network.source_LabelType = self.network.create_source('String', id_='LabelType') - self.network.source_Ensemble = self.network.create_source('String', id_='Ensemble') - self.network.source_LabelType.input = [self.label_type] - self.network.source_Ensemble.input = [self.ensemble] + # self.source_LabelType = self.network.create_source('String', id='LabelType') + # self.source_Ensemble = self.network.create_source('String', id='Ensemble') + # self.source_LabelType.input = [self.label_type] + # self.source_Ensemble.input = [self.ensemble] + + self.source_LabelType = self.network.create_constant('String', [self.label_type], id='LabelType') + self.source_Ensemble = self.network.create_constant('String', [self.ensemble], id='Ensemble') # Create sources if not supplied by a WORC network if self.mode == 'StandAlone': - self.network.source_Estimator = self.network.create_source('HDF5', id_='Estimator') - self.network.source_PatientInfo = self.network.create_source('PatientInfoFile', id_='PatientInfo') - self.network.source_Images = self.network.create_source('ITKImageFile', id_='Images', nodegroup='patients') - self.network.source_Segmentations = self.network.create_source('ITKImageFile', id_='Segmentations', nodegroup='patients') - self.network.source_Config = self.network.create_source('ParameterFile', id_='Config') + self.source_Estimator = self.network.create_source('HDF5', id='Estimator') + self.source_PatientInfo = self.network.create_source('PatientInfoFile', id='PatientInfo') + self.source_Images = self.network.create_source('ITKImageFile', id='Images', node_group='patients') + self.source_Segmentations = self.network.create_source('ITKImageFile', id='Segmentations', node_group='patients') + self.source_Config = self.network.create_source('ParameterFile', id='Config') self.labels = list() - self.network.source_Features = list() + self.source_Features = list() for idx in range(0, len(self.features)): label = 'Features_' + str(idx) self.labels.append(label) - self.network.source_Features.append(self.network.create_source('HDF5', id_=label, nodegroup='features')) + self.source_Features.append(self.network.create_source('HDF5', id=label, node_group='features')) # Create links to sources that are not supplied by a WORC network - self.network.node_ROC.inputs['ensemble'] = self.network.source_Ensemble.output - self.network.node_ROC.inputs['label_type'] = self.network.source_LabelType.output + self.node_ROC.inputs['ensemble'] = self.source_Ensemble.output + self.node_ROC.inputs['label_type'] = self.source_LabelType.output - self.network.node_SVM.inputs['ensemble'] = self.network.source_Ensemble.output - self.network.node_SVM.inputs['label_type'] = self.network.source_LabelType.output + self.node_SVM.inputs['ensemble'] = self.source_Ensemble.output + self.node_SVM.inputs['label_type'] = self.source_LabelType.output - self.network.node_Barchart.inputs['estimators'] = self.network.source_Ensemble.output - self.network.node_Barchart.inputs['label_type'] = self.network.source_LabelType.output + self.node_Barchart.inputs['estimators'] = self.source_Ensemble.output + self.node_Barchart.inputs['label_type'] = self.source_LabelType.output - self.network.node_Ranked_Percentages.inputs['ensemble'] = self.network.source_Ensemble.output - self.network.node_Ranked_Percentages.inputs['label_type'] = self.network.source_LabelType.output + self.node_Ranked_Percentages.inputs['ensemble'] = self.source_Ensemble.output + self.node_Ranked_Percentages.inputs['label_type'] = self.source_LabelType.output - self.network.node_Ranked_Posteriors.inputs['ensemble'] = self.network.source_Ensemble.output - self.network.node_Ranked_Posteriors.inputs['label_type'] = self.network.source_LabelType.output + self.node_Ranked_Posteriors.inputs['ensemble'] = self.source_Ensemble.output + self.node_Ranked_Posteriors.inputs['label_type'] = self.source_LabelType.output # Create links to the sources that could be in a WORC network if self.mode == 'StandAlone': + self.create_links_Standalone() + else: + self.create_links_Addon() + + def create_links_Standalone(self): # Sources from the Evaluate network are used - self.network.node_ROC.inputs['prediction'] = self.network.source_Estimator.output - self.network.node_ROC.inputs['pinfo'] = self.network.source_PatientInfo.output + self.node_ROC.inputs['prediction'] = self.source_Estimator.output + self.node_ROC.inputs['pinfo'] = self.source_PatientInfo.output - self.network.node_SVM.inputs['prediction'] = self.network.source_Estimator.output - self.network.node_SVM.inputs['pinfo'] = self.network.source_PatientInfo.output + self.node_SVM.inputs['prediction'] = self.source_Estimator.output + self.node_SVM.inputs['pinfo'] = self.source_PatientInfo.output - self.network.node_Barchart.inputs['prediction'] = self.network.source_Estimator.output + self.node_Barchart.inputs['prediction'] = self.source_Estimator.output - self.network.links_STest_Features = list() + self.links_STest_Features = list() for idx, label in enumerate(self.labels): - self.network.links_STest_Features.append(self.network.node_STest.inputs['features'][str(label)] << self.network.source_Features[idx].output) - self.network.links_STest_Features[idx].collapse = 'features' - self.network.node_STest.inputs['patientclass'] = self.network.source_PatientInfo.output - self.network.node_STest.inputs['config'] = self.network.source_Config.output - - self.network.node_Ranked_Percentages.inputs['estimator'] = self.network.source_Estimator.output - self.network.node_Ranked_Percentages.inputs['pinfo'] = self.network.source_PatientInfo.output - self.network.link_images_perc = self.network.create_link(self.network.source_Images.output, self.network.node_Ranked_Percentages.inputs['images']) - self.network.link_images_perc.collapse = 'patients' - self.network.link_segmentations_perc = self.network.create_link(self.network.source_Segmentations.output, self.network.node_Ranked_Percentages.inputs['segmentations']) - self.network.link_segmentations_perc.collapse = 'patients' - - self.network.node_Ranked_Posteriors.inputs['estimator'] = self.network.source_Estimator.output - self.network.node_Ranked_Posteriors.inputs['pinfo'] = self.network.source_PatientInfo.output - self.network.link_images_post = self.network.create_link(self.network.source_Images.output, self.network.node_Ranked_Posteriors.inputs['images']) - self.network.link_images_post.collapse = 'patients' - self.network.link_segmentations_post = self.network.create_link(self.network.source_Segmentations.output, self.network.node_Ranked_Posteriors.inputs['segmentations']) - self.network.link_segmentations_post.collapse = 'patients' - else: + self.links_STest_Features.append(self.node_STest.inputs['features'][str(label)] << self.source_Features[idx].output) + self.links_STest_Features[idx].collapse = 'features' + self.node_STest.inputs['patientclass'] = self.source_PatientInfo.output + self.node_STest.inputs['config'] = self.source_Config.output + + self.node_Ranked_Percentages.inputs['estimator'] = self.source_Estimator.output + self.node_Ranked_Percentages.inputs['pinfo'] = self.source_PatientInfo.output + self.link_images_perc = self.network.create_link(self.source_Images.output, self.node_Ranked_Percentages.inputs['images']) + self.link_images_perc.collapse = 'patients' + self.link_segmentations_perc = self.network.create_link(self.source_Segmentations.output, self.node_Ranked_Percentages.inputs['segmentations']) + self.link_segmentations_perc.collapse = 'patients' + + self.node_Ranked_Posteriors.inputs['estimator'] = self.source_Estimator.output + self.node_Ranked_Posteriors.inputs['pinfo'] = self.source_PatientInfo.output + self.link_images_post = self.network.create_link(self.source_Images.output, self.node_Ranked_Posteriors.inputs['images']) + self.link_images_post.collapse = 'patients' + self.link_segmentations_post = self.network.create_link(self.source_Segmentations.output, self.node_Ranked_Posteriors.inputs['segmentations']) + self.link_segmentations_post.collapse = 'patients' + + def create_links_Addon(self): # Sources from the WORC network are used - print('WIP') + prediction = self.parent.classify.outputs['classification'] + if self.parent.labels_test: + pinfo = self.parent.source_patientclass_test.output + else: + pinfo = self.parent.source_patientclass_train.output + + config = self.parent.source_class_config.output + + if self.parent.sources_images_train: + # NOTE: Use images of first modality to depict tumor + label = self.parent.modlabels[0] + images = self.parent.sources_images_train[label].output + segmentations = self.parent.sources_segmentations_train[label].output + + self.node_ROC.inputs['prediction'] = prediction + self.node_ROC.inputs['pinfo'] = pinfo + + self.node_SVM.inputs['prediction'] = prediction + self.node_SVM.inputs['pinfo'] = pinfo + + self.node_Barchart.inputs['prediction'] = prediction + + self.links_STest_Features = dict() + for idx, label in enumerate(self.parent.modlabels): + # NOTE: Currently statistical testing is only done within the training set + if self.parent.sources_images_train: + # Features are computed within the network + self.links_STest_Features[label] = self.node_STest.inputs['features'][str(label)] << self.parent.calcfeatures_train[label].outputs['features'] + else: + # Feature are precomputed and given as sources + self.links_STest_Features[label] = self.node_STest.inputs['features'][str(label)] << self.parent.sources_features_train[label].output + self.links_STest_Features[label].collapse = 'train' + + self.node_STest.inputs['patientclass'] = pinfo + self.node_STest.inputs['config'] = config + + self.node_Ranked_Percentages.inputs['estimator'] = prediction + self.node_Ranked_Percentages.inputs['pinfo'] = pinfo + self.node_Ranked_Posteriors.inputs['estimator'] = prediction + self.node_Ranked_Posteriors.inputs['pinfo'] = pinfo + + if self.parent.sources_images_train: + self.link_images_perc = self.network.create_link(images, self.node_Ranked_Percentages.inputs['images']) + self.link_images_perc.collapse = 'train' + self.link_segmentations_perc = self.network.create_link(segmentations, self.node_Ranked_Percentages.inputs['segmentations']) + self.link_segmentations_perc.collapse = 'train' + + self.link_images_post = self.network.create_link(images, self.node_Ranked_Posteriors.inputs['images']) + self.link_images_post.collapse = 'train' + self.link_segmentations_post = self.network.create_link(segmentations, self.node_Ranked_Posteriors.inputs['segmentations']) + self.link_segmentations_post.collapse = 'train' def set(self, estimator=None, pinfo=None, images=None, segmentations=None, config=None, features=None, @@ -220,40 +284,42 @@ def set(self, estimator=None, pinfo=None, images=None, for feature, label in zip(features, self.labels): self.source_data[label] = feature + else: + self.sink_data = self.parent.sink_data - if 'ROC_PNG' not in sink_data.keys(): - self.sink_data['ROC_PNG'] = ("vfs://output/{}/ROC_{{sample_id}}_{{cardinality}}{{ext}}").format(self.name) - if 'ROC_Tex' not in sink_data.keys(): - self.sink_data['ROC_Tex'] = ("vfs://output/{}/ROC_{{sample_id}}_{{cardinality}}{{ext}}").format(self.name) - if 'ROC_CSV' not in sink_data.keys(): - self.sink_data['ROC_CSV'] = ("vfs://output/{}/ROC_{{sample_id}}_{{cardinality}}{{ext}}").format(self.name) - - if 'SVM_Json' not in sink_data.keys(): - self.sink_data['SVM_Json'] = ("vfs://output/{}/performance_{{sample_id}}_{{cardinality}}{{ext}}").format(self.name) + if 'ROC_PNG' not in sink_data.keys(): + self.sink_data['ROC_PNG'] = ("vfs://output/{}/ROC_{{sample_id}}_{{cardinality}}{{ext}}").format(self.name) + if 'ROC_Tex' not in sink_data.keys(): + self.sink_data['ROC_Tex'] = ("vfs://output/{}/ROC_{{sample_id}}_{{cardinality}}{{ext}}").format(self.name) + if 'ROC_CSV' not in sink_data.keys(): + self.sink_data['ROC_CSV'] = ("vfs://output/{}/ROC_{{sample_id}}_{{cardinality}}{{ext}}").format(self.name) - if 'Barchart_PNG' not in sink_data.keys(): - self.sink_data['Barchart_PNG'] = ("vfs://output/{}/Barchart_{{sample_id}}_{{cardinality}}{{ext}}").format(self.name) - if 'Barchart_Tex' not in sink_data.keys(): - self.sink_data['Barchart_Tex'] = ("vfs://output/{}/Barchart_{{sample_id}}_{{cardinality}}{{ext}}").format(self.name) + if 'SVM_Json' not in sink_data.keys(): + self.sink_data['SVM_Json'] = ("vfs://output/{}/performance_{{sample_id}}_{{cardinality}}{{ext}}").format(self.name) - if 'StatisticalTestFeatures_CSV' not in sink_data.keys(): - self.sink_data['StatisticalTestFeatures_CSV'] = ("vfs://output/{}/StatisticalTestFeatures_{{sample_id}}_{{cardinality}}{{ext}}").format(self.name) + if 'Barchart_PNG' not in sink_data.keys(): + self.sink_data['Barchart_PNG'] = ("vfs://output/{}/Barchart_{{sample_id}}_{{cardinality}}{{ext}}").format(self.name) + if 'Barchart_Tex' not in sink_data.keys(): + self.sink_data['Barchart_Tex'] = ("vfs://output/{}/Barchart_{{sample_id}}_{{cardinality}}{{ext}}").format(self.name) - if 'RankedPercentages_Zip' not in sink_data.keys(): - self.sink_data['RankedPercentages_Zip'] = ("vfs://output/{}/RankedPercentages_{{sample_id}}_{{cardinality}}{{ext}}").format(self.name) - if 'RankedPercentages_CSV' not in sink_data.keys(): - self.sink_data['RankedPercentages_CSV'] = ("vfs://output/{}/RankedPercentages_{{sample_id}}_{{cardinality}}{{ext}}").format(self.name) + if 'StatisticalTestFeatures_CSV' not in sink_data.keys(): + self.sink_data['StatisticalTestFeatures_CSV'] = ("vfs://output/{}/StatisticalTestFeatures_{{sample_id}}_{{cardinality}}{{ext}}").format(self.name) - if 'RankedPosteriors_Zip' not in sink_data.keys(): - self.sink_data['RankedPosteriors_Zip'] = ("vfs://output/{}/RankedPosteriors_{{sample_id}}_{{cardinality}}{{ext}}").format(self.name) - if 'RankedPosteriors_CSV' not in sink_data.keys(): - self.sink_data['RankedPosteriors_CSV'] = ("vfs://output/{}/RankedPosteriors_{{sample_id}}_{{cardinality}}{{ext}}").format(self.name) + if 'RankedPercentages_Zip' not in sink_data.keys(): + self.sink_data['RankedPercentages_Zip'] = ("vfs://output/{}/RankedPercentages_{{sample_id}}_{{cardinality}}{{ext}}").format(self.name) + if 'RankedPercentages_CSV' not in sink_data.keys(): + self.sink_data['RankedPercentages_CSV'] = ("vfs://output/{}/RankedPercentages_{{sample_id}}_{{cardinality}}{{ext}}").format(self.name) - else: - print('[WORC Warning] Evaluate set attribute not needed when WORC network is provided!') + if 'RankedPosteriors_Zip' not in sink_data.keys(): + self.sink_data['RankedPosteriors_Zip'] = ("vfs://output/{}/RankedPosteriors_{{sample_id}}_{{cardinality}}{{ext}}").format(self.name) + if 'RankedPosteriors_CSV' not in sink_data.keys(): + self.sink_data['RankedPosteriors_CSV'] = ("vfs://output/{}/RankedPosteriors_{{sample_id}}_{{cardinality}}{{ext}}").format(self.name) def execute(self): """ Execute the network through the fastr.network.execute command. """ # Draw and execute nwtwork - self.network.draw_network(self.network.id, draw_dimension=True) + try: + self.network.draw(file_path=self.network.id + '.svg', draw_dimensions=True) + except graphviz.backend.ExecutableNotFound: + print('[WORC WARNING] Graphviz executable not found: not drawing network diagram. MAke sure the Graphviz executables are on your systems PATH.') self.network.execute(self.source_data, self.sink_data, execution_plugin=self.fastr_plugin, tmpdir=self.fastr_tmpdir) diff --git a/WORC/tools/Slicer.py b/WORC/tools/Slicer.py index e4150950..ab2a0815 100644 --- a/WORC/tools/Slicer.py +++ b/WORC/tools/Slicer.py @@ -17,6 +17,7 @@ import WORC.addexceptions as WORCexceptions import fastr +from fastr.api import ResourceLimit import os @@ -43,15 +44,15 @@ def __init__(self, images=None, segmentations=None, self.mode = 'StandAlone' self.fastr_plugin = fastr_plugin self.name = 'WORC_Slicer_' + name - self.network = fastr.Network(id_=self.name) + self.network = fastr.create_network(id=self.name) self.fastr_tmpdir = os.path.join(fastr.config.mounts['tmp'], self.name) if images is None and self.mode == 'StandAlone': message = 'Either images and segmentations as input or a WORC' +\ 'network is required for the Evaluate network.' - raise WORCexceptions.IOError(message) + raise WORCexceptions.WORCIOError(message) - self.image = images + self.images = images self.segmentations = segmentations self.create_network() @@ -62,23 +63,23 @@ def create_network(self): ''' # Create all nodes - self.network.node_slicer =\ - self.network.create_node('Slicer', memory='20G', id_='Slicer') + self.node_slicer =\ + self.network.create_node('worc/Slicer:1.0', tool_version='1.0', id='Slicer', resources=ResourceLimit(memory='20G')) # Create sinks - self.network.sink_PNG =\ - self.network.create_sink('PNGFile', id_='PNG') - self.network.sink_PNGZoomed =\ - self.network.create_sink('PNGFile', id_='PNGZoomed') + self.sink_PNG =\ + self.network.create_sink('PNGFile', id='PNG') + self.sink_PNGZoomed =\ + self.network.create_sink('PNGFile', id='PNGZoomed') # Create links to sinks - self.network.sink_PNG.input = self.network.node_slicer.outputs['out'] - self.network.sink_PNGZoomed.input = self.network.node_slicer.outputs['outzoom'] + self.sink_PNG.input = self.node_slicer.outputs['out'] + self.sink_PNGZoomed.input = self.node_slicer.outputs['outzoom'] # Create sources if not supplied by a WORC network if self.mode == 'StandAlone': - self.network.source_images = self.network.create_source('ITKImage', id_='Images') - self.network.source_segmentations = self.network.create_source('ITKImage', id_='Segmentations') + self.source_images = self.network.create_source('ITKImageFile', id='Images') + self.source_segmentations = self.network.create_source('ITKImageFile', id='Segmentations') # Create links to sources that are not supplied by a WORC network # Not needed in this network @@ -86,8 +87,8 @@ def create_network(self): # Create links to the sources that could be in a WORC network if self.mode == 'StandAlone': # Sources from the Evaluate network are used - self.network.node_slicer.inputs['image'] = self.network.source_images.output - self.network.node_slicer.inputs['segmentation'] = self.network.source_segmentations.output + self.node_slicer.inputs['image'] = self.source_images.output + self.node_slicer.inputs['segmentation'] = self.source_segmentations.output else: # Sources from the WORC network are used print('WIP') @@ -100,8 +101,8 @@ def set(self, images=None, segmentations=None, sink_data={}): self.source_data = dict() self.sink_data = dict() - self.source_data['Images'] = images - self.source_data['Segmentations'] = segmentations + self.source_data['Images'] = self.images + self.source_data['Segmentations'] = self.segmentations if 'PNG' not in sink_data.keys(): self.sink_data['PNG'] = ("vfs://output/{}/Slice_{{sample_id}}_{{cardinality}}{{ext}}").format(self.name) @@ -114,5 +115,5 @@ def set(self, images=None, segmentations=None, sink_data={}): def execute(self): """ Execute the network through the fastr.network.execute command. """ # Draw and execute nwtwork - self.network.draw_network(self.network.id, draw_dimension=True) + self.network.draw(file_path=self.network.id + '.svg', draw_dimensions=True) self.network.execute(self.source_data, self.sink_data, execution_plugin=self.fastr_plugin, tmpdir=self.fastr_tmpdir) diff --git a/WORC/tools/Transformix.py b/WORC/tools/Transformix.py index b6e4bc7f..8206ba5b 100644 --- a/WORC/tools/Transformix.py +++ b/WORC/tools/Transformix.py @@ -17,6 +17,7 @@ import SimpleITK as sitk import fastr +from fastr.api import ResourceLimit import numpy as np import os import WORC.addexceptions as WORCexceptions @@ -30,19 +31,19 @@ def __init__(self): self.TransformParameterMap = None def create_network(self): - self.network = fastr.Network(id_="transformix") + self.network = fastr.create_network(id="transformix") - self.MovingImageSource = self.network.create_source('ITKImageFile', id_='MovingImage') - self.ParameterMapSource = self.network.create_source('ElastixTransformFile', id_='ParameterFile') + self.MovingImageSource = self.network.create_source('ITKImageFile', id='MovingImage') + self.ParameterMapSource = self.network.create_source('ElastixTransformFile', id='ParameterFile') - self.transformix_node = self.network.create_node('transformix_dev', id_='transformix') + self.transformix_node = self.network.create_node('elastix_dev/transformix_dev:4.9-dev-wyke', tool_version='0.2', id='transformix') self.transformix_node.inputs['image'] = self.MovingImageSource.output self.transformix_node.inputs['transform'] = self.ParameterMapSource.output - self.outimage = self.network.create_sink('ITKImageFile', id_='sink_image') + self.outimage = self.network.create_sink('ITKImageFile', id='sink_image') self.outimage.inputs['input'] = self.transformix_node.outputs['image'] - self.network.draw_network(img_format='svg') + self.network.draw(file_path='transformix.svg') self.network.dumpf('{}.json'.format(self.network.id), indent=2) def execute(self): diff --git a/WORC/tools/createfixedsplits.py b/WORC/tools/createfixedsplits.py new file mode 100644 index 00000000..e0db0415 --- /dev/null +++ b/WORC/tools/createfixedsplits.py @@ -0,0 +1,127 @@ +#!/usr/bin/env python + +# Copyright 2016-2019 Biomedical Imaging Group Rotterdam, Departments of +# Medical Informatics and Radiology, Erasmus MC, Rotterdam, The Netherlands +# +# 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 numpy as np +from sklearn.model_selection import train_test_split +import WORC.addexceptions as ae +from WORC.processing.label_processing import load_labels +import pandas as pd + + +def createfixedsplits(label_file=None, label_type=None, patient_IDs=None, + test_size=0.2, N_iterations=1, regression=False, + stratify=None, modus='singlelabel', output=None): + ''' + Create fixed splits for a cross validation. + ''' + # Check whether input is valid + if patient_IDs is None: + if label_file is not None and label_type is not None: + # Read the label file + label_data = load_labels(label_file, label_type) + patient_IDs = label_data['patient_IDs'] + + # Create the stratification object + if modus == 'singlelabel': + stratify = label_data['label'] + elif modus == 'multilabel': + # Create a stratification object from the labels + # Label = 0 means no label equals one + # Other label numbers refer to the label name that is 1 + stratify = list() + labels = label_data['label'] + for pnum in range(0, len(labels[0])): + plabel = 0 + for lnum, slabel in enumerate(labels): + if slabel[pnum] == 1: + plabel = lnum + 1 + stratify.append(plabel) + + else: + raise ae.WORCKeyError('{} is not a valid modus!').format(modus) + else: + raise ae.WORCIOError('Either a label file and label type or patient_IDs need to be provided!') + + pd_dict = dict() + for i in range(N_iterations): + print(f'Splitting iteration {i + 1} / {N_iterations}') + # Create a random seed for the splitting + random_seed = np.random.randint(5000) + + # Define stratification + unique_patient_IDs, unique_indices =\ + np.unique(np.asarray(patient_IDs), return_index=True) + if regression: + unique_stratify = None + else: + unique_stratify = [stratify[i] for i in unique_indices] + + # Split, throw error when dataset is too small for split ratio's + try: + unique_PID_train, indices_PID_test\ + = train_test_split(unique_patient_IDs, + test_size=test_size, + random_state=random_seed, + stratify=unique_stratify) + except ValueError as e: + e = str(e) + ' Increase the size of your test set.' + raise ae.WORCValueError(e) + + # Check for all IDs if they are in test or training + indices_train = list() + indices_test = list() + patient_ID_train = list() + patient_ID_test = list() + for num, pid in enumerate(patient_IDs): + if pid in unique_PID_train: + indices_train.append(num) + + # Make sure we get a unique ID + if pid in patient_ID_train: + n = 1 + while str(pid + '_' + str(n)) in patient_ID_train: + n += 1 + pid = str(pid + '_' + str(n)) + patient_ID_train.append(pid) + else: + indices_test.append(num) + + # Make sure we get a unique ID + if pid in patient_ID_test: + n = 1 + while str(pid + '_' + str(n)) in patient_ID_test: + n += 1 + pid = str(pid + '_' + str(n)) + patient_ID_test.append(pid) + + # Add to train object + pd_dict[str(i) + '_train'] = patient_ID_train + + # Test object has to be same length as training object + extras = [""]*(len(patient_ID_train) - len(patient_ID_test)) + patient_ID_test.extend(extras) + pd_dict[str(i) + '_test'] = patient_ID_test + + # Convert into pandas dataframe for easy use and conversion + df = pd.DataFrame(pd_dict) + + # Write output if required + if output is not None: + print("Writing Output.") + df.to_csv(output) + + return df diff --git a/build/lib/WORC/IOparser/config_WORC.py b/build/lib/WORC/IOparser/config_WORC.py deleted file mode 100644 index 4ada0379..00000000 --- a/build/lib/WORC/IOparser/config_WORC.py +++ /dev/null @@ -1,53 +0,0 @@ -#!/usr/bin/env python - -# Copyright 2016-2019 Biomedical Imaging Group Rotterdam, Departments of -# Medical Informatics and Radiology, Erasmus MC, Rotterdam, The Netherlands -# -# 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 configparser - - -def load_config(config_file_path): - """ Parse a WORC configuration file. - - Arguments: - config_file_path: path to the configuration file to be parsed. - - Returns: - settings_dict: dictionary containing all parsed settings. - """ - - settings = configparser.ConfigParser() - settings.read(config_file_path) - - settings_dict = {'ImageFeatures': dict(), 'General': dict(), - 'SVMFeatures': dict()} - - settings_dict['ImageFeatures']['image_type'] =\ - str(settings['ImageFeatures']['image_type']) - - settings_dict['General']['FeatureCalculator'] =\ - str(settings['General']['FeatureCalculator']) - - settings_dict['General']['Preprocessing'] =\ - str(settings['General']['Preprocessing']) - - settings_dict['General']['PCE'] =\ - settings['General'].getboolean('PCE') - - settings_dict['General']['Segmentix'] =\ - settings['General'].getboolean('Segmentix') - - return settings_dict diff --git a/build/lib/WORC/IOparser/config_io_classifier.py b/build/lib/WORC/IOparser/config_io_classifier.py deleted file mode 100644 index 60f811ce..00000000 --- a/build/lib/WORC/IOparser/config_io_classifier.py +++ /dev/null @@ -1,271 +0,0 @@ -#!/usr/bin/env python - -# Copyright 2016-2019 Biomedical Imaging Group Rotterdam, Departments of -# Medical Informatics and Radiology, Erasmus MC, Rotterdam, The Netherlands -# -# 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 configparser - - -def load_config(config_file_path): - """ - Load the config ini, parse settings to WORC - - Args: - config_file_path (String): path of the .ini config file - - Returns: - settings_dict (dict): dict with the loaded settings - """ - - settings = configparser.ConfigParser() - settings.read(config_file_path) - print(settings.keys()) - - settings_dict = {'General': dict(), 'CrossValidation': dict(), - 'Labels': dict(), 'HyperOptimization': dict(), - 'Classification': dict(), 'SelectFeatGroup': dict(), - 'Featsel': dict(), 'FeatureScaling': dict(), - 'SampleProcessing': dict(), 'Imputation': dict(), - 'Ensemble': dict()} - - settings_dict['General']['cross_validation'] =\ - settings['General'].getboolean('cross_validation') - - settings_dict['General']['Joblib_ncores'] =\ - settings['General'].getint('Joblib_ncores') - - settings_dict['General']['Joblib_backend'] =\ - str(settings['General']['Joblib_backend']) - - settings_dict['General']['tempsave'] =\ - settings['General'].getboolean('tempsave') - - settings_dict['Featsel']['Variance'] =\ - [str(item).strip() for item in - settings['Featsel']['Variance'].split(',')] - - settings_dict['Featsel']['SelectFromModel'] =\ - [str(item).strip() for item in - settings['Featsel']['SelectFromModel'].split(',')] - - settings_dict['Featsel']['GroupwiseSearch'] =\ - [str(item).strip() for item in - settings['Featsel']['GroupwiseSearch'].split(',')] - - settings_dict['Featsel']['UsePCA'] =\ - [str(item).strip() for item in - settings['Featsel']['UsePCA'].split(',')] - - settings_dict['Featsel']['PCAType'] =\ - [str(item).strip() for item in - settings['Featsel']['PCAType'].split(',')] - - settings_dict['Featsel']['StatisticalTestUse'] =\ - [str(item).strip() for item in - settings['Featsel']['StatisticalTestUse'].split(',')] - - settings_dict['Featsel']['StatisticalTestMetric'] =\ - [str(item).strip() for item in - settings['Featsel']['StatisticalTestMetric'].split(',')] - - settings_dict['Featsel']['StatisticalTestThreshold'] =\ - [float(str(item).strip()) for item in - settings['Featsel']['StatisticalTestThreshold'].split(',')] - - settings_dict['Featsel']['ReliefUse'] =\ - [str(item).strip() for item in - settings['Featsel']['ReliefUse'].split(',')] - - settings_dict['Featsel']['ReliefNN'] =\ - [int(str(item).strip()) for item in - settings['Featsel']['ReliefNN'].split(',')] - - settings_dict['Featsel']['ReliefSampleSize'] =\ - [int(str(item).strip()) for item in - settings['Featsel']['ReliefSampleSize'].split(',')] - - settings_dict['Featsel']['ReliefDistanceP'] =\ - [int(str(item).strip()) for item in - settings['Featsel']['ReliefDistanceP'].split(',')] - - settings_dict['Featsel']['ReliefNumFeatures'] =\ - [int(str(item).strip()) for item in - settings['Featsel']['ReliefNumFeatures'].split(',')] - - settings_dict['Imputation']['use'] =\ - [str(item).strip() for item in - settings['Imputation']['use'].split(',')] - - settings_dict['Imputation']['strategy'] =\ - [str(item).strip() for item in - settings['Imputation']['strategy'].split(',')] - - settings_dict['Imputation']['n_neighbors'] =\ - [int(str(item).strip()) for item in - settings['Imputation']['n_neighbors'].split(',')] - - settings_dict['General']['FeatureCalculator'] =\ - str(settings['General']['FeatureCalculator']) - - # Feature selection options - for key in settings['SelectFeatGroup'].keys(): - settings_dict['SelectFeatGroup'][key] =\ - [str(item).strip() for item in - settings['SelectFeatGroup'][key].split(',')] - - # Classification options - settings_dict['Classification']['fastr'] =\ - settings['Classification'].getboolean('fastr') - - settings_dict['Classification']['fastr_plugin'] =\ - str(settings['Classification']['fastr_plugin']) - - settings_dict['Classification']['classifiers'] =\ - [str(item).strip() for item in - settings['Classification']['classifiers'].split(',')] - - settings_dict['Classification']['max_iter'] =\ - [int(str(item).strip()) for item in - settings['Classification']['max_iter'].split(',')] - - # Specific SVM options - settings_dict['Classification']['SVMKernel'] =\ - [str(item).strip() for item in - settings['Classification']['SVMKernel'].split(',')] - - settings_dict['Classification']['SVMC'] =\ - [int(str(item).strip()) for item in - settings['Classification']['SVMC'].split(',')] - - settings_dict['Classification']['SVMdegree'] =\ - [int(str(item).strip()) for item in - settings['Classification']['SVMdegree'].split(',')] - - settings_dict['Classification']['SVMcoef0'] =\ - [int(str(item).strip()) for item in - settings['Classification']['SVMcoef0'].split(',')] - - settings_dict['Classification']['SVMgamma'] =\ - [int(str(item).strip()) for item in - settings['Classification']['SVMgamma'].split(',')] - - # Specific RF options - settings_dict['Classification']['RFn_estimators'] =\ - [int(str(item).strip()) for item in - settings['Classification']['RFn_estimators'].split(',')] - settings_dict['Classification']['RFmin_samples_split'] =\ - [int(str(item).strip()) for item in - settings['Classification']['RFmin_samples_split'].split(',')] - settings_dict['Classification']['RFmax_depth'] =\ - [int(str(item).strip()) for item in - settings['Classification']['RFmax_depth'].split(',')] - - # Specific LR options - settings_dict['Classification']['LRpenalty'] =\ - [str(item).strip() for item in - settings['Classification']['LRpenalty'].split(',')] - settings_dict['Classification']['LRC'] =\ - [float(str(item).strip()) for item in - settings['Classification']['LRC'].split(',')] - - # Specific LDA/QDA options - settings_dict['Classification']['LDA_solver'] =\ - [str(item).strip() for item in - settings['Classification']['LDA_solver'].split(',')] - settings_dict['Classification']['LDA_shrinkage'] =\ - [int(str(item).strip()) for item in - settings['Classification']['LDA_shrinkage'].split(',')] - settings_dict['Classification']['QDA_reg_param'] =\ - [int(str(item).strip()) for item in - settings['Classification']['QDA_reg_param'].split(',')] - - # ElasticNet options - settings_dict['Classification']['ElasticNet_alpha'] =\ - [int(str(item).strip()) for item in - settings['Classification']['ElasticNet_alpha'].split(',')] - settings_dict['Classification']['ElasticNet_l1_ratio'] =\ - [float(str(item).strip()) for item in - settings['Classification']['ElasticNet_l1_ratio'].split(',')] - - # SGD (R) options - settings_dict['Classification']['SGD_alpha'] =\ - [int(str(item).strip()) for item in - settings['Classification']['SGD_alpha'].split(',')] - settings_dict['Classification']['SGD_l1_ratio'] =\ - [float(str(item).strip()) for item in - settings['Classification']['SGD_l1_ratio'].split(',')] - settings_dict['Classification']['SGD_loss'] =\ - [str(item).strip() for item in - settings['Classification']['SGD_loss'].split(',')] - settings_dict['Classification']['SGD_penalty'] =\ - [str(item).strip() for item in - settings['Classification']['SGD_penalty'].split(',')] - - # Naive Bayes options - settings_dict['Classification']['CNB_alpha'] =\ - [int(str(item).strip()) for item in - settings['Classification']['CNB_alpha'].split(',')] - - # Cross validation settings - settings_dict['CrossValidation']['N_iterations'] =\ - settings['CrossValidation'].getint('N_iterations') - - settings_dict['CrossValidation']['test_size'] =\ - settings['CrossValidation'].getfloat('test_size') - - # Genetic settings - settings_dict['Labels']['label_names'] =\ - [str(item).strip() for item in - settings['Labels']['label_names'].split(',')] - - settings_dict['Labels']['modus'] =\ - str(settings['Labels']['modus']) - - # Settings for hyper optimization - settings_dict['HyperOptimization']['scoring_method'] =\ - str(settings['HyperOptimization']['scoring_method']) - settings_dict['HyperOptimization']['test_size'] =\ - settings['HyperOptimization'].getfloat('test_size') - settings_dict['HyperOptimization']['N_iter'] =\ - settings['HyperOptimization'].getint('N_iterations') - settings_dict['HyperOptimization']['n_jobspercore'] =\ - int(settings['HyperOptimization']['n_jobspercore']) - - settings_dict['FeatureScaling']['scale_features'] =\ - settings['FeatureScaling'].getboolean('scale_features') - settings_dict['FeatureScaling']['scaling_method'] =\ - str(settings['FeatureScaling']['scaling_method']) - - settings_dict['SampleProcessing']['SMOTE'] =\ - [str(item).strip() for item in - settings['SampleProcessing']['SMOTE'].split(',')] - - settings_dict['SampleProcessing']['SMOTE_ratio'] =\ - [int(str(item).strip()) for item in - settings['SampleProcessing']['SMOTE_ratio'].split(',')] - - settings_dict['SampleProcessing']['SMOTE_neighbors'] =\ - [int(str(item).strip()) for item in - settings['SampleProcessing']['SMOTE_neighbors'].split(',')] - - settings_dict['SampleProcessing']['Oversampling'] =\ - [str(item).strip() for item in - settings['SampleProcessing']['Oversampling'].split(',')] - - settings_dict['Ensemble']['Use'] =\ - settings['Ensemble'].getboolean('Use') - - return settings_dict diff --git a/build/lib/WORC/IOparser/config_preprocessing.py b/build/lib/WORC/IOparser/config_preprocessing.py deleted file mode 100644 index c8bf0cf2..00000000 --- a/build/lib/WORC/IOparser/config_preprocessing.py +++ /dev/null @@ -1,47 +0,0 @@ -#!/usr/bin/env python - -# Copyright 2016-2019 Biomedical Imaging Group Rotterdam, Departments of -# Medical Informatics and Radiology, Erasmus MC, Rotterdam, The Netherlands -# -# 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 configparser - - -def load_config(config_file_path): - """ Parse a WORC configuration file. - - Arguments: - config_file_path: path to the configuration file to be parsed. - - Returns: - settings_dict: dictionary containing all parsed settings. - """ - - settings = configparser.ConfigParser() - settings.read(config_file_path) - - settings_dict = {'Normalize': dict(), 'ImageFeatures': dict()} - - settings_dict['Normalize']['ROI'] =\ - str(settings['Normalize']['ROI']) - - settings_dict['Normalize']['Method'] =\ - str(settings['Normalize']['Method']) - - settings_dict['ImageFeatures']['image_type'] =\ - [str(item).strip() for item in - settings['ImageFeatures']['image_type'].split(',')] - - return settings_dict diff --git a/build/lib/WORC/IOparser/config_segmentix.py b/build/lib/WORC/IOparser/config_segmentix.py deleted file mode 100644 index 3a75f05e..00000000 --- a/build/lib/WORC/IOparser/config_segmentix.py +++ /dev/null @@ -1,54 +0,0 @@ -#!/usr/bin/env python - -# Copyright 2016-2019 Biomedical Imaging Group Rotterdam, Departments of -# Medical Informatics and Radiology, Erasmus MC, Rotterdam, The Netherlands -# -# 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 configparser - - -def load_config(config_file_path): - """ Parse a segmentix configuration file. - - Arguments: - config_file_path: path to the configuration file to be parsed. - - Returns: - settings_dict: dictionary containing all parsed settings. - """ - - settings = configparser.ConfigParser() - settings.read(config_file_path) - - settings_dict = {'Segmentix': dict()} - - # Segmentation settings - settings_dict['Sementix'] = dict() - settings_dict['Segmentix']['type'] =\ - str(settings['Segmentix']['segtype']) - - settings_dict['Segmentix']['mask'] =\ - str(settings['Segmentix']['mask']) - - settings_dict['Segmentix']['radius'] =\ - int(settings['Segmentix']['segradius']) - - settings_dict['Segmentix']['N_blobs'] =\ - int(settings['Segmentix']['N_blobs']) - - settings_dict['Segmentix']['fillholes'] =\ - settings['Segmentix'].getboolean('fillholes') - - return settings_dict diff --git a/build/lib/WORC/IOparser/file_io.py b/build/lib/WORC/IOparser/file_io.py deleted file mode 100644 index 8a369abc..00000000 --- a/build/lib/WORC/IOparser/file_io.py +++ /dev/null @@ -1,118 +0,0 @@ -#!/usr/bin/env python - -# Copyright 2016-2019 Biomedical Imaging Group Rotterdam, Departments of -# Medical Informatics and Radiology, Erasmus MC, Rotterdam, The Netherlands -# -# 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 pandas as pd -import WORC.processing.label_processing as lp -import WORC.addexceptions as WORCexceptions -import numpy as np - - -def load_data(featurefiles, patientinfo=None, label_names=None, modnames=[]): - ''' Read feature files and stack the features per patient in an array. - Additionally, if a patient label file is supplied, the features from - a patient will be matched to the labels. - - Parameters - ---------- - featurefiles: list, mandatory - List containing all paths to the .hdf5 feature files to be loaded. - The argument should contain a list per modelity, e.g. - [[features_mod1_patient1, features_mod1_patient2, ...], - [features_mod2_patient1, features_mod2_patient2, ...]]. - - patientinfo: string, optional - Path referring to the .txt file to be used to read patient - labels from. See the Github Wiki for the format. - - label_names: list, optional - List containing all the labels that should be extracted from - the patientinfo file. - - ''' - - # Read out all feature values and labels - image_features_temp = list() - feature_labels_all = list() - for i_patient in range(0, len(featurefiles[0])): - feature_values_temp = list() - feature_labels_temp = list() - for i_mod in range(0, len(featurefiles)): - feat_temp = pd.read_hdf(featurefiles[i_mod][i_patient]) - feature_values_temp += feat_temp.feature_values - if not modnames: - # Create artificial names - feature_labels_temp += [f + '_M' + str(i_mod) for f in feat_temp.feature_labels] - else: - # Use the provides modality names - feature_labels_temp += [f + '_' + str(modnames[i_mod]) for f in feat_temp.feature_labels] - - image_features_temp.append((feature_values_temp, feature_labels_temp)) - - # Also make a list of all unique label names - feature_labels_all = feature_labels_all + list(set(feature_labels_temp) - set(feature_labels_all)) - - # If some objects miss certain features, we will identify these with NaN values - feature_labels_all.sort() - image_features = list() - for patient in image_features_temp: - feat_temp = patient[0] - label_temp = patient[1] - - feat = list() - for f in feature_labels_all: - if f in label_temp: - index = label_temp.index(f) - fv = feat_temp[index] - else: - fv = np.NaN - feat.append(fv) - - image_features.append((feat, feature_labels_all)) - - # Get the labels and patient IDs - if patientinfo is not None: - # We use the feature files of the first modality to match to patient name - pfiles = featurefiles[0] - try: - label_data, image_features =\ - lp.findlabeldata(patientinfo, - label_names, - pfiles, - image_features) - except ValueError as e: - message = e.message + '. Please take a look at your labels' +\ - ' file and make sure it is formatted correctly. ' +\ - 'See also https://github.com/MStarmans91/WORC/wiki/The-WORC-configuration#genetics.' - raise WORCexceptions.WORCValueError(message) - - print("Labels:") - print(label_data['label']) - print('Total of ' + str(label_data['patient_IDs'].shape[0]) + - ' patients') - pos = np.sum(label_data['label']) - neg = label_data['patient_IDs'].shape[0] - pos - print(('{} positives, {} negatives').format(pos, neg)) - else: - # Use filenames as patient ID s - patient_IDs = list() - for i in featurefiles: - patient_IDs.append(os.path.basename(i)) - label_data = dict() - label_data['patient_IDs'] = patient_IDs - - return label_data, image_features diff --git a/build/lib/WORC/WORC.py b/build/lib/WORC/WORC.py deleted file mode 100644 index 0956bb2d..00000000 --- a/build/lib/WORC/WORC.py +++ /dev/null @@ -1,982 +0,0 @@ -#!/usr/bin/env python - -# Copyright 2016-2019 Biomedical Imaging Group Rotterdam, Departments of -# Medical Informatics and Radiology, Erasmus MC, Rotterdam, The Netherlands -# -# 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 configparser -import fastr -from fastr.api import ResourceLimit -import os -from random import randint -import WORC.addexceptions as WORCexceptions -import WORC.IOparser.config_WORC as config_io -from WORC.tools.Elastix import Elastix -from WORC.tools.Evaluate import Evaluate - - -class WORC(object): - """ - A Workflow for Optimal Radiomics Classification (WORC) object that - serves as a pipeline spawner and manager for optimizating radiomics - studies. Depending on the attributes set, the object will spawn an - appropriate pipeline and manage it. - - Note that many attributes are lists and can therefore contain multiple - instances. For example, when providing two sequences per patient, - the "images" list contains two items. The type of items in the lists - is described below. - - All objects that serve as source for your network, i.e. refer to - actual files to be used, should be formatted as fastr sources suited for - one of the fastr plugings, see also - http://fastr.readthedocs.io/en/stable/fastr.reference.html#ioplugin-reference - The objects should be lists of these fastr sources or dictionaries with the - sample ID's, e.g. - - images_train = [{'Patient001': vfs://input/CT001.nii.gz, - 'Patient002': vfs://input/CT002.nii.gz}, - {'Patient001': vfs://input/MR001.nii.gz, - 'Patient002': vfs://input/MR002.nii.gz}] - - Attributes - ------------------ - name: String, default 'WORC' - name of the network. - - configs: list, required - Configuration parameters, either ConfigParser objects - created through the defaultconfig function or paths of config .ini - files. (list, required) - - labels: list, required - Paths to files containing patient labels (.txt files). - - network: automatically generated - The FASTR network generated through the "build" function. - - images: list, optional - Paths refering to the images used for Radiomics computation. Images - should be of the ITK Image type. - - segmentations: list, optional - Paths refering to the segmentations used for Radiomics computation. - Segmentations should be of the ITK Image type. - - semantics: semantic features per image type (list, optional) - - masks: state which pixels of images are valid (list, optional) - - features: input Radiomics features for classification (list, optional) - - metadata: DICOM headers belonging to images (list, optional) - - Elastix_Para: parameter files for Elastix (list, optional) - - fastr_plugin: plugin to use for FASTR execution - - fastr_tempdir: temporary directory to use for FASTR execution - - additions: additional inputs for your network (dict, optional) - - source_data: data to use as sources for FASTR (dict) - - sink_data: data to use as sinks for FASTR (dict) - - CopyMetadata: Boolean, default True - when using elastix, copy metadata from image to segmentation or not - - - """ - - def __init__(self, name='WORC'): - """Initialize WORC object. Set the initial variables all to None, - except for some defaults. - - Arguments: - name: name of the nework (string, optional) - - """ - self.name = name - - # Initialize several objects - self.configs = list() - self.fastrconfigs = list() - - self.images_train = list() - self.segmentations_train = list() - self.semantics_train = list() - self.labels_train = list() - self.masks_train = list() - self.features_train = list() - self.metadata_train = list() - - self.images_test = list() - self.segmentations_test = list() - self.semantics_test = list() - self.labels_test = list() - self.masks_test = list() - self.features_test = list() - self.metadata_test = list() - - self.Elastix_Para = list() - - # Set some defaults, name - self.fastr_plugin = 'ProcessPoolExecution' - if name == '': - name = [randint(0, 9) for p in range(0, 5)] - self.fastr_tmpdir = os.path.join(fastr.config.mounts['tmp'], 'WORC_' + str(name)) - - self.additions = dict() - self.CopyMetadata = True - self.segmode = [] - - def defaultconfig(self): - """Generate a configparser object holding all default configuration values. - - Returns: - config: configparser configuration file - - """ - # TODO: cluster parallel execution parameters - config = configparser.ConfigParser() - config.optionxform = str - - # General configuration of WORC - config['General'] = dict() - config['General']['cross_validation'] = 'True' - config['General']['Segmentix'] = 'False' - config['General']['FeatureCalculator'] = 'predict/CalcFeatures:1.0' - config['General']['Preprocessing'] = 'worc/PreProcess:1.0' - config['General']['RegistrationNode'] = "'elastix4.8/Elastix:4.8'" - config['General']['TransformationNode'] = "'elastix4.8/Transformix:4.8'" - config['General']['Joblib_ncores'] = '4' - config['General']['Joblib_backend'] = 'multiprocessing' - config['General']['tempsave'] = 'False' - - # Segmentix - config['Segmentix'] = dict() - config['Segmentix']['mask'] = 'subtract' - config['Segmentix']['segtype'] = 'None' - config['Segmentix']['segradius'] = '5' - config['Segmentix']['N_blobs'] = '1' - config['Segmentix']['fillholes'] = 'False' - - # Preprocessing - config['Normalize'] = dict() - config['Normalize']['ROI'] = 'Full' - config['Normalize']['Method'] = 'z_score' - - # PREDICT - Feature calculation - # Determine which features are calculated - config['ImageFeatures'] = dict() - config['ImageFeatures']['shape'] = 'True' - config['ImageFeatures']['histogram'] = 'True' - config['ImageFeatures']['orientation'] = 'True' - config['ImageFeatures']['texture_Gabor'] = 'False' - config['ImageFeatures']['texture_LBP'] = 'True' - config['ImageFeatures']['texture_GLCM'] = 'True' - config['ImageFeatures']['texture_GLCMMS'] = 'True' - config['ImageFeatures']['texture_GLRLM'] = 'True' - config['ImageFeatures']['texture_GLSZM'] = 'True' - config['ImageFeatures']['texture_NGTDM'] = 'True' - config['ImageFeatures']['coliage'] = 'False' - config['ImageFeatures']['vessel'] = 'False' - config['ImageFeatures']['log'] = 'False' - config['ImageFeatures']['phase'] = 'False' - - # Parameter settings for PREDICT feature calculation - # Defines what should be done with the images - config['ImageFeatures']['image_type'] = 'CT' - - # Define frequencies for gabor filter in pixels - config['ImageFeatures']['gabor_frequencies'] = '0.05, 0.2, 0.5' - - # Gabor, GLCM angles in degrees and radians, respectively - config['ImageFeatures']['gabor_angles'] = '0, 45, 90, 135' - config['ImageFeatures']['GLCM_angles'] = '0, 0.79, 1.57, 2.36' - - # GLCM discretization levels, distances in pixels - config['ImageFeatures']['GLCM_levels'] = '16' - config['ImageFeatures']['GLCM_distances'] = '1, 3' - - # LBP radius, number of points in pixels - config['ImageFeatures']['LBP_radius'] = '3, 8, 15' - config['ImageFeatures']['LBP_npoints'] = '12, 24, 36' - - # Phase features minimal wavelength and number of scales - config['ImageFeatures']['phase_minwavelength'] = '3' - config['ImageFeatures']['phase_nscale'] = '5' - - # Log features sigma of Gaussian in pixels - config['ImageFeatures']['log_sigma'] = '1, 5, 10' - - # Vessel features scale range, steps for the range - config['ImageFeatures']['vessel_scale_range'] = '1, 10' - config['ImageFeatures']['vessel_scale_step'] = '2' - - # Vessel features radius for erosion to determine boudnary - config['ImageFeatures']['vessel_radius'] = '5' - - # Feature selection - config['Featsel'] = dict() - config['Featsel']['Variance'] = 'True, False' - config['Featsel']['GroupwiseSearch'] = 'True' - config['Featsel']['SelectFromModel'] = 'False' - config['Featsel']['UsePCA'] = 'False' - config['Featsel']['PCAType'] = '95variance' - config['Featsel']['StatisticalTestUse'] = 'False' - config['Featsel']['StatisticalTestMetric'] = 'ttest, Welch, Wilcoxon, MannWhitneyU' - config['Featsel']['StatisticalTestThreshold'] = '0.02, 0.2' - config['Featsel']['ReliefUse'] = 'False' - config['Featsel']['ReliefNN'] = '2, 4' - config['Featsel']['ReliefSampleSize'] = '1, 1' - config['Featsel']['ReliefDistanceP'] = '1, 3' - config['Featsel']['ReliefNumFeatures'] = '25, 200' - - # Groupwise Featureselection options - config['SelectFeatGroup'] = dict() - config['SelectFeatGroup']['shape_features'] = 'True, False' - config['SelectFeatGroup']['histogram_features'] = 'True, False' - config['SelectFeatGroup']['orientation_features'] = 'True, False' - config['SelectFeatGroup']['texture_Gabor_features'] = 'True, False' - config['SelectFeatGroup']['texture_GLCM_features'] = 'True, False' - config['SelectFeatGroup']['texture_GLCMMS_features'] = 'True, False' - config['SelectFeatGroup']['texture_GLRLM_features'] = 'True, False' - config['SelectFeatGroup']['texture_GLSZM_features'] = 'True, False' - config['SelectFeatGroup']['texture_NGTDM_features'] = 'True, False' - config['SelectFeatGroup']['texture_LBP_features'] = 'True, False' - config['SelectFeatGroup']['patient_features'] = 'False' - config['SelectFeatGroup']['semantic_features'] = 'False' - config['SelectFeatGroup']['coliage_features'] = 'False' - config['SelectFeatGroup']['log_features'] = 'False' - config['SelectFeatGroup']['vessel_features'] = 'False' - config['SelectFeatGroup']['phase_features'] = 'False' - - # Feature imputation - config['Imputation'] = dict() - config['Imputation']['use'] = 'False' - config['Imputation']['strategy'] = 'mean, median, most_frequent, constant, knn' - config['Imputation']['n_neighbors'] = '5, 5' - - # Classification - config['Classification'] = dict() - config['Classification']['fastr'] = 'True' - config['Classification']['fastr_plugin'] = self.fastr_plugin - config['Classification']['classifiers'] = 'SVM' - config['Classification']['max_iter'] = '100000' - config['Classification']['SVMKernel'] = 'poly' - config['Classification']['SVMC'] = '0, 6' - config['Classification']['SVMdegree'] = '1, 6' - config['Classification']['SVMcoef0'] = '0, 1' - config['Classification']['SVMgamma'] = '-5, 5' - config['Classification']['RFn_estimators'] = '10, 90' - config['Classification']['RFmin_samples_split'] = '2, 3' - config['Classification']['RFmax_depth'] = '5, 5' - config['Classification']['LRpenalty'] = 'l2, l1' - config['Classification']['LRC'] = '0.01, 1.0' - config['Classification']['LDA_solver'] = 'svd, lsqr, eigen' - config['Classification']['LDA_shrinkage'] = '-5, 5' - config['Classification']['QDA_reg_param'] = '-5, 5' - config['Classification']['ElasticNet_alpha'] = '-5, 5' - config['Classification']['ElasticNet_l1_ratio'] = '0, 1' - config['Classification']['SGD_alpha'] = '-5, 5' - config['Classification']['SGD_l1_ratio'] = '0, 1' - config['Classification']['SGD_loss'] = 'hinge, squared_hinge, modified_huber' - config['Classification']['SGD_penalty'] = 'none, l2, l1' - config['Classification']['CNB_alpha'] = '0, 1' - - # CrossValidation - config['CrossValidation'] = dict() - config['CrossValidation']['N_iterations'] = '100' - config['CrossValidation']['test_size'] = '0.2' - - # Options for the object/patient labels that are used - config['Labels'] = dict() - config['Labels']['label_names'] = 'Label1, Label2' - config['Labels']['modus'] = 'singlelabel' - config['Labels']['url'] = 'WIP' - config['Labels']['projectID'] = 'WIP' - - # Hyperparameter optimization options - config['HyperOptimization'] = dict() - config['HyperOptimization']['scoring_method'] = 'f1_weighted' - config['HyperOptimization']['test_size'] = '0.15' - config['HyperOptimization']['N_iterations'] = '10000' - config['HyperOptimization']['n_jobspercore'] = '2000' # only relevant when using fastr in classification - - # Feature scaling options - config['FeatureScaling'] = dict() - config['FeatureScaling']['scale_features'] = 'True' - config['FeatureScaling']['scaling_method'] = 'z_score' - - # Sample processing options - config['SampleProcessing'] = dict() - config['SampleProcessing']['SMOTE'] = 'True' - config['SampleProcessing']['SMOTE_ratio'] = '1, 0' - config['SampleProcessing']['SMOTE_neighbors'] = '5, 15' - config['SampleProcessing']['Oversampling'] = 'False' - - # Ensemble options - config['Ensemble'] = dict() - config['Ensemble']['Use'] = 'False' # Still WIP - - return config - - def add_tools(self): - self.Tools = Tools() - - def build(self, wtype='training'): - """Build the network based on the given attributes. - - Parameters - ---------- - wtype: string, default 'training' - Specify the WORC execution type. - - testing: use if you have a trained classifier and want to - train it on some new images. - - training: use if you want to train a classifier from a dataset. - - """ - - self.wtype = wtype - if wtype == 'training': - self.build_training() - elif wtype == 'testing': - self.build_testing() - - def build_training(self): - """Build the training network based on the given attributes.""" - # We either need images or features for Radiomics - if self.images_train or self.features_train: - # We currently require labels for supervised learning - if self.labels_train: - if not self.configs: - print("No configuration given, assuming default") - if self.images_train: - self.configs = [self.defaultconfig()] * len(self.images_train) - else: - self.configs = [self.defaultconfig()] * len(self.features_train) - self.network = fastr.create_network('WORC_' + self.name) - - # BUG: We currently use the first configuration as general config - image_types = list() - for c in range(len(self.configs)): - if type(self.configs[c]) == str: - # Probably, c is a configuration file - self.configs[c] = config_io.load_config(self.configs[c]) - image_types.append(self.configs[c]['ImageFeatures']['image_type']) - - # Create config source - self.source_class_config = self.network.create_source('ParameterFile', id='config_classification_source', node_group='conf') - - # Classification tool and label source - self.source_patientclass_train = self.network.create_source('PatientInfoFile', id='patientclass_train', node_group='pctrain') - if self.labels_test: - self.source_patientclass_test = self.network.create_source('PatientInfoFile', id='patientclass_test', node_group='pctest') - - self.classify = self.network.create_node('worc/TrainClassifier:1.0', tool_version='1.0', id='classify', resources=ResourceLimit(memory='12G')) - - # Outputs - self.sink_classification = self.network.create_sink('HDF5', id='classification') - self.sink_performance = self.network.create_sink('JsonFile', id='performance') - self.sink_class_config = self.network.create_sink('ParameterFile', id='config_classification_sink', node_group='conf') - - # Links - self.sink_class_config.input = self.source_class_config.output - self.link_class_1 = self.network.create_link(self.source_class_config.output, self.classify.inputs['config']) - self.link_class_2 = self.network.create_link(self.source_patientclass_train.output, self.classify.inputs['patientclass_train']) - self.link_class_1.collapse = 'conf' - self.link_class_2.collapse = 'pctrain' - - if self.images_test or self.features_test: - # FIXME: the naming here is ugly - self.link_class_3 = self.network.create_link(self.source_patientclass_test.output, self.classify.inputs['patientclass_test']) - self.link_class_3.collapse = 'pctest' - - self.sink_classification.input = self.classify.outputs['classification'] - self.sink_performance.input = self.classify.outputs['performance'] - - if not self.features_train: - # Create nodes to compute features - self.sources_parameters = dict() - - self.calcfeatures_train = dict() - self.preprocessing_train = dict() - self.sources_images_train = dict() - self.sinks_features_train = dict() - self.converters_im_train = dict() - self.converters_seg_train = dict() - self.links_C1_train = dict() - - if self.images_test or self.features_test: - # A test set is supplied, for which nodes also need to be created - self.preprocessing_test = dict() - self.calcfeatures_test = dict() - self.sources_images_test = dict() - self.sinks_features_test = dict() - self.converters_im_test = dict() - self.converters_seg_test = dict() - self.links_C1_test = dict() - - # Check which nodes are necessary - if not self.segmentations_train: - message = "No automatic segmentation method is yet implemented." - raise WORCexceptions.WORCNotImplementedError(message) - - elif len(self.segmentations_train) == len(image_types): - # Segmentations provided - self.sources_segmentations_train = dict() - self.sources_segmentations_test = dict() - self.segmode = 'Provided' - - elif len(self.segmentations_train) == 1: - # Assume segmentations need to be registered to other modalities - self.sources_segmentation = dict() - self.segmode = 'Register' - - self.source_Elastix_Parameters = dict() - self.elastix_nodes_train = dict() - self.transformix_seg_nodes_train = dict() - self.sources_segmentations_train = dict() - self.sinks_transformations_train = dict() - self.sinks_segmentations_elastix_train = dict() - self.sinks_images_elastix_train = dict() - self.converters_seg_train = dict() - self.edittransformfile_nodes_train = dict() - self.transformix_im_nodes_train = dict() - - self.elastix_nodes_test = dict() - self.transformix_seg_nodes_test = dict() - self.sources_segmentations_test = dict() - self.sinks_transformations_test = dict() - self.sinks_segmentations_elastix_test = dict() - self.sinks_images_elastix_test = dict() - self.converters_seg_test = dict() - self.edittransformfile_nodes_test = dict() - self.transformix_im_nodes_test = dict() - pass - - # BUG: We assume that first type defines if we use segmentix - if self.configs[0]['General']['Segmentix'] == 'True': - # Use the segmentix toolbox for segmentation processing - self.sinks_segmentations_segmentix_train = dict() - self.sources_masks_train = dict() - self.converters_masks_train = dict() - self.nodes_segmentix_train = dict() - - if self.images_test or self.features_test: - # Also use segmentix on the tes set - self.sinks_segmentations_segmentix_test = dict() - self.sources_masks_test = dict() - self.converters_masks_test = dict() - self.nodes_segmentix_test = dict() - - if self.semantics_train: - # Semantic features are supplied - self.sources_semantics_train = dict() - - if self.metadata_train: - # Metadata to extract patient features from is supplied - self.sources_metadata_train = dict() - - if self.semantics_test: - # Semantic features are supplied - self.sources_semantics_test = dict() - - if self.metadata_test: - # Metadata to extract patient features from is supplied - self.sources_metadata_test = dict() - - # Create a part of the pipeline for each modality - self.modlabels = list() - for nmod, mod in enumerate(image_types): - # Create label for each modality/image - num = 0 - label = mod + '_' + str(num) - while label in self.calcfeatures_train.keys(): - # if label already exists, add number to label - num += 1 - label = mod + '_' + str(num) - self.modlabels.append(label) - - # Create required sources and sinks - self.sources_parameters[label] = self.network.create_source('ParameterFile', id='parameters_' + label) - self.sources_images_train[label] = self.network.create_source('ITKImageFile', id='images_train_' + label, node_group='train') - self.sinks_features_train[label] = self.network.create_sink('HDF5', id='features_train_' + label) - if self.images_test or self.features_test: - self.sources_images_test[label] = self.network.create_source('ITKImageFile', id='images_test_' + label, node_group='test') - self.sinks_features_test[label] = self.network.create_sink('HDF5', id='features_test_' + label) - - if self.metadata_train and len(self.metadata_train) >= nmod + 1: - self.sources_metadata_train[label] = self.network.create_source('DicomImageFile', id='metadata_train_' + label, node_group='train') - - if self.metadata_test and len(self.metadata_test) >= nmod + 1: - self.sources_metadata_test[label] = self.network.create_source('DicomImageFile', id='metadata_test_' + label, node_group='test') - - if self.masks_train and len(self.masks_train) >= nmod + 1: - # Create mask source and convert - self.sources_masks_train[label] = self.network.create_source('ITKImageFile', id='mask_train_' + label, node_group='train') - self.converters_masks_train[label] = self.network.create_node('worc/WORCCastConvert:0.3.2', tool_version='0.1', id='convert_mask_train_' + label, node_group='train', resources=ResourceLimit(memory='4G')) - self.converters_masks_train[label].inputs['image'] = self.sources_masks_train[label].output - - if self.masks_test and len(self.masks_test) >= nmod + 1: - # Create mask source and convert - self.sources_masks_test[label] = self.network.create_source('ITKImageFile', id='mask_test_' + label, node_group='test') - self.converters_masks_test[label] = self.network.create_node('worc/WORCCastConvert:0.3.2', tool_version='0.1', id='convert_mask_test_' + label, node_group='test', resources=ResourceLimit(memory='4G')) - self.converters_masks_test[label].inputs['image'] = self.sources_masks_test[label].output - - # First convert the images - if any(modality in mod for modality in ['MR', 'CT', 'MG', 'PET']): - # Use ITKTools PXCastConvet for converting image formats - self.converters_im_train[label] = self.network.create_node('worc/WORCCastConvert:0.3.2', tool_version='0.1', id='convert_im_train_' + label, resources=ResourceLimit(memory='4G')) - if self.images_test or self.features_test: - self.converters_im_test[label] = self.network.create_node('worc/WORCCastConvert:0.3.2', tool_version='0.1', id='convert_im_test_' + label, resources=ResourceLimit(memory='4G')) - - else: - raise WORCexceptions.WORCTypeError(('No valid image type for modality {}: {} provided.').format(str(nmod), mod)) - - # Create required links - self.converters_im_train[label].inputs['image'] = self.sources_images_train[label].output - if self.images_test or self.features_test: - self.converters_im_test[label].inputs['image'] = self.sources_images_test[label].output - - # ----------------------------------------------------- - # Preprocessing - # Create nodes - preprocess_node = str(self.configs[nmod]['General']['Preprocessing']) - self.preprocessing_train[label] = self.network.create_node(preprocess_node, tool_version='1.0', id='preprocessing_train_' + label, resources=ResourceLimit(memory='4G')) - if self.images_test or self.features_test: - self.preprocessing_test[label] = self.network.create_node(preprocess_node, tool_version='1.0', id='preprocessing_test_' + label, resources=ResourceLimit(memory='4G')) - - # Create required links - self.preprocessing_train[label].inputs['parameters'] = self.sources_parameters[label].output - self.preprocessing_train[label].inputs['image'] = self.converters_im_train[label].outputs['image'] - - if self.images_test or self.features_test: - self.preprocessing_test[label].inputs['parameters'] = self.sources_parameters[label].output - self.preprocessing_test[label].inputs['image'] = self.converters_im_test[label].outputs['image'] - - if self.metadata_train and len(self.metadata_train) >= nmod + 1: - self.preprocessing_train[label].inputs['metadata'] = self.sources_metadata_train[label].output - - if self.metadata_test and len(self.metadata_test) >= nmod + 1: - self.preprocessing_test[label].inputs['metadata'] = self.sources_metadata_test[label].output - - # ----------------------------------------------------- - # Create a feature calculator node - calcfeat_node = str(self.configs[nmod]['General']['FeatureCalculator']) - self.calcfeatures_train[label] = self.network.create_node(calcfeat_node, tool_version='1.0', id='calcfeatures_train_' + label, resources=ResourceLimit(memory='14G')) - if self.images_test or self.features_test: - self.calcfeatures_test[label] = self.network.create_node(calcfeat_node, tool_version='1.0', id='calcfeatures_test_' + label, resources=ResourceLimit(memory='14G')) - - # Create required links - self.calcfeatures_train[label].inputs['parameters'] = self.sources_parameters[label].output - self.calcfeatures_train[label].inputs['image'] = self.preprocessing_train[label].outputs['image'] - - if self.images_test or self.features_test: - self.calcfeatures_test[label].inputs['parameters'] = self.sources_parameters[label].output - self.calcfeatures_test[label].inputs['image'] = self.preprocessing_test[label].outputs['image'] - - if self.metadata_train and len(self.metadata_train) >= nmod + 1: - self.calcfeatures_train[label].inputs['metadata'] = self.sources_metadata_train[label].output - - if self.metadata_train and len(self.metadata_test) >= nmod + 1: - self.calcfeatures_train[label].inputs['metadata'] = self.sources_metadata_train[label].output - - if self.semantics_train and len(self.semantics_train) >= nmod + 1: - self.sources_semantics_train[label] = self.network.create_source('CSVFile', id='semantics_train_' + label) - self.calcfeatures_train[label].inputs['semantics'] = self.sources_semantics_train[label].output - - if self.semantics_test and len(self.semantics_test) >= nmod + 1: - self.sources_semantics_test[label] = self.network.create_source('CSVFile', id='semantics_test_' + label) - self.calcfeatures_test[label].inputs['semantics'] = self.sources_semantics_test[label].output - - if self.segmode == 'Provided': - # Segmentation ----------------------------------------------------- - # Use the provided segmantions for each modality - self.sources_segmentations_train[label] = self.network.create_source('ITKImageFile', id='segmentations_train_' + label, node_group='train') - self.converters_seg_train[label] = self.network.create_node('worc/WORCCastConvert:0.3.2', tool_version='0.1', id='convert_seg_train_' + label, resources=ResourceLimit(memory='4G')) - self.converters_seg_train[label].inputs['image'] = self.sources_segmentations_train[label].output - - if self.images_test or self.features_test: - self.sources_segmentations_test[label] = self.network.create_source('ITKImageFile', id='segmentations_test_' + label, node_group='test') - self.converters_seg_test[label] = self.network.create_node('worc/WORCCastConvert:0.3.2', tool_version='0.1', id='convert_seg_test_' + label, resources=ResourceLimit(memory='4G')) - self.converters_seg_test[label].inputs['image'] = self.sources_segmentations_test[label].output - - elif self.segmode == 'Register': - # Registration nodes ----------------------------------------------------- - # Align segmentation of first modality to others using registration with Elastix - - # Create sources and converter for only for the given segmentation, which should be on the first modality - if nmod == 0: - self.sources_segmentations_train[label] = self.network.create_source('ITKImageFile', id='segmentations_train_' + label, node_group='input') - self.converters_seg_train[label] = self.network.create_node('worc/WORCCastConvert:0.3.2', tool_version='0.1', id='convert_seg_train_' + label, resources=ResourceLimit(memory='4G')) - self.converters_seg_train[label].inputs['image'] = self.sources_segmentations_train[label].output - - if self.images_test or self.features_test: - self.sources_segmentations_test[label] = self.network.create_source('ITKImageFile', id='segmentations_test_' + label, node_group='input') - self.converters_seg_test[label] = self.network.create_node('worc/WORCCastConvert:0.3.2', tool_version='0.1', id='convert_seg_test_' + label, resources=ResourceLimit(memory='4G')) - self.converters_seg_test[label].inputs['image'] = self.sources_segmentations_test[label].output - - # Assume provided segmentation is on first modality - if nmod > 0: - # Use elastix and transformix for registration - # NOTE: Assume elastix node type is on first configuration - elastix_node = str(self.configs[0]['General']['RegistrationNode']) - transformix_node = str(self.configs[0]['General']['TransformationNode']) - self.elastix_nodes_train[label] = self.network.create_node(elastix_node, tool_version='0.2', id='elastix_train_' + label, resources=ResourceLimit(memory='4G')) - self.transformix_seg_nodes_train[label] = self.network.create_node(transformix_node, tool_version= '0.2' , id='transformix_seg_train_' + label) - self.transformix_im_nodes_train[label] = self.network.create_node(transformix_node, tool_version= '0.2' , id='transformix_im_train_' + label) - - if self.images_test or self.features_test: - self.elastix_nodes_test[label] = self.network.create_node(elastix_node, tool_version='0.2', id='elastix_test_' + label, resources=ResourceLimit(memory='4G')) - self.transformix_seg_nodes_test[label] = self.network.create_node(transformix_node, tool_version= '0.2' , id='transformix_seg_test_' + label) - self.transformix_im_nodes_test[label] = self.network.create_node(transformix_node, tool_version= '0.2' , id='transformix_im_test_' + label) - - # Create sources_segmentation - # M1 = moving, others = fixed - self.elastix_nodes_train[label].inputs['fixed_image'] = self.converters_im_train[label].outputs['image'] - self.elastix_nodes_train[label].inputs['moving_image'] = self.converters_im_train[self.modlabels[0]].outputs['image'] - - # Add node that copies metadata from the image to the segmentation if required - if self.CopyMetadata: - # Copy metadata from the image which was registered to the segmentation, if it is not created yet - if not hasattr(self, "copymetadata_nodes_train"): - # NOTE: Do this for first modality, as we assume segmentation is on that one - self.copymetadata_nodes_train = dict() - self.copymetadata_nodes_train[self.modlabels[0]] = self.network.create_node('itktools/0.3.2/CopyMetadata:1.0', tool_version= '1.0' , id='CopyMetadata_train_' + self.modlabels[0]) - self.copymetadata_nodes_train[self.modlabels[0]].inputs["source"] = self.converters_im_train[self.modlabels[0]].outputs['image'] - self.copymetadata_nodes_train[self.modlabels[0]].inputs["destination"] = self.converters_seg_train[self.modlabels[0]].outputs['image'] - self.transformix_seg_nodes_train[label].inputs['image'] = self.copymetadata_nodes_train[self.modlabels[0]].outputs['output'] - else: - self.transformix_seg_nodes_train[label].inputs['image'] = self.converters_seg_train[self.modlabels[0]].outputs['image'] - - if self.images_test or self.features_test: - self.elastix_nodes_test[label].inputs['fixed_image'] = self.converters_im_test[label].outputs['image'] - self.elastix_nodes_test[label].inputs['moving_image'] = self.converters_im_test[self.modlabels[0]].outputs['image'] - - if self.CopyMetadata: - # Copy metadata from the image which was registered to the segmentation - if not hasattr(self, "copymetadata_nodes_test"): - # NOTE: Do this for first modality, as we assume segmentation is on that one - self.copymetadata_nodes_test = dict() - self.copymetadata_nodes_test[self.modlabels[0]] = self.network.create_node('itktools/0.3.2/CopyMetadata:1.0', tool_version= '1.0' , id='CopyMetadata_test_' + self.modlabels[0]) - self.copymetadata_nodes_test[self.modlabels[0]].inputs["source"] = self.converters_im_test[self.modlabels[0]].outputs['image'] - self.copymetadata_nodes_test[self.modlabels[0]].inputs["destination"] = self.converters_seg_test[self.modlabels[0]].outputs['image'] - self.transformix_seg_nodes_test[label].inputs['image'] = self.copymetadata_nodes_test[self.modlabels[0]].outputs['output'] - else: - self.transformix_seg_nodes_test[label].inputs['image'] = self.converters_seg_test[self.modlabels[0]].outputs['image'] - - # Apply registration to input modalities - self.source_Elastix_Parameters[label] = self.network.create_source('ElastixParameterFile', id='Elastix_Para_' + label, node_group='elpara') - self.link_elparam_train = self.network.create_link(self.source_Elastix_Parameters[label].output, - self.elastix_nodes_train[label].inputs['parameters']) - self.link_elparam_train.collapse = 'elpara' - - if self.images_test or self.features_test: - self.link_elparam_test = self.network.create_link(self.source_Elastix_Parameters[label].output, - self.elastix_nodes_test[label].inputs['parameters']) - self.link_elparam_test.collapse = 'elpara' - - if self.masks_train: - self.elastix_nodes_train[label].inputs['fixed_mask'] = self.converters_masks_train[label].outputs['image'] - self.elastix_nodes_train[label].inputs['moving_mask'] = self.converters_masks_train[self.modlabels[0]].outputs['image'] - - if self.images_test or self.features_test: - if self.masks_test: - self.elastix_nodes_test[label].inputs['fixed_mask'] = self.converters_masks_test[label].outputs['image'] - self.elastix_nodes_test[label].inputs['moving_mask'] = self.converters_masks_test[self.modlabels[0]].outputs['image'] - - # Change the FinalBSpline Interpolation order to 0 as required for binarie images: see https://github.com/SuperElastix/elastix/wiki/FAQ - self.edittransformfile_nodes_train[label] = self.network.create_node('elastixtools/EditElastixTransformFile:0.1', tool_version= '0.1' , id='EditElastixTransformFile' + label) - self.edittransformfile_nodes_train[label].inputs['set'] = ["FinalBSplineInterpolationOrder=0"] - self.edittransformfile_nodes_train[label].inputs['transform'] = self.elastix_nodes_train[label].outputs['transform'][-1] - - if self.images_test or self.features_test: - self.edittransformfile_nodes_test[label] = self.network.create_node('elastixtools/EditElastixTransformFile:0.1', tool_version= '0.1' , id='EditElastixTransformFile' + label) - self.edittransformfile_nodes_test[label].inputs['set'] = ["FinalBSplineInterpolationOrder=0"] - self.edittransformfile_nodes_test[label].inputs['transform'] = self.elastix_nodes_test[label].outputs['transform'][-1] - - # Link data and transformation to transformix and source - self.transformix_seg_nodes_train[label].inputs['transform'] = self.edittransformfile_nodes_train[label].outputs['transform'] - self.calcfeatures_train[label].inputs['segmentation'] = self.transformix_seg_nodes_train[label].outputs['image'] - - self.transformix_im_nodes_train[label].inputs['transform'] = self.elastix_nodes_train[label].outputs['transform'][-1] - self.transformix_im_nodes_train[label].inputs['image'] = self.converters_im_train[self.modlabels[0]].outputs['image'] - - if self.images_test or self.features_test: - self.transformix_seg_nodes_test[label].inputs['transform'] = self.edittransformfile_nodes_test[label].outputs['transform'] - self.calcfeatures_test[label].inputs['segmentation'] = self.transformix_seg_nodes_test[label] .outputs['image'] - - self.transformix_im_nodes_test[label].inputs['transform'] = self.elastix_nodes_test[label].outputs['transform'][-1] - self.transformix_im_nodes_test[label].inputs['image'] = self.converters_im_test[self.modlabels[0]].outputs['image'] - - # Save output - self.sinks_transformations_train[label] = self.network.create_sink('ElastixTransformFile', id='transformations_train_' + label) - self.sinks_segmentations_elastix_train[label] = self.network.create_sink('ITKImageFile', id='segmentations_out_elastix_train_' + label) - self.sinks_images_elastix_train[label] = self.network.create_sink('ITKImageFile', id='images_out_elastix_train_' + label) - self.sinks_transformations_train[label].input = self.elastix_nodes_train[label].outputs['transform'] - self.sinks_segmentations_elastix_train[label].input = self.transformix_seg_nodes_train[label].outputs['image'] - self.sinks_images_elastix_train[label].input = self.transformix_im_nodes_train[label].outputs['image'] - - if self.images_test or self.features_test: - self.sinks_transformations_test[label] = self.network.create_sink('ElastixTransformFile', id='transformations_test_' + label) - self.sinks_segmentations_elastix_test[label] = self.network.create_sink('ITKImageFile', id='segmentations_out_elastix_test_' + label) - self.sinks_images_elastix_test[label] = self.network.create_sink('ITKImageFile', id='images_out_elastix_test_' + label) - self.sinks_transformations_elastix_test[label].input = self.elastix_nodes_test[label].outputs['transform'] - self.sinks_segmentations_elastix_test[label].input = self.transformix_seg_nodes_test[label].outputs['image'] - self.sinks_images_elastix_test[label].input = self.transformix_im_nodes_test[label].outputs['image'] - - if self.configs[nmod]['General']['Segmentix'] == 'True': - # Segmentix nodes ----------------------------------------------------- - # Use segmentix node to convert input segmentation into correct contour - if label not in self.sinks_segmentations_segmentix_train: - self.sinks_segmentations_segmentix_train[label] = self.network.create_sink('ITKImageFile', id='segmentations_out_segmentix_train_' + label) - - self.nodes_segmentix_train[label] = self.network.create_node('segmentix/Segmentix:1.0', tool_version='1.0', id='segmentix_train_' + label, resources=ResourceLimit(memory='6G')) - if hasattr(self, 'transformix_seg_nodes_train'): - if label in self.transformix_seg_nodes_train.keys(): - # Use output of registration in segmentix - self.nodes_segmentix_train[label].inputs['segmentation_in'] = self.transformix_seg_nodes_train[label].outputs['image'] - else: - # Use original segmentation - self.nodes_segmentix_train[label].inputs['segmentation_in'] = self.converters_seg_train[label].outputs['image'] - else: - # Use original segmentation - self.nodes_segmentix_train[label].inputs['segmentation_in'] = self.converters_seg_train[label].outputs['image'] - - self.nodes_segmentix_train[label].inputs['parameters'] = self.sources_parameters[label].output - self.calcfeatures_train[label].inputs['segmentation'] = self.nodes_segmentix_train[label].outputs['segmentation_out'] - self.sinks_segmentations_segmentix_train[label].input = self.nodes_segmentix_train[label].outputs['segmentation_out'] - - if self.images_test or self.features_test: - self.sinks_segmentations_segmentix_test[label] = self.network.create_sink('ITKImageFile', id='segmentations_out_segmentix_test_' + label) - self.nodes_segmentix_test[label] = self.network.create_node('segmentix/Segmentix:1.0', tool_version='1.0', id='segmentix_test_' + label, resources=ResourceLimit(memory='6G')) - if hasattr(self, 'transformix_seg_nodes_test'): - if label in self.transformix_seg_nodes_test.keys(): - # Use output of registration in segmentix - self.nodes_segmentix_test[label].inputs['segmentation_in'] = self.transformix_seg_nodes_test[label].outputs['image'] - else: - # Use original segmentation - self.nodes_segmentix_test[label].inputs['segmentation_in'] = self.converters_seg_test[label].outputs['image'] - else: - # Use original segmentation - self.nodes_segmentix_test[label].inputs['segmentation_in'] = self.converters_seg_test[label].outputs['image'] - - self.nodes_segmentix_test[label].inputs['parameters'] = self.sources_parameters[label].output - self.calcfeatures_test[label].inputs['segmentation'] = self.nodes_segmentix_test[label].outputs['segmentation_out'] - self.sinks_segmentations_segmentix_test[label].input = self.nodes_segmentix_test[label].outputs['segmentation_out'] - - if self.masks_train and len(self.masks_train) >= nmod + 1: - # Use masks - self.nodes_segmentix_train[label].inputs['mask'] = self.converters_masks_train[label].outputs['image'] - - if self.masks_test and len(self.masks_test) >= nmod + 1: - # Use masks - self.nodes_segmentix_test[label].inputs['mask'] = self.converters_masks_test[label].outputs['image'] - - else: - if self.segmode == 'Provided': - self.calcfeatures_train[label].inputs['segmentation'] = self.converters_seg_train[label].outputs['image'] - elif self.segmode == 'Register': - if nmod > 0: - self.calcfeatures_train[label].inputs['segmentation'] = self.transformix_seg_nodes_train[label].outputs['image'] - else: - self.calcfeatures_train[label].inputs['segmentation'] = self.converters_seg_train[label].outputs['image'] - - if self.images_test or self.features_test: - if self.segmode == 'Provided': - self.calcfeatures_train[label].inputs['segmentation'] = self.converters_seg_train[label].outputs['image'] - elif self.segmode == 'Register': - if nmod > 0: - self.calcfeatures_test[label].inputs['segmentation'] = self.transformix_seg_nodes_test[label] .outputs['image'] - else: - self.calcfeatures_train[label].inputs['segmentation'] = self.converters_seg_train[label].outputs['image'] - - # Classification nodes ----------------------------------------------------- - # Add the features from this modality to the classifier node input - self.links_C1_train[label] = self.classify.inputs['features_train'][str(label)] << self.calcfeatures_train[label].outputs['features'] - self.links_C1_train[label].collapse = 'train' - - if self.images_test or self.features_test: - # Add the features from this modality to the classifier node input - self.links_C1_test[label] = self.classify.inputs['features_test'][str(label)] << self.calcfeatures_test[label].outputs['features'] - self.links_C1_test[label].collapse = 'test' - - # Save output - self.sinks_features_train[label].input = self.calcfeatures_train[label].outputs['features'] - if self.images_test or self.features_test: - self.sinks_features_test[label].input = self.calcfeatures_test[label].outputs['features'] - - else: - # Features already provided: hence we can skip numerous nodes - self.sources_features_train = dict() - self.links_C1_train = dict() - - if self.features_test: - self.sources_features_test = dict() - self.links_C1_test = dict() - - # Create label for each modality/image - self.modlabels = list() - for num, mod in enumerate(image_types): - num = 0 - label = mod + str(num) - while label in self.sources_features_train.keys(): - # if label exists, add number to label - num += 1 - label = mod + str(num) - self.modlabels.append(label) - - # Create a node for the feature computation - self.sources_features_train[label] = self.network.create_source('HDF5', id='features_train_' + label, node_group='train') - - # Add the features from this modality to the classifier node input - self.links_C1_train[label] = self.classify.inputs['features_train'][str(label)] << self.sources_features_train[label].output - self.links_C1_train[label].collapse = 'train' - - if self.features_test: - self.sources_features_test[label] = self.network.create_source('HDF5', id='features_test_' + label, node_group='test') - self.links_C1_test[label] = self.classify.inputs['features_test'][str(label)] << self.sources_features_test[label].output - self.links_C1_test[label].collapse = 'test' - - else: - raise WORCexceptions.WORCIOError("Please provide labels.") - else: - raise WORCexceptions.WORCIOError("Please provide either images or features.") - - def build_testing(self): - ''' todo ''' - - def set(self): - """ Set the FASTR source and sink data based on the given attributes.""" - self.fastrconfigs = list() - self.source_data = dict() - self.sink_data = dict() - - # If the configuration files are confiparse objects, write to file - for num, c in enumerate(self.configs): - if type(c) != configparser.ConfigParser: - # A filepath (not a fastr source) is provided. Hence we read - # the config file and convert it to a configparser object - config = configparser.ConfigParser() - config.read(c) - c = config - cfile = os.path.join(fastr.config.mounts['tmp'], 'WORC_' + self.name, ("config_{}_{}.ini").format(self.name, num)) - if not os.path.exists(os.path.dirname(cfile)): - os.makedirs(os.path.dirname(cfile)) - with open(cfile, 'w') as configfile: - c.write(configfile) - self.fastrconfigs.append(("vfs://tmp/{}/config_{}_{}.ini").format('WORC_' + self.name, self.name, num)) - - # Generate gridsearch parameter files if required - # TODO: We now use the first configuration for the classifier, but his needs to be separated from the rest per modality - self.source_data['config_classification_source'] = self.fastrconfigs[0] - - # Set source and sink data - self.source_data['patientclass_train'] = self.labels_train - self.source_data['patientclass_test'] = self.labels_test - - self.sink_data['classification'] = ("vfs://output/{}/svm_{{sample_id}}_{{cardinality}}{{ext}}").format(self.name) - self.sink_data['performance'] = ("vfs://output/{}/performance_{{sample_id}}_{{cardinality}}{{ext}}").format(self.name) - self.sink_data['config_classification_sink'] = ("vfs://output/{}/config_{{sample_id}}_{{cardinality}}{{ext}}").format(self.name) - - # Set the source data from the WORC objects you created - for num, label in enumerate(self.modlabels): - self.source_data['parameters_' + label] = self.fastrconfigs[num] - - # Add train data sources - if self.images_train and len(self.images_train) - 1 >= num: - self.source_data['images_train_' + label] = self.images_train[num] - - if self.masks_train and len(self.masks_train) - 1 >= num: - self.source_data['mask_train_' + label] = self.masks_train[num] - - if self.metadata_train and len(self.metadata_train) - 1 >= num: - self.source_data['metadata_train_' + label] = self.metadata_train[num] - - if self.segmentations_train and len(self.segmentations_train) - 1 >= num: - self.source_data['segmentations_train_' + label] = self.segmentations_train[num] - - if self.semantics_train and len(self.semantics_train) - 1 >= num: - self.source_data['semantics_train_' + label] = self.semantics_train[num] - - if self.features_train and len(self.features_train) - 1 >= num: - self.source_data['features_train_' + label] = self.features_train[num] - - if self.Elastix_Para: - # First modality does not need to be registered - if num > 0: - if len(self.Elastix_Para) > 1: - # Each modality has its own registration parameters - self.source_data['Elastix_Para_' + label] = self.Elastix_Para[num] - else: - # Use one fileset for all modalities - self.source_data['Elastix_Para_' + label] = self.Elastix_Para[0] - - # Add test data sources - if self.images_test and len(self.images_test) - 1 >= num: - self.source_data['images_test_' + label] = self.images_test[num] - - if self.masks_test and len(self.masks_test) - 1 >= num: - self.source_data['mask_test_' + label] = self.masks_test[num] - - if self.metadata_test and len(self.metadata_test) - 1 >= num: - self.source_data['metadata_test_' + label] = self.metadata_test[num] - - if self.segmentations_test and len(self.segmentations_test) - 1 >= num: - self.source_data['segmentations_test_' + label] = self.segmentations_test[num] - - if self.semantics_test and len(self.semantics_test) - 1 >= num: - self.source_data['semantics_test_' + label] = self.semantics_test[num] - - if self.features_test and len(self.features_test) - 1 >= num: - self.source_data['features_test_' + label] = self.features_test[num] - - self.sink_data['segmentations_out_segmentix_train_' + label] = ("vfs://output/{}/Segmentations/seg_{}_segmentix_{{sample_id}}_{{cardinality}}{{ext}}").format(self.name, label) - self.sink_data['segmentations_out_elastix_train_' + label] = ("vfs://output/{}/Elastix/seg_{}_elastix_{{sample_id}}_{{cardinality}}{{ext}}").format(self.name, label) - self.sink_data['images_out_elastix_train_' + label] = ("vfs://output/{}/Elastix/im_{}_elastix_{{sample_id}}_{{cardinality}}{{ext}}").format(self.name, label) - self.sink_data['features_train_' + label] = ("vfs://output/{}/Features/features_{}_{{sample_id}}_{{cardinality}}{{ext}}").format(self.name, label) - - if self.labels_test: - self.sink_data['segmentations_out_segmentix_test_' + label] = ("vfs://output/Segmentations/{}/seg_{}_segmentix_{{sample_id}}_{{cardinality}}{{ext}}").format(self.name, label) - self.sink_data['segmentations_out_elastix_test_' + label] = ("vfs://output/{}/Elastix/seg_{}_elastix_{{sample_id}}_{{cardinality}}{{ext}}").format(self.name, label) - self.sink_data['images_out_elastix_test_' + label] = ("vfs://output/{}/Images/im_{}_elastix_{{sample_id}}_{{cardinality}}{{ext}}").format(self.name, label) - self.sink_data['features_test_' + label] = ("vfs://output/{}/Features/features_{}_{{sample_id}}_{{cardinality}}{{ext}}").format(self.name, label) - - # Add elastix sinks if used - if self.segmode: - # Segmode is only non-empty if segmentations are provided - if self.segmode == 'Register': - self.sink_data['transformations_train_' + label] = ("vfs://output/{}/Elastix/transformation_{}_{{sample_id}}_{{cardinality}}{{ext}}").format(self.name, label) - if self.images_test or self.features_test: - self.sink_data['transformations_test_' + label] = ("vfs://output/{}/Elastix/transformation_{}_{{sample_id}}_{{cardinality}}{{ext}}").format(self.name, label) - - def execute(self): - """ Execute the network through the fastr.network.execute command. """ - # Draw and execute nwtwork - self.network.draw(file_path=self.network.id + '.svg', draw_dimensions=True) - self.network.execute(self.source_data, self.sink_data, execution_plugin=self.fastr_plugin, tmpdir=self.fastr_tmpdir) - # self.network.execute(self.source_data, self.sink_data) - - -class Tools(object): - ''' - This object can be used to create other pipelines besides the default - Radiomics executions. Currently only includes a registratio pipeline. - ''' - def __init__(self): - self.Elastix = Elastix() - self.Evaluate = Evaluate() diff --git a/build/lib/WORC/__init__.py b/build/lib/WORC/__init__.py deleted file mode 100644 index 503b3f67..00000000 --- a/build/lib/WORC/__init__.py +++ /dev/null @@ -1,2 +0,0 @@ -from WORC.WORC import WORC -from WORC import classification, featureprocessing, processing diff --git a/build/lib/WORC/addexceptions.py b/build/lib/WORC/addexceptions.py deleted file mode 100644 index b16c17eb..00000000 --- a/build/lib/WORC/addexceptions.py +++ /dev/null @@ -1,122 +0,0 @@ -#!/usr/bin/env python - -# Copyright 2016-2019 Biomedical Imaging Group Rotterdam, Departments of -# Medical Informatics and Radiology, Erasmus MC, Rotterdam, The Netherlands -# -# 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. - -""" -This module contains all WORC-related Exceptions -""" - -# import inspect -# import os -# import textwrap - -# pylint: disable=too-many-ancestors -# Because fo inheriting from FastrError and a common exception causes this -# exception, even though this behaviour is desired - - -class WORCError(Exception): - """ - This is the base class for all WORC related exceptions. Catching this - class of exceptions should ensure a proper execution of WORC. - """ - # def __init__(self, *args, **kwargs): - # """ - # Constructor for all exceptions. Saves the caller object fullid (if - # found) and the file, function and line number where the object was - # created. - # """ - # super(WORCError, self).__init__(*args, **kwargs) - # - # frame = inspect.stack()[1][0] - # call_object = frame.f_locals.get('self', None) - # if call_object is not None and hasattr(call_object, 'fullid'): - # self.WORC_object = call_object.fullid - # else: - # self.WORC_object = None - # - # info = inspect.getframeinfo(frame) - # self.filename = info.filename - # self.function = info.function - # self.linenumber = info.lineno - # - # def __str__(self): - # """ - # String representation of the error - # - # :return: error string - # :rtype: str - # """ - # if self.WORC_object is not None: - # return '[{}] {}'.format(self.WORC_object, super(WORCError, self).__str__()) - # else: - # return super(WORCError, self).__str__() - # - # def excerpt(self): - # """ - # Return a excerpt of the Error as a tuple. - # """ - # return type(self).__name__, self.message, self.filename, self.linenumber - pass - - -class WORCNotImplementedError(WORCError, NotImplementedError): - """ - This function/method has not been implemented on purpose (e.g. should be - overwritten in a sub-class) - """ - pass - - -class WORCIOError(WORCError, IOError): - """ - IOError in WORC - """ - pass - - -class WORCTypeError(WORCError, TypeError): - """ - TypeError in the WORC system - """ - pass - - -class WORCValueError(WORCError, ValueError): - """ - ValueError in the WORC system - """ - pass - - -class WORCKeyError(WORCError, KeyError): - """ - KeyError in the WORC system - """ - pass - - -class WORCAssertionError(WORCError, AssertionError): - """ - AssertionError in the WORC system - """ - pass - -class WORCIndexError(WORCError, IndexError): - """ - IndexError in the WORC system - """ - pass \ No newline at end of file diff --git a/build/lib/WORC/classification/AdvancedSampler.py b/build/lib/WORC/classification/AdvancedSampler.py deleted file mode 100644 index 79512226..00000000 --- a/build/lib/WORC/classification/AdvancedSampler.py +++ /dev/null @@ -1,195 +0,0 @@ -#!/usr/bin/env python - -# Copyright 2016-2019 Biomedical Imaging Group Rotterdam, Departments of -# Medical Informatics and Radiology, Erasmus MC, Rotterdam, The Netherlands -# -# 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. - -from sklearn.utils import check_random_state -import numpy as np -from sklearn.externals import six -from ghalton import Halton -# from sobol_seq import i4_sobol_generate as Sobol -import scipy -from scipy.stats import uniform -import math - - -class log_uniform(): - def __init__(self, loc=-1, scale=0, base=10): - self.loc = loc - self.scale = scale - self.base = base - self.uniform_dist = uniform(loc=self.loc, scale=self.scale) - - def rvs(self, size=None, random_state=None): - if size is None: - return np.power(self.base, self.uniform_dist.rvs(random_state=random_state)) - else: - return np.power(self.base, self.uniform_dist.rvs(size=size, random_state=random_state)) - - -class discrete_uniform(): - def __init__(self, loc=-1, scale=0): - self.loc = loc - self.scale = scale - self.uniform_dist = uniform(loc=self.loc, scale=self.scale) - - def rvs(self, size=None, random_state=None): - if size is None: - return int(self.uniform_dist.rvs(random_state=random_state)) - else: - return int(self.uniform_dist.rvs(size=size, random_state=random_state)) - - -class exp_uniform(): - def __init__(self, loc=-1, scale=0, base=math.e): - self.loc = loc - self.scale = scale - self.base = base - - def rvs(self, size=None, random_state=None): - uniform_dist = uniform(loc=self.loc, scale=self.scale) - if size is None: - return np.power(self.base, uniform_dist .rvs(random_state=random_state)) - else: - return np.power(self.base, uniform_dist .rvs(size=size, random_state=random_state)) - - -class AdvancedSampler(object): - """Generator on parameters sampled from given distributions using - numerical sequences. Based on the sklearn ParameterSampler. - - Non-deterministic iterable over random candidate combinations for hyper- - parameter search. If all parameters are presented as a list, - sampling without replacement is performed. If at least one parameter - is given as a distribution, sampling with replacement is used. - It is highly recommended to use continuous distributions for continuous - parameters. - - Note that before SciPy 0.16, the ``scipy.stats.distributions`` do not - accept a custom RNG instance and always use the singleton RNG from - ``numpy.random``. Hence setting ``random_state`` will not guarantee a - deterministic iteration whenever ``scipy.stats`` distributions are used to - define the parameter search space. Deterministic behavior is however - guaranteed from SciPy 0.16 onwards. - - Read more in the :ref:`User Guide `. - - Parameters - ---------- - param_distributions : dict - Dictionary where the keys are parameters and values - are distributions from which a parameter is to be sampled. - Distributions either have to provide a ``rvs`` function - to sample from them, or can be given as a list of values, - where a uniform distribution is assumed. - - n_iter : integer - Number of parameter settings that are produced. - - random_state : int or RandomState - Pseudo random number generator state used for random uniform sampling - from lists of possible values instead of scipy.stats distributions. - - Returns - ------- - params : dict of string to any - **Yields** dictionaries mapping each estimator parameter to - as sampled value. - - Examples - -------- - >>> from WORC.classification.AdvancedSampler import HaltonSampler - >>> from scipy.stats.distributions import expon - >>> import numpy as np - >>> np.random.seed(0) - >>> param_grid = {'a':[1, 2], 'b': expon()} - >>> param_list = list(HaltonSampler(param_grid, n_iter=4)) - >>> rounded_list = [dict((k, round(v, 6)) for (k, v) in d.items()) - ... for d in param_list] - >>> rounded_list == [{'b': 0.89856, 'a': 1}, - ... {'b': 0.923223, 'a': 1}, - ... {'b': 1.878964, 'a': 2}, - ... {'b': 1.038159, 'a': 2}] - True - """ - def __init__(self, param_distributions, n_iter, random_state=None, - method='Halton'): - self.param_distributions = param_distributions - self.n_iter = n_iter - self.random_state = random_state - self.method = method - - if method == 'Halton': - self.Halton = Halton(len(self.param_distributions.keys())) - - def __iter__(self): - # Create a random state to be used - rnd = check_random_state(self.random_state) - - # Generate the sequence generator - if self.method == 'Halton': - sequence = self.Halton.get(self.n_iter) - elif self.method == 'Sobol': - sequence = Sobol(len(self.param_distributions.keys()), self.n_iter) - - # Always sort the keys of a dictionary, for reproducibility - items = sorted(self.param_distributions.items()) - for i in six.moves.range(self.n_iter): - sample = sequence[i] - params = dict() - for ind, (k, v) in enumerate(items): - point = sample[ind] - # Check if the parameter space is a distribution or a list - if hasattr(v, "rvs"): - print(point) - # Parameter space is a distribution, hence sample - params[k] = v.ppf(point) - else: - # Parameter space is a list, so select an index - point = int(round(point*float(len(v) - 1))) - print(point) - params[k] = v[point] - yield params - - # For reproducibility, reset sampler if needed - if self.method == 'Halton': - self.Halton.reset() - - def __len__(self): - """Number of points that will be sampled.""" - return self.n_iter - - -if __name__ == '__main__': - random_seed = np.random.randint(1, 5000) - random_state = check_random_state(random_seed) - - param_distributions = {'kernel': ['poly', 'RGB'], - 'C': scipy.stats.uniform(loc=0, scale=1E6), - 'degree': scipy.stats.uniform(loc=1, scale=6), - 'coef0': scipy.stats.uniform(loc=0, scale=1), - 'gamma': scipy.stats.uniform(loc=1E-5, scale=1), - 'histogram_features': ['True', 'False']} - - n_iter = 6 - - method = 'Sobol' - sampled_params = AdvancedSampler(param_distributions, - n_iter, - random_state) - - - for s in sampled_params: - print(s) diff --git a/build/lib/WORC/classification/RankedSVM.py b/build/lib/WORC/classification/RankedSVM.py deleted file mode 100644 index ba2e4d30..00000000 --- a/build/lib/WORC/classification/RankedSVM.py +++ /dev/null @@ -1,753 +0,0 @@ -#!/usr/bin/env python - -# Copyright 2016-2019 Biomedical Imaging Group Rotterdam, Departments of -# Medical Informatics and Radiology, Erasmus MC, Rotterdam, The Netherlands -# -# 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. - - -from __future__ import division -import numpy as np -from scipy.optimize import linprog -from scipy.optimize import fminbound -from scipy import linalg -import operator -import WORC.addexceptions as WORCexceptions - - -''' -This code is based on the original RankSVM Matlab Code from [1] and [2]. -Only the multi-classification variant has been ported. - - -RanKSVM_train trains a multi-label ranking svm using the method described in -[1] and [2] and originally implemented in MATLAB. - -[1] Elisseeff A, Weston J. Kernel methods for multi-labelled classfication - and categorical regression problems. Technical Report, - BIOwulf Technologies, 2001. -[2] Elisseeff A,Weston J. A kernel method for multi-labelled classification. - In: Dietterich T G, Becker S, Ghahramani Z, eds. Advances in - Neural Information Processing Systems 14, Cambridge, - MA: MIT Press, 2002, 681-687. - -Translated by Mumtaz Hussain Soomro (mumtazhussain.soomro@uniroma3.tk) in August 2018 -''' - - -def neg_dual_func(Lambda, Alpha_old, Alpha_new, c_value, kernel, - num_training, num_class, Label, not_Label, - Label_size, size_alpha): - - # Local Variables: kernel, num_class, Alpha_new, index, i, num_training, k, size_alpha, m, c_value, Label, Alpha, Beta, n, not_Label, output, Lambda, Label_size, Alpha_old - # Function calls: sum, zeros, neg_dual_func - - Alpha = Alpha_old+np.dot(Lambda, Alpha_new-Alpha_old) - Beta = np.zeros(shape =(num_class, num_training)) - for k in range(num_class): - for i in range(num_training): - for m in range(Label_size[:,int(i)]): - for n in range(num_class-Label_size[:,int(i)]): - index = np.sum(size_alpha[:,0:i])+n - - ak = np.array(c_value[k], dtype=int) - r1 = Label[int(i)] ####this supports for only for multiclass - ### if you want to work on multilabel then try this: r1 = Label[i] - #################################################### r1 = r1[m] - c1 = not_Label[int(i)] - c1 = c1[n] - Beta[k,i] = Beta[k,i]+ak[int(r1),int(c1)]*Alpha[:,int(index)] - - - output = 0 - for k in range(num_class): - fg = np.dot(Beta[int(k),:], kernel.conj().T) - fg = fg.conj().T - gf = np.dot(Beta[int(k),:], fg) - output = output + gf - - output = np.dot(0.5, output) - output = output-np.sum(Alpha) - return np.array([output]) - - -def is_empty(any_structure): - if any_structure: - return False - - else: - return True - - -def RankSVM_train_old(train_data, train_target, cost=1, lambda_tol=1e-6, - norm_tol=1e-4, max_iter=500, svm='Poly', gamma=0.05, - coefficient=0.05, degree=3): - # NOTE: Only multilabel classification, not multiclass! Make a check. - ''' - Weights,Bias,SVs = RankSVM_train(train_data,train_target,cost,lambda_tol,norm_tol,max_iter,svm,gamma,coefficient,degree) - - Description - - RankSVM_train takes, - train_data - An MxN array, the ith instance of training instance is stored in train_data[i,:] - train_target - A QxM array, if the ith training instance belongs to the jth class, then train_target[j,i] equals +1, otherwise train_target(j,i) equals -1 - svm - svm gives the type of svm used in training, which can take the value of 'RBF', 'Poly' or 'Linear'; svm.para gives the corresponding parameters used for the svm: - 1) if svm is 'RBF', then gamma gives the value of gamma, where the kernel is exp(-Gamma*|x[i]-x[j]|^2) - 2) if svm is 'Poly', then three values are used gamma, coefficient, and degree respectively, where the kernel is (gamma*+coefficient)^degree. - 3) if svm is 'Linear', then svm is []. - cost - The value of 'C' used in the SVM, default=1 - lambda_tol - The tolerance value for lambda described in the appendix of [1]; default value is 1e-6 - norm_tol - The tolerance value for difference between alpha(p+1) and alpha(p) described in the appendix of [1]; default value is 1e-4 - max_iter - The maximum number of iterations for RankSVM, default=500 - - and returns, - Weights - The value for beta[ki] as described in the appendix of [1] is stored in Weights[k,i] - Bias - The value for b[i] as described in the appendix of [1] is stored in Bias[1,i] - SVs - The ith support vector is stored in SVs[:,i] - - - For more details,please refer to [1] and [2]. - ''' - - # RankedSVM only works for multilabel problems, not multiclass, so check - # Whether patients have no class or multiple classes - n_class = train_target.shape[0] - n_object = train_target.shape[1] - for i in range(0, n_object): - if np.sum(train_target[:, i]) != -n_class + 2: - raise WORCexceptions.WORCIOError('RankedSVM only works ' + - 'for multilabel problems,' + - ' not multiclass. One or ' + - 'more objects belong ' + - 'either to no class or' + - ' multiple classes. ' + - 'Please check your data' + - ' again.') - - num_training, tempvalue = np.shape(train_data) - - SVs = np.zeros(shape=(tempvalue,num_training)) - - num_class, tempvalue = np.shape(train_target) - lc = np.ones(shape=(1,num_class)) - - target = np.zeros(shape=(num_class, tempvalue)) - for i in range(num_training): - temp = train_target[:,int(i)] - if np.logical_and(np.sum(temp) != num_class, np.sum(temp) != -num_class): - #SVs = (SVs, train_data[int(i),:].conj().T) - SVs [:,i] = train_data[int(i),:].conj().T - target[:,i] = temp - - - Dim, num_training = np.shape(SVs) - Label = np.array(np.zeros(shape=(num_training,1)), dtype=float) - not_Label = [] - Label_size = np.zeros(shape=(1,num_training)) - size_alpha = np.zeros(shape=(1,num_training), dtype=float) - - for i in range(num_training): - temp1 = train_target[:,int(i)] - Label_size[0,int(i)] = np.sum(temp1 == lc) - lds = num_class-Label_size[0,int(i)] - size_alpha[0,int(i)] = np.dot(lds, Label_size[0,int(i)]) - for j in range(num_class): - if temp1[int(j)] == 1: - Label[int(i),0] = np.array([j]) - else: - not_Label.append((j)) - - not_Label = np.reshape(not_Label, (num_training,num_class-1)) - - kernel = np.zeros(shape =(num_training, num_training), dtype=float) - - if svm == 'RBF': - for i in range(num_training): - for j in range(num_training): - kernel[int(i),int(j)] = np.exp(-gamma*(np.sum((SVs[:,i]-SVs[:,j])**2))) - - - else: - if svm == 'Poly': - for i in range(num_training): - for j in range(num_training): - ab= np.dot((np.array([SVs[:,int(j)]])),((np.array([SVs[:,int(i)]])).conj().T)) - ab=gamma*ab - ab=ab+coefficient - ab=ab**degree - #kernel[int(i),int(j)] = (gamma*(SVs[:,int(i)].conj().T)*SVs[:,int(j)]+coefficient)**degree - kernel[int(i),int(j)] = np.array([ab]) - else: - for i in range(num_training): - for j in range(num_training): - kernel[int(i),int(j)] = np.dot((np.array([SVs[:,int(j)]])),((np.array([SVs[:,int(i)]])).conj().T)) - - svm_used=svm; - - #Begin training phase - - #data initializing - - ak = np.sum(size_alpha, dtype=int) - Alpha = np.zeros(shape=(1, ak)) - - ####creating a cell c_value - - c_value = np.zeros((num_class,), dtype=np.object) - - for i in range(num_class): - c_value[i] = np.zeros(shape=(num_class,num_class)) - - for i in range(num_class): - ak = c_value[i] - ak[i,:]= np.ones(shape=(1,num_class)) - ak[:,i]= -np.ones(shape=(num_class,)) - c_value[i] = ak - - #print Label_size - ### Find the Alpha value using Franke and Wolfe method [1] - - continuing = True - iteration = 0 - - while(continuing): - - #computing Beta - #iteration=iteration+1; - - #disp(strcat('current iteration: ',num2str(iteration))) - Beta = np.zeros(shape=(num_class,num_training)) - for k in range(num_class): - for i in range(num_training): - for m in range(Label_size[:,int(i)]): - for n in range(num_class-Label_size[:,int(i)]): - #index = np.sum(size_alpha[:,0:i])+(m-1)*(num_class-Label_size[i])+n - index = np.sum(size_alpha[:,0:i])+n - - ak = np.array(c_value[k], dtype=int) - r1 = Label[int(i)] ####this supports for only for multiclass - ### if you want to work on multilabel then try this: r1 = Label[i] - #################################################### r1 = r1[m] - c1 = not_Label[int(i)] - c1 = c1[n] - Beta[k,i] = Beta[k,i]+ak[int(r1),int(c1)]*Alpha[:,int(index)] - - ####computing gradient(ikl) - - inner = np.zeros(shape=(num_class,num_training)) - for k in range(num_class): - for j in range(num_training): - inner[k,j] = np.dot(Beta[k,:], kernel[:,j]) - - gradient=[] - - for i in range(num_training): - for m in range(Label_size[:,int(i)]): - for n in range(num_class-Label_size[:,int(i)]): - r1 = Label[int(i)] ####this supports only for multiclass - ### if you want to work on multilabel then try this: r1 = Label[i] - #################################################### r1 = r1[m] - c1 = not_Label[int(i)] - c1 = c1[n] - temp = inner[int(r1), int(i)]-inner[int(c1),int(i)]-1 - #gradient=np.array([gradient,temp]) - gradient.append(float(temp)) - - gradient = np.array(gradient, dtype=float) - gradient = gradient.conj().T - - - ###Find Alpha_new - Aeq = np.zeros(shape=(num_class,np.sum(size_alpha, dtype=int))) - for k in range(num_class): - counter=0 - for i in range(num_training): - for m in range (Label_size[:,int(i)]): - for n in range(num_class-Label_size[:,int(i)]): - #counter+=1 - r1 = Label[i] ####this supports only for multiclass - ### if you want to work on multilabel then try this: r1 = Label[i] - #################################################### r1 = r1[m] - c1 = not_Label[int(i)] - c1 = c1[n] - ak = c_value[k] - Aeq[k,counter] = ak[int(r1),int(c1)] - counter+=1 - #print Aeq - beq=np.zeros(shape=(num_class,)) - LB=np.zeros(shape=(np.sum(size_alpha, dtype=int),1)) - UB=np.zeros(shape=(np.sum(size_alpha, dtype=int),1)) - counter=0 - for i in range(num_training): - for m in range(Label_size[:,int(i)]): - for n in range(num_class-Label_size[:,int(i)]): - #counter+=1 - UB[counter,:]=cost/(size_alpha[:,i]) - counter+=1 - #print UB - cc = [LB.T, UB.T] - cc =np.ravel(cc) - bounds = np.reshape(cc, (2,np.sum(size_alpha, dtype=int))) - bounds = bounds.T - Alpha_new=linprog(gradient.conj().T,A_ub=None, b_ub=None, A_eq=Aeq, b_eq=beq.T,bounds=bounds) - Alpha_new = Alpha_new.x - Alpha_new = (np.array(Alpha_new)).conj().T - - Lambda =fminbound(neg_dual_func, 0.0, 1.0,args= (Alpha,Alpha_new,c_value,kernel,num_training,num_class,Label,not_Label,Label_size,size_alpha)) - - - #print Lambda - #Test convergence - - if np.logical_or(np.abs(Lambda)<=lambda_tol, np.dot(Lambda, np.sqrt(np.sum(((Alpha_new-Alpha)**2.))))<=norm_tol): - continuing = False - # np.disp('program terminated normally') - else: - if iteration >= max_iter: - continuing = False - - else: - Alpha = Alpha+np.dot(Lambda, Alpha_new-Alpha) - - iteration+=1 - - - Weights = Beta - - #Computing Bias - - Left = [] - Right = [] - for i in range(num_training): - for m in range(Label_size[:,int(i)]): - for n in range(num_class-Label_size[:,int(i)]): - index = np.sum(size_alpha[:,0:i])+n - if np.logical_and(np.abs(Alpha[:,int(index)]) >= lambda_tol, np.abs(Alpha[:,int(index)]-cost/(size_alpha[:,i])) >= lambda_tol): - vector = np.zeros(shape=(1, num_class)) - vector[0,int(Label[i])] = 1 - c1 = not_Label[int(i)] - c1 = c1[n] - vector[0,int(c1)] = -1. - Left.append(vector) - Right.append(-gradient[int(index)]) - - - if is_empty(Left): - Bias = np.sum(train_target.conj().T) - else: - bb = np.array([Right]) - ss1,ss2 = bb.shape - aa = np.ravel(Left) - aa = np.reshape(aa,(ss2,num_class)) - - ##### Proper way to solve linear equation with non-square matrix - Bias = np.linalg.lstsq(aa,bb.T,rcond = -1)[0] - #Bias = Bias.T - - return Weights, Bias, SVs - - -def RankSVM_train(train_data, train_target, cost=1, lambda_tol=1e-6, - norm_tol=1e-4, max_iter=500, svm='Poly', gamma=0.05, - coefficient=0.05, degree=3): - print('Training Ranked SVM ...') - num_training, tempvalue = np.shape(train_data) - - SVs = np.zeros(shape=(tempvalue,num_training)) - num_class, tempvalue = np.shape(train_target) - lc = np.ones(shape=(1,num_class)) - #print SVs.shape - target = np.zeros(shape=(num_class, tempvalue)) - for i in range(num_training): - temp = train_target[:,int(i)] - if np.logical_and(np.sum(temp) != num_class, np.sum(temp) != -num_class): - #SVs = (SVs, train_data[int(i),:].conj().T) - #print (train_data[int(i),:]).conj().T - SVs [:,i] = train_data[int(i),:].conj().T - #SVs [i,:] = train_data[int(i),:].T - - target[:,i] = temp - - #SVs = SVs.T - Dim, num_training = np.shape(SVs) - Label = np.array(np.zeros(shape=(num_training,1)), dtype=float) - not_Label = [] - Label_size = np.zeros(shape=(1,num_training)) - size_alpha = np.zeros(shape=(1,num_training), dtype=float) - - for i in range(num_training): - temp1 = train_target[:,int(i)] - Label_size[0,int(i)] = np.sum(temp1 == lc) - lds = num_class-Label_size[0,int(i)] - size_alpha[0,int(i)] = np.dot(lds, Label_size[0,int(i)]) - for j in range(num_class): - if temp1[int(j)] == 1: - Label[int(i),0] = np.array([j]) - else: - not_Label.append((j)) - not_Label = np.reshape(not_Label, (num_training,num_class-1)) - - kernel = np.zeros(shape =(num_training, num_training), dtype=float) - - if svm == 'RBF': - for i in range(num_training): - for j in range(num_training): - kernel[int(i),int(j)] = np.exp(-gamma*(np.sum((SVs[:,i]-SVs[:,j])**2))) - - - else: - if svm == 'Poly': - for i in range(num_training): - for j in range(num_training): - ab= np.dot((np.array([SVs[:,int(j)]])),((np.array([SVs[:,int(i)]])).conj().T)) - ab=gamma*ab - ab=ab+coefficient - ab=ab**degree - #kernel[int(i),int(j)] = (gamma*(SVs[:,int(i)].conj().T)*SVs[:,int(j)]+coefficient)**degree - kernel[int(i),int(j)] = np.array([ab]) - else: - for i in range(num_training): - for j in range(num_training): - kernel[int(i),int(j)] = np.dot((np.array([SVs[:,int(j)]])),((np.array([SVs[:,int(i)]])).conj().T)) - - svm_used=svm; - - #Begin training phase - - #data initializing - - ak = np.sum(size_alpha, dtype=int) - Alpha = np.zeros(shape=(1, ak)) - - ####creating a cell c_value - - c_value = np.zeros((num_class,), dtype=np.object) - - for i in range(num_class): - c_value[i] = np.zeros(shape=(num_class,num_class)) - - for i in range(num_class): - ak = c_value[i] - ak[i,:]= np.ones(shape=(1,num_class)) - ak[:,i]= -np.ones(shape=(num_class,)) - c_value[i] = ak - - #print Label_size - ### Find the Alpha value using Franke and Wolfe method [1] - - continuing = True - iteration = 0 - - while(continuing): - print('Iteration {}.').format(iteration) - #computing Beta - #iteration=iteration+1; - - #disp(strcat('current iteration: ',num2str(iteration))) - Beta = np.zeros(shape=(num_class,num_training)) - for k in range(num_class): - for i in range(num_training): - for m in range(Label_size[:,int(i)]): - for n in range(num_class-Label_size[:,int(i)]): - #index = np.sum(size_alpha[:,0:i])+(m-1)*(num_class-Label_size[i])+n - index = np.sum(size_alpha[:,0:i])+n - - ak = np.array(c_value[k], dtype=int) - r1 = Label[int(i)] ####this supports for only for multiclass - ### if you want to work on multilabel then try this: r1 = Label[i] - #################################################### r1 = r1[m] - c1 = not_Label[int(i)] - c1 = c1[n] - Beta[k,i] = Beta[k,i]+ak[int(r1),int(c1)]*Alpha[:,int(index)] - - ####computing gradient(ikl) - - inner = np.zeros(shape=(num_class,num_training)) - for k in range(num_class): - for j in range(num_training): - inner[k,j] = np.dot(Beta[k,:], kernel[:,j]) - - gradient=[] - - for i in range(num_training): - for m in range(Label_size[:,int(i)]): - for n in range(num_class-Label_size[:,int(i)]): - r1 = Label[int(i)] ####this supports only for multiclass - ### if you want to work on multilabel then try this: r1 = Label[i] - #################################################### r1 = r1[m] - c1 = not_Label[int(i)] - c1 = c1[n] - temp = inner[int(r1), int(i)]-inner[int(c1),int(i)]-1 - #gradient=np.array([gradient,temp]) - gradient.append(float(temp)) - - gradient = np.array(gradient, dtype=float) - gradient = gradient.conj().T - - - ###Find Alpha_new - - Aeq = np.zeros(shape=(num_class,np.sum(size_alpha, dtype=int))) - for k in range(num_class): - counter=0 - for i in range(num_training): - for m in range (Label_size[:,int(i)]): - for n in range(num_class-Label_size[:,int(i)]): - #counter+=1 - r1 = Label[i] ####this supports only for multiclass - ### if you want to work on multilabel then try this: r1 = Label[i] - #################################################### r1 = r1[m] - c1 = not_Label[int(i)] - c1 = c1[n] - ak = c_value[k] - Aeq[k,counter] = ak[int(r1),int(c1)] - counter+=1 - #print Aeq - beq=np.zeros(shape=(num_class,)) - LB=np.zeros(shape=(np.sum(size_alpha, dtype=int),1)) - UB=np.zeros(shape=(np.sum(size_alpha, dtype=int),1)) - counter=0 - for i in range(num_training): - for m in range(Label_size[:,int(i)]): - for n in range(num_class-Label_size[:,int(i)]): - #counter+=1 - UB[counter,:]=cost/(size_alpha[:,i]) - counter+=1 - #print UB - cc = [LB.T, UB.T] - cc =np.ravel(cc) - bounds = np.reshape(cc, (2,np.sum(size_alpha, dtype=int))) - bounds = bounds.T - try: - Alpha_new = linprog(gradient.conj().T,A_ub=None, b_ub=None, A_eq=Aeq, b_eq=beq.T,bounds=bounds) - Alpha_new = Alpha_new.x - Alpha_new = (np.array(Alpha_new)).conj().T - except IndexError: - print('[WORC Warning] RankedSVM could not be fit to data. Returning zero classifier.') - Alpha_new = Alpha - - Lambda =fminbound(neg_dual_func, 0.0, 1.0,args= (Alpha,Alpha_new,c_value,kernel,num_training,num_class,Label,not_Label,Label_size,size_alpha)) - - - #print Lambda - #Test convergence - - if np.logical_or(np.abs(Lambda)<=lambda_tol, np.dot(Lambda, np.sqrt(np.sum(((Alpha_new-Alpha)**2.))))<=norm_tol): - continuing = False - # np.disp('program terminated normally') - else: - if iteration >= max_iter: - continuing = False - - else: - Alpha = Alpha+np.dot(Lambda, Alpha_new-Alpha) - - iteration+=1 - - Weights = Beta - - #Computing Bias - Left = [] - Right = [] - for i in range(num_training): - for m in range(Label_size[:,int(i)]): - for n in range(num_class-Label_size[:,int(i)]): - index = np.sum(size_alpha[:,0:i])+n - if np.logical_and(np.abs(Alpha[:,int(index)]) >= lambda_tol, np.abs(Alpha[:,int(index)]-cost/(size_alpha[:,i])) >= lambda_tol): - vector = np.zeros(shape=(1, num_class)) - vector[0,int(Label[i])] = 1 - c1 = not_Label[int(i)] - c1 = c1[n] - vector[0,int(c1)] = -1. - Left.append(vector) - Right.append(-gradient[int(index)]) - - if is_empty(Left): - Bias = np.sum(train_target.conj().T) - else: - bb = np.array([Right]) - ss1,ss2 = bb.shape - aa = np.ravel(Left) - aa = np.reshape(aa,(ss2,num_class)) - - ##### Proper way to solve linear equation with non-square matrix - Bias = np.linalg.lstsq(aa,bb.T,rcond = -1)[0] - #Bias = Bias.T - - if Bias.shape == (): - # Error in Alpha, create empty bias - print('[WORC Warning] Error in Alpha, create empty bias.') - Bias = np.zeros(shape=(num_class,1)) - - return Weights,Bias,SVs - -def RankSVM_test_original(test_data, test_target, Weights, Bias, SVs, - svm='Poly', gamma=0.05, - coefficient=0.05, degree=3): - num_testing, tempvalue = np.shape(test_data) - num_class, tempvalue = np.shape(test_target) - tempvalue,num_training= np.shape(SVs) - Label = np.array(np.zeros(shape=(num_testing,1)), dtype=float) - not_Label = [] - Label_size = np.zeros(shape=(1,num_testing)) - size_alpha = np.zeros(shape=(1,num_training), dtype=float) - lc = np.ones(shape=(1,num_class)) - for i in range(num_testing): - temp = test_target[:,int(i)] - Label_size[0,int(i)] = np.sum(temp == lc) - lds = num_class-Label_size[0,int(i)] - size_alpha[0,int(i)] = np.dot(lds, Label_size[0,int(i)]) - for j in range(num_class): - if temp[int(j)] == 1: - Label[int(i),0] = np.array([j]) - else: - not_Label.append((j)) - - not_Label = np.reshape(not_Label, (num_testing,num_class-1)) - - kernel = np.zeros(shape =(num_testing, num_training), dtype=float) - if svm == 'RBF': - for i in range(num_testing): - for j in range(num_training): - kernel[int(i),int(j)] = np.exp(-gamma*(np.sum(((test_data[i,:].conj.T)-SVs[:,j])**2))) - - - else: - if svm == 'Poly': - for i in range(num_testing): - for j in range(num_training): - ab= np.dot((np.array([SVs[:,int(j)]])),(np.array([test_data[int(i),:]]).T)) - ab=gamma*ab - ab=ab+coefficient - ab=ab**degree - #kernel[int(i),int(j)] = (gamma*(SVs[:,int(i)].conj().T)*SVs[:,int(j)]+coefficient)**degree - kernel[int(i),int(j)] = np.array([ab]) - else: - for i in range(num_testing): - for j in range(num_training): - kernel[int(i),int(j)] = np.dot((np.array([SVs[:,int(j)]])),(np.array([test_data[int(i),:]]))) - - Outputs =np.zeros(shape=(num_class,num_testing)) - - for i in range(num_testing): - for k in range(num_class): - temp = 0 - for j in range(num_training): - - temp=temp + np.dot(Weights[k,j],kernel[i,j]) - #temp = np.array([temp], dtype=int) - #temp.append(int(temp)) - temp=temp+Bias[k] - Outputs[k,i]=temp - #hh = Outputs - #mm, nn = np.shape(Outputs) - - for i in range(num_testing): ########### this logic is only for 3 classes and can be modified for further classes - - idx,val = max(enumerate(Outputs[:,i]), key=operator.itemgetter(1)) - - if idx == 0: - Outputs[idx+1,i]=0 - Outputs[idx+2,i]=0 - if idx == 1: - Outputs[idx+1,i]=0 - Outputs[idx-1,i]=0 - if idx == 2: - Outputs[idx-1,i]=0 - Outputs[idx-2,i]=0 - - Pre_Labels = np.zeros(shape = (num_class,num_testing)) - for i in range(num_testing): - for k in range(num_class): - - if (abs(Outputs[k,i]) > 0): - Pre_Labels[k,i]=1 - else: - Pre_Labels[k,i]=-1 - - return Outputs, Pre_Labels - - -def RankSVM_test(test_data, num_class, Weights, Bias, SVs, - svm='Poly', gamma=0.05, - coefficient=0.05, degree=3): - num_testing, tempvalue = np.shape(test_data) - # num_class, tempvalue = np.shape(test_target) - tempvalue, num_training = np.shape(SVs) - # Label = np.array(np.zeros(shape=(num_testing,1)), dtype=float) - # not_Label = [] - # Label_size = np.zeros(shape=(1,num_testing)) - # size_alpha = np.zeros(shape=(1,num_training), dtype=float) - # lc = np.ones(shape=(1,num_class)) - # for i in range(num_testing): - # temp = test_target[:,int(i)] - # Label_size[0,int(i)] = np.sum(temp == lc) - # lds = num_class-Label_size[0,int(i)] - # size_alpha[0,int(i)] = np.dot(lds, Label_size[0,int(i)]) - # for j in range(num_class): - # if temp[int(j)] == 1: - # Label[int(i),0] = np.array([j]) - # else: - # not_Label.append((j)) - # - # not_Label = np.reshape(not_Label, (num_testing,num_class-1)) - - kernel = np.zeros(shape =(num_testing, num_training), dtype=float) - if svm == 'RBF': - for i in range(num_testing): - for j in range(num_training): - kernel[int(i),int(j)] = np.exp(-gamma*(np.sum(((test_data[i,:].conj.T)-SVs[:,j])**2))) - - - else: - if svm == 'Poly': - for i in range(num_testing): - for j in range(num_training): - ab= np.dot((np.array([SVs[:,int(j)]])),(np.array([test_data[int(i),:]]).T)) - ab=gamma*ab - ab=ab+coefficient - ab=ab**degree - #kernel[int(i),int(j)] = (gamma*(SVs[:,int(i)].conj().T)*SVs[:,int(j)]+coefficient)**degree - kernel[int(i),int(j)] = np.array([ab]) - else: - for i in range(num_testing): - for j in range(num_training): - kernel[int(i),int(j)] = np.dot((np.array([SVs[:,int(j)]])),(np.array([test_data[int(i),:]]))) - - Probabilities = np.zeros(shape=(num_class,num_testing)) - - for i in range(num_testing): - for k in range(num_class): - temp = 0 - for j in range(num_training): - - temp=temp + np.dot(Weights[k,j],kernel[i,j]) - #temp = np.array([temp], dtype=int) - #temp.append(int(temp)) - temp=temp+Bias[k] - Probabilities[k,i]=temp - #hh = Outputs - #mm, nn = np.shape(Outputs) - - # Class with maximum probability is predicted as label - Predicted_Labels = np.zeros(Probabilities.shape) - # Probabilities = np.asarray([np.argmax(Probabilities[:, i]) for i in range(num_testing)]) - for i in range(num_testing): - idx = np.argmax(Probabilities[:, i]) - Predicted_Labels[idx, i] = 1 - - # Transpose in order to be compatible with sklearn - Probabilities = np.transpose(Probabilities) - Predicted_Labels = np.transpose(Predicted_Labels) - - return Probabilities, Predicted_Labels diff --git a/build/lib/WORC/classification/SearchCV.py b/build/lib/WORC/classification/SearchCV.py deleted file mode 100644 index 91a71530..00000000 --- a/build/lib/WORC/classification/SearchCV.py +++ /dev/null @@ -1,2469 +0,0 @@ -#!/usr/bin/env python - -# Copyright 2016-2019 Biomedical Imaging Group Rotterdam, Departments of -# Medical Informatics and Radiology, Erasmus MC, Rotterdam, The Netherlands -# -# 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. - - -from sklearn.base import BaseEstimator, is_classifier, clone -from sklearn.base import MetaEstimatorMixin -from sklearn.exceptions import NotFittedError -from sklearn.utils.metaestimators import if_delegate_has_method -from sklearn.utils.validation import indexable, check_is_fitted -from WORC.classification.metrics import check_scoring -from sklearn.model_selection._split import check_cv -from scipy.stats import rankdata -from sklearn.externals import six -from sklearn.utils.fixes import MaskedArray - -from sklearn.model_selection._search import _CVScoreTuple, ParameterSampler -from sklearn.model_selection._search import ParameterGrid, _check_param_grid - -from abc import ABCMeta, abstractmethod -from collections import Sized, defaultdict -import numpy as np -from functools import partial -import warnings - -import os -import random -import string -import fastr -from fastr.api import ResourceLimit -from joblib import Parallel, delayed -from WORC.classification.fitandscore import fit_and_score -from WORC.classification.fitandscore import delete_nonestimator_parameters -import WORC.addexceptions as WORCexceptions -import pandas as pd -import json -import glob -from itertools import islice -import shutil -from sklearn.metrics import f1_score, roc_auc_score, mean_squared_error -from sklearn.metrics import accuracy_score -from sklearn.multiclass import OneVsRestClassifier -from WORC.classification.estimators import RankedSVM -from WORC.classification import construct_classifier as cc - - -def rms_score(truth, prediction): - ''' Root-mean-square-error metric''' - return np.sqrt(mean_squared_error(truth, prediction)) - - -def sar_score(truth, prediction): - ''' SAR metric from Caruana et al. 2004''' - - ROC = roc_auc_score(truth, prediction) - # Convert score to binaries first - for num in range(0, len(prediction)): - if prediction[num] >= 0.5: - prediction[num] = 1 - else: - prediction[num] = 0 - - ACC = accuracy_score(truth, prediction) - RMS = rms_score(truth, prediction) - SAR = (ACC + ROC + (1 - RMS))/3 - return SAR - - -def chunksdict(data, SIZE): - '''Split a dictionary in equal parts of certain slice''' - it = iter(data) - for i in xrange(0, len(data), SIZE): - yield {k: data[k] for k in islice(it, SIZE)} - - -def chunks(l, n): - """Yield successive n-sized chunks from l.""" - for i in range(0, len(l), n): - yield l[i:i + n] - - -class Ensemble(six.with_metaclass(ABCMeta, BaseEstimator, - MetaEstimatorMixin)): - """Ensemble of BaseSearchCV Estimators.""" - # @abstractmethod - def __init__(self, estimators): - self.estimators = estimators - self.n_estimators = len(estimators) - - def predict(self, X): - """Call predict on the estimator with the best found parameters. - - Only available if ``refit=True`` and the underlying estimator supports - ``predict``. - - Parameters - ----------- - X : indexable, length n_samples - Must fulfill the input assumptions of the - underlying estimator. - - """ - self.estimators[0]._check_is_fitted('predict') - - # NOTE: Check if we are dealing with multilabel - if type(self.estimators[0].best_estimator_) == OneVsRestClassifier: - # Multilabel - nlabels = self.estimators[0].predict(X).shape[1] - outcome = np.zeros((self.n_estimators, len(X), nlabels)) - for num, est in enumerate(self.estimators): - if hasattr(est, 'predict_proba'): - # BUG: SVM kernel can be wrong type - if hasattr(est.best_estimator_, 'kernel'): - est.best_estimator_.kernel = str(est.best_estimator_.kernel) - outcome[num, :, :] = est.predict_proba(X)[:, 1] - else: - outcome[num, :, :] = est.predict(X) - - outcome = np.squeeze(np.mean(outcome, axis=0)) - - # NOTE: Binarize specifically for multiclass - for i in range(0, outcome.shape[0]): - label = np.argmax(outcome[i, :]) - outcome[i, :] = np.zeros(outcome.shape[1]) - outcome[i, label] = 1 - - else: - # Singlelabel - outcome = np.zeros((self.n_estimators, len(X))) - for num, est in enumerate(self.estimators): - if hasattr(est, 'predict_proba'): - # BUG: SVM kernel can be wrong type - if hasattr(est.best_estimator_, 'kernel'): - est.best_estimator_.kernel = str(est.best_estimator_.kernel) - outcome[num, :] = est.predict_proba(X)[:, 1] - else: - outcome[num, :] = est.predict(X) - - outcome = np.squeeze(np.mean(outcome, axis=0)) - - # Binarize - isclassifier = is_classifier(est.best_estimator_) - - if isclassifier: - outcome[outcome >= 0.5] = 1 - outcome[outcome < 0.5] = 0 - - return outcome - - def predict_proba(self, X): - """Call predict_proba on the estimator with the best found parameters. - - Only available if ``refit=True`` and the underlying estimator supports - ``predict_proba``. - - Parameters - ----------- - X : indexable, length n_samples - Must fulfill the input assumptions of the - underlying estimator. - - """ - self.estimators[0]._check_is_fitted('predict_proba') - - # For probabilities, we get both a class0 and a class1 score - outcome = np.zeros((len(X), 2)) - outcome_class1 = np.zeros((self.n_estimators, len(X))) - outcome_class2 = np.zeros((self.n_estimators, len(X))) - for num, est in enumerate(self.estimators): - # BUG: SVM kernel can be wrong type - if hasattr(est.best_estimator_, 'kernel'): - est.best_estimator_.kernel = str(est.best_estimator_.kernel) - outcome_class1[num, :] = est.predict_proba(X)[:, 0] - outcome_class2[num, :] = est.predict_proba(X)[:, 1] - - outcome[:, 0] = np.squeeze(np.mean(outcome_class1, axis=0)) - outcome[:, 1] = np.squeeze(np.mean(outcome_class2, axis=0)) - return outcome - - def predict_log_proba(self, X): - """Call predict_log_proba on the estimator with the best found parameters. - - Only available if ``refit=True`` and the underlying estimator supports - ``predict_log_proba``. - - Parameters - ----------- - X : indexable, length n_samples - Must fulfill the input assumptions of the - underlying estimator. - - """ - self.estimators[0]._check_is_fitted('predict_log_proba') - - outcome = np.zeros((self.n_estimators, len(X))) - for num, est in enumerate(self.estimators): - outcome[num, :] = est.predict_log_proba(X) - - outcome = np.squeeze(np.mean(outcome, axis=0)) - return outcome - - def decision_function(self, X): - """Call decision_function on the estimator with the best found parameters. - - Only available if ``refit=True`` and the underlying estimator supports - ``decision_function``. - - Parameters - ----------- - X : indexable, length n_samples - Must fulfill the input assumptions of the - underlying estimator. - - """ - self.estimators[0]._check_is_fitted('decision_function') - - # NOTE: Check if we are dealing with multilabel - if type(self.estimators[0].best_estimator_) == OneVsRestClassifier: - # Multilabel - nlabels = self.estimators[0].decision_function(X).shape[1] - outcome = np.zeros((self.n_estimators, len(X), nlabels)) - for num, est in enumerate(self.estimators): - outcome[num, :, :] = est.decision_function(X) - - outcome = np.squeeze(np.mean(outcome, axis=0)) - - else: - # Singlelabel - outcome = np.zeros((self.n_estimators, len(X))) - for num, est in enumerate(self.estimators): - outcome[num, :] = est.decision_function(X) - - outcome = np.squeeze(np.mean(outcome, axis=0)) - - return outcome - - def transform(self, X): - """Call transform on the estimator with the best found parameters. - - Only available if the underlying estimator supports ``transform`` and - ``refit=True``. - - Parameters - ----------- - X : indexable, length n_samples - Must fulfill the input assumptions of the - underlying estimator. - - """ - self.estimators[0]._check_is_fitted('transform') - - outcome = np.zeros((self.n_estimators, len(X))) - for num, est in enumerate(self.estimators): - outcome[num, :] = est.transform(X) - - outcome = np.squeeze(np.mean(outcome, axis=0)) - return outcome - - def inverse_transform(self, Xt): - """Call inverse_transform on the estimator with the best found params. - - Only available if the underlying estimator implements - ``inverse_transform`` and ``refit=True``. - - Parameters - ----------- - Xt : indexable, length n_samples - Must fulfill the input assumptions of the - underlying estimator. - - """ - self.estimators[0]._check_is_fitted('inverse_transform') - - outcome = np.zeros((self.n_estimators, len(Xt))) - for num, est in enumerate(self.estimators): - outcome[num, :] = est.transform(Xt) - - outcome = np.squeeze(np.mean(outcome, axis=0)) - return outcome - - -class BaseSearchCV(six.with_metaclass(ABCMeta, BaseEstimator, - MetaEstimatorMixin)): - """Base class for hyper parameter search with cross-validation.""" - @abstractmethod - def __init__(self, param_distributions={}, n_iter=10, scoring=None, - fit_params=None, n_jobs=1, iid=True, - refit=True, cv=None, verbose=0, pre_dispatch='2*n_jobs', - random_state=None, error_score='raise', return_train_score=True, - n_jobspercore=100, maxlen=100, fastr_plugin=None): - - # Added for fastr and joblib executions - self.param_distributions = param_distributions - self.n_iter = n_iter - self.n_jobspercore = n_jobspercore - self.random_state = random_state - self.ensemble = list() - self.fastr_plugin = fastr_plugin - - # Below are the defaults from sklearn - self.scoring = scoring - self.n_jobs = n_jobs - self.fit_params = fit_params if fit_params is not None else {} - self.iid = iid - self.refit = refit - self.cv = cv - self.verbose = verbose - self.pre_dispatch = pre_dispatch - self.error_score = error_score - self.return_train_score = return_train_score - self.maxlen = maxlen - - @property - def _estimator_type(self): - return self.estimator._estimator_type - - def score(self, X, y=None): - """Returns the score on the given data, if the estimator has been refit. - - This uses the score defined by ``scoring`` where provided, and the - ``best_estimator_.score`` method otherwise. - - Parameters - ---------- - X : array-like, shape = [n_samples, n_features] - Input data, where n_samples is the number of samples and - n_features is the number of features. - - y : array-like, shape = [n_samples] or [n_samples, n_output], optional - Target relative to X for classification or regression; - None for unsupervised learning. - - Returns - ------- - score : float - """ - if self.scorer_ is None: - raise ValueError("No score function explicitly defined, " - "and the estimator doesn't provide one %s" - % self.best_estimator_) - - X, y = self.preprocess(X, y) - - return self.scorer_(self.best_estimator_, X, y) - - def _check_is_fitted(self, method_name): - if not self.refit: - raise NotFittedError(('This GridSearchCV instance was initialized ' - 'with refit=False. %s is ' - 'available only after refitting on the best ' - 'parameters. ') % method_name) - else: - check_is_fitted(self, 'best_estimator_') - - @if_delegate_has_method(delegate=('best_estimator_', 'estimator')) - def predict(self, X): - """Call predict on the estimator with the best found parameters. - - Only available if ``refit=True`` and the underlying estimator supports - ``predict``. - - Parameters - ----------- - X : indexable, length n_samples - Must fulfill the input assumptions of the - underlying estimator. - - """ - self._check_is_fitted('predict') - - if self.ensemble: - return self.ensemble.predict(X) - else: - X, _ = self.preprocess(X) - return self.best_estimator_.predict(X) - - @if_delegate_has_method(delegate=('best_estimator_', 'estimator')) - def predict_proba(self, X): - """Call predict_proba on the estimator with the best found parameters. - - Only available if ``refit=True`` and the underlying estimator supports - ``predict_proba``. - - Parameters - ----------- - X : indexable, length n_samples - Must fulfill the input assumptions of the - underlying estimator. - - """ - self._check_is_fitted('predict_proba') - - # BUG: kernel sometimes saved as unicode - # BUG: SVM kernel can be wrong type - if hasattr(self.best_estimator_, 'kernel'): - self.best_estimator_.kernel = str(self.best_estimator_.kernel) - if self.ensemble: - return self.ensemble.predict_proba(X) - else: - X, _ = self.preprocess(X) - return self.best_estimator_.predict_proba(X) - - @if_delegate_has_method(delegate=('best_estimator_', 'estimator')) - def predict_log_proba(self, X): - """Call predict_log_proba on the estimator with the best found parameters. - - Only available if ``refit=True`` and the underlying estimator supports - ``predict_log_proba``. - - Parameters - ----------- - X : indexable, length n_samples - Must fulfill the input assumptions of the - underlying estimator. - - """ - self._check_is_fitted('predict_log_proba') - - # BUG: SVM kernel can be wrong type - if hasattr(self.est.best_estimator_, 'kernel'): - self.best_estimator_.kernel = str(self.best_estimator_.kernel) - - if self.ensemble: - return self.ensemble.predict_log_proba(X) - else: - X, _ = self.preprocess(X) - return self.best_estimator_.predict_log_proba(X) - - @if_delegate_has_method(delegate=('best_estimator_', 'estimator')) - def decision_function(self, X): - """Call decision_function on the estimator with the best found parameters. - - Only available if ``refit=True`` and the underlying estimator supports - ``decision_function``. - - Parameters - ----------- - X : indexable, length n_samples - Must fulfill the input assumptions of the - underlying estimator. - - """ - self._check_is_fitted('decision_function') - - if self.ensemble: - return self.ensemble.decision_function(X) - else: - X, _ = self.preprocess(X) - return self.best_estimator_.decision_function(X) - - @if_delegate_has_method(delegate=('best_estimator_', 'estimator')) - def transform(self, X): - """Call transform on the estimator with the best found parameters. - - Only available if the underlying estimator supports ``transform`` and - ``refit=True``. - - Parameters - ----------- - X : indexable, length n_samples - Must fulfill the input assumptions of the - underlying estimator. - - """ - self._check_is_fitted('transform') - - if self.ensemble: - return self.ensemble.transform(X) - else: - X = self.preprocess(X) - return self.best_estimator_.transform(X) - - @if_delegate_has_method(delegate=('best_estimator_', 'estimator')) - def inverse_transform(self, Xt): - """Call inverse_transform on the estimator with the best found params. - - Only available if the underlying estimator implements - ``inverse_transform`` and ``refit=True``. - - Parameters - ----------- - Xt : indexable, length n_samples - Must fulfill the input assumptions of the - underlying estimator. - - """ - self._check_is_fitted('inverse_transform') - - if self.ensemble: - return self.ensemble.transform(Xt) - else: - Xt, _ = self.preprocess(Xt) - return self.best_estimator_.transform(Xt) - - def preprocess(self, X, y=None): - '''Apply the available preprocssing methods to the features''' - if self.best_imputer is not None: - X = self.best_imputer.transform(X) - - # Only oversample in training phase, i.e. if we have the labels - if y is not None: - if self.best_SMOTE is not None: - X, y = self.best_SMOTE.fit_sample(X, y) - - if self.best_RandomOverSampler is not None: - X, y = self.best_RandomOverSampler.fit_sample(X, y) - - if self.best_groupsel is not None: - X = self.best_groupsel.transform(X) - - if self.best_varsel is not None: - X = self.best_varsel.transform(X) - - if self.best_statisticalsel is not None: - X = self.best_statisticalsel.transform(X) - - if self.best_scaler is not None: - X = self.best_scaler.transform(X) - - if self.best_reliefsel is not None: - X = self.best_reliefsel.transform(X) - - if self.best_pca is not None: - X = self.best_pca.transform(X) - - if self.best_modelsel is not None: - X = self.best_modelsel.transform(X) - - return X, y - - @property - def best_params_(self): - check_is_fitted(self, 'cv_results_') - return self.cv_results_['params_all'][self.best_index_] - - @property - def best_score_(self): - check_is_fitted(self, 'cv_results_') - return self.cv_results_['mean_test_score'][self.best_index_] - - @property - def grid_scores_(self): - warnings.warn( - "The grid_scores_ attribute was deprecated in version 0.18" - " in favor of the more elaborate cv_results_ attribute." - " The grid_scores_ attribute will not be available from 0.20", - DeprecationWarning) - - check_is_fitted(self, 'cv_results_') - grid_scores = list() - - for i, (params, mean, std) in enumerate(zip( - self.cv_results_['params'], - self.cv_results_['mean_test_score'], - self.cv_results_['std_test_score'])): - scores = np.array(list(self.cv_results_['split%d_test_score' - % s][i] - for s in range(self.n_splits_)), - dtype=np.float64) - grid_scores.append(_CVScoreTuple(params, mean, scores)) - - return grid_scores - - def process_fit(self, n_splits, parameters_est, parameters_all, - test_sample_counts, test_scores, - train_scores, fit_time, score_time, cv_iter, - X, y): - - """ - Process the outcomes of a SearchCV fit and find the best settings - over all cross validations from all hyperparameters tested - - """ - # We take only one result per split, default by sklearn - candidate_params_est = list(parameters_est[::n_splits]) - candidate_params_all = list(parameters_all[::n_splits]) - n_candidates = len(candidate_params_est) - - # Computed the (weighted) mean and std for test scores alone - # NOTE test_sample counts (weights) remain the same for all candidates - test_sample_counts = np.array(test_sample_counts[:n_splits], - dtype=np.int) - - # Store some of the resulting scores - results = dict() - - def _store(key_name, array, weights=None, splits=False, rank=False): - """A small helper to store the scores/times to the cv_results_""" - array = np.array(array, dtype=np.float64).reshape(n_candidates, - n_splits) - if splits: - for split_i in range(n_splits): - results["split%d_%s" - % (split_i, key_name)] = array[:, split_i] - - try: - array_means = np.average(array, axis=1, weights=weights) - except ZeroDivisionError as e: - e = ('[PREDICT Warning] {}. Setting {} to unweighted.').format(e, key_name) - print(e) - array_means = np.average(array, axis=1) - - results['mean_%s' % key_name] = array_means - # Weighted std is not directly available in numpy - try: - array_stds = np.sqrt(np.average((array - - array_means[:, np.newaxis]) ** 2, - axis=1, weights=weights)) - except ZeroDivisionError as e: - e = ('[PREDICT Warning] {}. Setting {} to unweighted.').format(e, key_name) - print(e) - array_stds = np.sqrt(np.average((array - - array_means[:, np.newaxis]) ** 2, - axis=1)) - - results['std_%s' % key_name] = array_stds - - if rank: - results["rank_%s" % key_name] = np.asarray( - rankdata(-array_means, method='min'), dtype=np.int32) - - _store('test_score', test_scores, splits=True, rank=True, - weights=test_sample_counts if self.iid else None) - if self.return_train_score: - _store('train_score', train_scores, splits=True) - _store('fit_time', fit_time) - _store('score_time', score_time) - - # Rank the indices of scores from all parameter settings - ranked_test_scores = results["rank_test_score"] - indices = range(0, len(ranked_test_scores)) - sortedindices = [x for _, x in sorted(zip(ranked_test_scores, indices))] - - # In order to reduce the memory used, we will only save - # a maximum of results - maxlen = min(self.maxlen, n_candidates) - bestindices = sortedindices[0:maxlen] - - candidate_params_est = np.asarray(candidate_params_est)[bestindices].tolist() - candidate_params_all = np.asarray(candidate_params_all)[bestindices].tolist() - for k in results.keys(): - results[k] = results[k][bestindices] - n_candidates = len(candidate_params_est) - - # Store the atributes of the best performing estimator - best_index = np.flatnonzero(results["rank_test_score"] == 1)[0] - best_parameters_est = candidate_params_est[best_index] - best_parameters_all = candidate_params_all[best_index] - - # Use one MaskedArray and mask all the places where the param is not - # applicable for that candidate. Use defaultdict as each candidate may - # not contain all the params - param_results = defaultdict(partial(MaskedArray, - np.empty(n_candidates,), - mask=True, - dtype=object)) - for cand_i, params in enumerate(candidate_params_all): - for name, value in params.items(): - # An all masked empty array gets created for the key - # `"param_%s" % name` at the first occurence of `name`. - # Setting the value at an index also unmasks that index - param_results["param_%s" % name][cand_i] = value - - # Store a list of param dicts at the key 'params' - results['params'] = candidate_params_est - results['params_all'] = candidate_params_all - - self.cv_results_ = results - self.best_index_ = best_index - self.n_splits_ = n_splits - self.cv_iter = cv_iter - - # Refit all objects with best settings on the full dataset - indices = range(0, len(y)) - self.refit_and_score(X, y, best_parameters_all, best_parameters_est, - train=indices, test=indices) - - return self - - def refit_and_score(self, X, y, parameters_all, parameters_est, - train, test, verbose=None): - """Refit the base estimator and attributes such as GroupSel - - Parameters - ---------- - X: array, mandatory - Array containingfor each object (rows) the feature values - (1st Column) and the associated feature label (2nd Column). - - y: list(?), mandatory - List containing the labels of the objects. - - parameters_all: dictionary, mandatory - Contains the settings used for the all preprocessing functions - and the fitting. TODO: Create a default object and show the - fields. - - parameters_est: dictionary, mandatory - Contains the settings used for the base estimator - - train: list, mandatory - Indices of the objects to be used as training set. - - test: list, mandatory - Indices of the objects to be used as testing set. - - - """ - - if verbose is None: - verbose = self.verbose - - # Refit all preprocessing functions - out = fit_and_score(X, y, self.scoring, - train, test, parameters_all, - fit_params=self.fit_params, - return_train_score=self.return_train_score, - return_n_test_samples=True, - return_times=True, return_parameters=True, - error_score=self.error_score, - verbose=verbose, - return_all=True) - - # Associate best options with new fits - (save_data, GroupSel, VarSel, SelectModel, feature_labels, scalers,\ - Imputers, PCAs, StatisticalSel, ReliefSel, sm, ros) = out - self.best_groupsel = GroupSel - self.best_scaler = scalers - self.best_varsel = VarSel - self.best_modelsel = SelectModel - self.best_imputer = Imputers - self.best_pca = PCAs - self.best_featlab = feature_labels - self.best_statisticalsel = StatisticalSel - self.best_reliefsel = ReliefSel - self.best_SMOTE = sm - self.best_RandomOverSampler = ros - - # Fit the estimator using the preprocessed features - X = [x[0] for x in X] - X, y = self.preprocess(X, y) - - parameters_est = delete_nonestimator_parameters(parameters_est) - best_estimator = cc.construct_classifier(parameters_all) - - # NOTE: This just has to go to the construct classifier function, - # although it is more convenient here due to the hyperparameter search - if type(y) is list: - labellength = 1 - else: - try: - labellength = y.shape[1] - except IndexError: - labellength = 1 - - if labellength > 1 and type(best_estimator) != RankedSVM: - # Multiclass, hence employ a multiclass classifier for e.g. SVM, RF - best_estimator = OneVsRestClassifier(best_estimator) - - if y is not None: - best_estimator.fit(X, y, **self.fit_params) - else: - best_estimator.fit(X, **self.fit_params) - self.best_estimator_ = best_estimator - - return self - - def create_ensemble(self, X_train, Y_train, verbose=None, initialize=True, - scoring=None, method=50): - # NOTE: Function is still WIP, do not actually use this. - ''' - - Create an (optimal) ensemble of a combination of hyperparameter settings - and the associated groupsels, PCAs, estimators etc. - - Based on Caruana et al. 2004, but a little different: - - 1. Recreate the training/validation splits for a n-fold cross validation. - 2. For each fold: - a. Start with an empty ensemble - b. Create starting ensemble by adding N individually best performing - models on the validation set. N is tuned on the validation set. - c. Add model that improves ensemble performance on validation set the most, with replacement. - d. Repeat (c) untill performance does not increase - - The performance metric is the same as for the original hyperparameter - search, i.e. probably the F1-score for classification and r2-score - for regression. However, we recommend using the SAR score, as this is - more universal. - - Method: top50 or Caruana - - ''' - - # Define a function for scoring the performance of a classifier - def compute_performance(scoring, Y_valid_truth, Y_valid_score): - if scoring == 'f1_weighted': - # Convert score to binaries first - for num in range(0, len(Y_valid_score)): - if Y_valid_score[num] >= 0.5: - Y_valid_score[num] = 1 - else: - Y_valid_score[num] = 0 - - perf = f1_score(Y_valid_truth, Y_valid_score, average='weighted') - elif scoring == 'auc': - perf = roc_auc_score(Y_valid_truth, Y_valid_score) - elif scoring == 'sar': - perf = sar_score(Y_valid_truth, Y_valid_score) - else: - raise KeyError('[PREDICT Warning] No valid score method given in ensembling: ' + str(scoring)) - - return perf - - if verbose is None: - verbose = self.verbose - - if scoring is None: - scoring = self.scoring - - # Get settings for best 100 estimators - parameters_est = self.cv_results_['params'] - parameters_all = self.cv_results_['params_all'] - n_classifiers = len(parameters_est) - n_iter = len(self.cv_iter) - - # Create a new base object for the ensemble components - if type(self) == RandomizedSearchCVfastr: - base_estimator = RandomizedSearchCVfastr() - elif type(self) == RandomizedSearchCVJoblib: - base_estimator = RandomizedSearchCVJoblib() - - if type(method) is int: - # Simply take the top50 best hyperparameters - if verbose: - print(f'Creating ensemble using top {str(method)} individual classifiers.') - ensemble = range(0, method) - - elif method == 'FitNumber': - # Use optimum number of models - - # In order to speed up the process, we precompute all scores of the possible - # classifiers in all cross validation estimatons - - # Create the training and validation set scores - if verbose: - print('Precomputing scores on training and validation set.') - Y_valid_score = list() - Y_valid_truth = list() - performances = np.zeros((n_iter, n_classifiers)) - for it, (train, valid) in enumerate(self.cv_iter): - if verbose: - print(f' - iteration {it + 1} / {n_iter}.') - Y_valid_score_it = np.zeros((n_classifiers, len(valid))) - - # Loop over the 100 best estimators - for num, (p_est, p_all) in enumerate(zip(parameters_est, parameters_all)): - # NOTE: Explicitly exclude validation set, elso refit and score - # somehow still seems to use it. - X_train_temp = [X_train[i] for i in train] - Y_train_temp = [Y_train[i] for i in train] - train_temp = range(0, len(train)) - - # Refit a SearchCV object with the provided parameters - base_estimator.refit_and_score(X_train_temp, Y_train_temp, p_all, - p_est, train_temp, train_temp, - verbose=False) - - # Predict and save scores - X_train_values = [x[0] for x in X_train] # Throw away labels - X_train_values_valid = [X_train_values[i] for i in valid] - Y_valid_score_temp = base_estimator.predict_proba(X_train_values_valid) - - # Only take the probabilities for the second class - Y_valid_score_temp = Y_valid_score_temp[:, 1] - - # Append to array for all classifiers on this validation set - Y_valid_score_it[num, :] = Y_valid_score_temp - - if num == 0: - # Also store the validation ground truths - Y_valid_truth.append(Y_train[valid]) - - performances[it, num] = compute_performance(scoring, - Y_train[valid], - Y_valid_score_temp) - - Y_valid_score.append(Y_valid_score_it) - - # Sorted Ensemble Initialization ------------------------------------- - # Go on adding to the ensemble untill we find the optimal performance - # Initialize variables - - # Note: doing this in a greedy way doesnt work. We compute the - # performances for the ensembles of lengt [1, n_classifiers] and - # select the optimum - best_performance = 0 - new_performance = 0.001 - iteration = 0 - ensemble = list() - y_score = [None]*n_iter - best_index = 0 - single_estimator_performance = new_performance - - if initialize: - # Rank the models based on scoring on the validation set - performances = np.mean(performances, axis=0) - sortedindices = np.argsort(performances)[::-1] - performances_n_class = list() - - if verbose: - print("\n") - print('Sorted Ensemble Initialization.') - # while new_performance > best_performance: - for dummy in range(0, n_classifiers): - # Score is better, so expand ensemble and replace new best score - best_performance = new_performance - - if iteration > 1: - # Stack scores: not needed for first iteration - ensemble.append(best_index) - # N_models += 1 - for num in range(0, n_iter): - y_score[num] = np.vstack((y_score[num], Y_valid_score[num][ensemble[-1], :])) - - elif iteration == 1: - # Create y_score object for second iteration - single_estimator_performance = new_performance - ensemble.append(best_index) - # N_models += 1 - for num in range(0, n_iter): - y_score[num] = Y_valid_score[num][ensemble[-1], :] - - # Perform n-fold cross validation to estimate performance of next best classifier - performances_temp = np.zeros((n_iter)) - for n_crossval in range(0, n_iter): - # For each estimator, add the score to the ensemble and new ensemble performance - if iteration == 0: - # No y_score yet, so we need to build it instead of stacking - y_valid_score_new = Y_valid_score[n_crossval][sortedindices[iteration], :] - else: - # Stack scores of added model on top of previous scores and average - y_valid_score_new = np.mean(np.vstack((y_score[n_crossval], Y_valid_score[n_crossval][sortedindices[iteration], :])), axis=0) - - perf = compute_performance(scoring, Y_valid_truth[n_crossval], y_valid_score_new) - performances_temp[n_crossval] = perf - - # Check which ensemble should be in the ensemble to maximally improve - new_performance = np.mean(performances_temp) - performances_n_class.append(new_performance) - best_index = sortedindices[iteration] - iteration += 1 - - # Select N_models for initialization - new_performance = max(performances_n_class) - N_models = performances_n_class.index(new_performance) + 1 # +1 due to python indexing - ensemble = ensemble[0:N_models] - best_performance = new_performance - - # Print the performance gain - print(f"Ensembling best {scoring}: {best_performance}.") - print(f"Single estimator best {scoring}: {single_estimator_performance}.") - print(f'Ensemble consists of {len(ensemble)} estimators {ensemble}.') - - elif method == 'Caruana': - # Use the method from Caruana - if verbose: - print('Creating ensemble with Caruana method.') - - # BUG: kernel parameter is sometimes saved in unicode - for i in range(0, len(parameters_est)): - kernel = str(parameters_est[i][u'kernel']) - del parameters_est[i][u'kernel'] - del parameters_all[i][u'kernel'] - parameters_est[i]['kernel'] = kernel - parameters_all[i]['kernel'] = kernel - - # In order to speed up the process, we precompute all scores of the possible - # classifiers in all cross validation estimatons - - # Create the training and validation set scores - if verbose: - print('Precomputing scores on training and validation set.') - Y_valid_score = list() - Y_valid_truth = list() - performances = np.zeros((n_iter, n_classifiers)) - for it, (train, valid) in enumerate(self.cv_iter): - if verbose: - print(f' - iteration {it + 1} / {n_iter}.') - Y_valid_score_it = np.zeros((n_classifiers, len(valid))) - - # Loop over the 100 best estimators - for num, (p_est, p_all) in enumerate(zip(parameters_est, parameters_all)): - # NOTE: Explicitly exclude validation set, elso refit and score - # somehow still seems to use it. - X_train_temp = [X_train[i] for i in train] - Y_train_temp = [Y_train[i] for i in train] - train_temp = range(0, len(train)) - - # Refit a SearchCV object with the provided parameters - base_estimator.refit_and_score(X_train_temp, Y_train_temp, p_all, - p_est, train_temp, train_temp, - verbose=False) - - # Predict and save scores - X_train_values = [x[0] for x in X_train] # Throw away labels - X_train_values_valid = [X_train_values[i] for i in valid] - Y_valid_score_temp = base_estimator.predict_proba(X_train_values_valid) - - # Only take the probabilities for the second class - Y_valid_score_temp = Y_valid_score_temp[:, 1] - - # Append to array for all classifiers on this validation set - Y_valid_score_it[num, :] = Y_valid_score_temp - - if num == 0: - # Also store the validation ground truths - Y_valid_truth.append(Y_train[valid]) - - performances[it, num] = compute_performance(scoring, - Y_train[valid], - Y_valid_score_temp) - - Y_valid_score.append(Y_valid_score_it) - - # Sorted Ensemble Initialization ------------------------------------- - # Go on adding to the ensemble untill we find the optimal performance - # Initialize variables - - # Note: doing this in a greedy way doesnt work. We compute the - # performances for the ensembles of lengt [1, n_classifiers] and - # select the optimum - best_performance = 0 - new_performance = 0.001 - iteration = 0 - ensemble = list() - y_score = [None]*n_iter - best_index = 0 - single_estimator_performance = new_performance - - if initialize: - # Rank the models based on scoring on the validation set - performances = np.mean(performances, axis=0) - sortedindices = np.argsort(performances)[::-1] - performances_n_class = list() - - if verbose: - print("\n") - print('Sorted Ensemble Initialization.') - # while new_performance > best_performance: - for dummy in range(0, n_classifiers): - # Score is better, so expand ensemble and replace new best score - best_performance = new_performance - - if iteration > 1: - # Stack scores: not needed for first iteration - ensemble.append(best_index) - # N_models += 1 - for num in range(0, n_iter): - y_score[num] = np.vstack((y_score[num], Y_valid_score[num][ensemble[-1], :])) - - elif iteration == 1: - # Create y_score object for second iteration - single_estimator_performance = new_performance - ensemble.append(best_index) - # N_models += 1 - for num in range(0, n_iter): - y_score[num] = Y_valid_score[num][ensemble[-1], :] - - # Perform n-fold cross validation to estimate performance of next best classifier - performances_temp = np.zeros((n_iter)) - for n_crossval in range(0, n_iter): - # For each estimator, add the score to the ensemble and new ensemble performance - if iteration == 0: - # No y_score yet, so we need to build it instead of stacking - y_valid_score_new = Y_valid_score[n_crossval][sortedindices[iteration], :] - else: - # Stack scores of added model on top of previous scores and average - y_valid_score_new = np.mean(np.vstack((y_score[n_crossval], Y_valid_score[n_crossval][sortedindices[iteration], :])), axis=0) - - perf = compute_performance(scoring, Y_valid_truth[n_crossval], y_valid_score_new) - performances_temp[n_crossval] = perf - - # Check which ensemble should be in the ensemble to maximally improve - new_performance = np.mean(performances_temp) - performances_n_class.append(new_performance) - best_index = sortedindices[iteration] - iteration += 1 - - # Select N_models for initialization - new_performance = max(performances_n_class) - N_models = performances_n_class.index(new_performance) + 1 # +1 due to python indexing - ensemble = ensemble[0:N_models] - best_performance = new_performance - - # Print the performance gain - print(f"Ensembling best {scoring}: {best_performance}.") - print(f"Single estimator best {scoring}: {single_estimator_performance}.") - print(f'Ensemble consists of {len(ensemble)} estimators {ensemble}.') - - # Greedy selection ----------------------------------------------- - # Initialize variables - best_performance -= 1e-10 - iteration = 0 - - # Go on adding to the ensemble untill we find the optimal performance - if verbose: - print("\n") - print('Greedy selection.') - while new_performance > best_performance: - # Score is better, so expand ensemble and replace new best score - if verbose: - print(f"Iteration: {iteration}, best {scoring}: {new_performance}.") - best_performance = new_performance - - if iteration > 1: - # Stack scores: not needed for first iteration - ensemble.append(best_index) - for num in range(0, n_iter): - y_score[num] = np.vstack((y_score[num], Y_valid_score[num][ensemble[-1], :])) - - elif iteration == 1: - if not initialize: - # Create y_score object for second iteration - single_estimator_performance = new_performance - ensemble.append(best_index) - for num in range(0, n_iter): - y_score[num] = Y_valid_score[num][ensemble[-1], :] - else: - # Stack scores: not needed when ensemble initialization is already used - ensemble.append(best_index) - for num in range(0, n_iter): - y_score[num] = np.vstack((y_score[num], Y_valid_score[num][ensemble[-1], :])) - - # Perform n-fold cross validation to estimate performance of each possible addition to ensemble - performances_temp = np.zeros((n_iter, n_classifiers)) - for n_crossval in range(0, n_iter): - # For each estimator, add the score to the ensemble and new ensemble performance - for n_estimator in range(0, n_classifiers): - if iteration == 0: - # No y_score yet, so we need to build it instead of stacking - y_valid_score_new = Y_valid_score[n_crossval][n_estimator, :] - else: - # Stack scores of added model on top of previous scores and average - y_valid_score_new = np.mean(np.vstack((y_score[n_crossval], Y_valid_score[n_crossval][n_estimator, :])), axis=0) - - perf = compute_performance(scoring, Y_valid_truth[n_crossval], y_valid_score_new) - performances_temp[n_crossval, n_estimator] = perf - - # Average performances over crossval - performances_temp = list(np.mean(performances_temp, axis=0)) - - # Check which ensemble should be in the ensemble to maximally improve - new_performance = max(performances_temp) - best_index = performances_temp.index(new_performance) - iteration += 1 - - # Print the performance gain - print(f"Ensembling best {scoring}: {best_performance}.") - print(f"Single estimator best {scoring}: {single_estimator_performance}.") - print(f'Ensemble consists of {len(ensemble)} estimators {ensemble}.') - else: - print('[PREDICT WARNING] No valid ensemble method given: {}. Not ensembling').format(str(method)) - return self - - # Create the ensemble -------------------------------------------------- - # Create the ensemble trained on the full training set - parameters_est = [parameters_est[i] for i in ensemble] - parameters_all = [parameters_all[i] for i in ensemble] - estimators = list() - train = range(0, len(X_train)) - nest = len(ensemble) - for enum, (p_est, p_all) in enumerate(zip(parameters_est, parameters_all)): - # Refit a SearchCV object with the provided parameters - print(f"Refitting estimator {enum+1} / {nest}.") - base_estimator = clone(base_estimator) - - # # Check if we need to create a multiclass estimator - # if Y_train.shape[1] > 1 and type(base_estimator) != RankedSVM: - # # Multiclass, hence employ a multiclass classifier for SVM - # base_estimator = OneVsRestClassifier(base_estimator) - - base_estimator.refit_and_score(X_train, Y_train, p_all, - p_est, train, train, - verbose=False) - - estimators.append(base_estimator) - - self.ensemble = Ensemble(estimators) - - print("\n") - return self - - -class BaseSearchCVfastr(BaseSearchCV): - """Base class for hyper parameter search with cross-validation.""" - - def _fit(self, X, y, groups, parameter_iterable): - """Actual fitting, performing the search over parameters.""" - - regressors = ['SVR', 'RFR', 'SGDR', 'Lasso', 'ElasticNet'] - isclassifier =\ - not any(clf in regressors for clf in self.param_distributions['classifiers']) - - cv = check_cv(self.cv, y, classifier=isclassifier) - - X, y, groups = indexable(X, y, groups) - n_splits = cv.get_n_splits(X, y, groups) - if self.verbose > 0 and isinstance(parameter_iterable, Sized): - n_candidates = len(parameter_iterable) - print(f"Fitting {n_splits} folds for each of {n_candidates} candidates, totalling {n_candidates * n_splits} fits.") - - cv_iter = list(cv.split(X, y, groups)) - name = ''.join(random.choice(string.ascii_uppercase + string.digits) for _ in range(10)) - tempfolder = os.path.join(fastr.config.mounts['tmp'], 'GS', name) - if not os.path.exists(tempfolder): - os.makedirs(tempfolder) - - # Create the parameter files - parameters_temp = dict() - try: - for num, parameters in enumerate(parameter_iterable): - - parameters["Number"] = str(num) - parameters_temp[str(num)] = parameters - except ValueError: - # One of the parameters gives an error. Find out which one. - param_grid = dict() - for k, v in parameter_iterable.param_distributions.iteritems(): - param_grid[k] = v - sampled_params = ParameterSampler(param_grid, 5) - try: - for num, parameters in enumerate(sampled_params): - a = 1 - except ValueError: - break - - message = 'One or more of the values in your parameter sampler ' +\ - 'is either not iterable, or the distribution cannot ' +\ - 'generate valid samples. Please check your ' +\ - (' parameters. At least {} gives an error.').format(k) - raise PREDICTexceptions.PREDICTValueError(message) - - # Split the parameters files in equal parts - keys = list(parameters_temp.keys()) - keys = chunks(keys, self.n_jobspercore) - parameter_files = dict() - for num, k in enumerate(keys): - temp_dict = dict() - for number in k: - temp_dict[number] = parameters_temp[number] - - fname = ('settings_{}.json').format(str(num)) - sourcename = os.path.join(tempfolder, 'parameters', fname) - if not os.path.exists(os.path.dirname(sourcename)): - os.makedirs(os.path.dirname(sourcename)) - with open(sourcename, 'w') as fp: - json.dump(temp_dict, fp, indent=4) - - parameter_files[str(num)] =\ - ('vfs://tmp/{}/{}/{}/{}').format('GS', - name, - 'parameters', - fname) - - # Create test-train splits - traintest_files = dict() - # TODO: ugly nummering solution - num = 0 - for train, test in cv_iter: - source_labels = ['train', 'test'] - - source_data = pd.Series([train, test], - index=source_labels, - name='Train-test data') - - fname = ('traintest_{}.hdf5').format(str(num)) - sourcename = os.path.join(tempfolder, 'traintest', fname) - if not os.path.exists(os.path.dirname(sourcename)): - os.makedirs(os.path.dirname(sourcename)) - traintest_files[str(num)] = ('vfs://tmp/{}/{}/{}/{}').format('GS', - name, - 'traintest', - fname) - - sourcelabel = ("Source Data Iteration {}").format(str(num)) - source_data.to_hdf(sourcename, sourcelabel) - - num += 1 - - # Create the files containing the estimator and settings - estimator_labels = ['X', 'y', 'scoring', - 'verbose', 'fit_params', 'return_train_score', - 'return_n_test_samples', - 'return_times', 'return_parameters', - 'error_score'] - - estimator_data = pd.Series([X, y, self.scoring, - self.verbose, - self.fit_params, self.return_train_score, - True, True, True, - self.error_score], - index=estimator_labels, - name='estimator Data') - fname = 'estimatordata.hdf5' - estimatorname = os.path.join(tempfolder, fname) - estimator_data.to_hdf(estimatorname, 'Estimator Data') - - estimatordata = ("vfs://tmp/{}/{}/{}").format('GS', name, fname) - - # Create the fastr network - network = fastr.create_network('PREDICT_GridSearch_' + name) - estimator_data = network.create_source('HDF5', id='estimator_source') - traintest_data = network.create_source('HDF5', id='traintest') - parameter_data = network.create_source('JsonFile', id='parameters') - sink_output = network.create_sink('HDF5', id='output') - - fitandscore = network.create_node('worc/fitandscore:1.0', tool_version='1.0', id='fitandscore', resources=ResourceLimit(memory='2G')) - fitandscore.inputs['estimatordata'].input_group = 'estimator' - fitandscore.inputs['traintest'].input_group = 'traintest' - fitandscore.inputs['parameters'].input_group = 'parameters' - - fitandscore.inputs['estimatordata'] = estimator_data.output - fitandscore.inputs['traintest'] = traintest_data.output - fitandscore.inputs['parameters'] = parameter_data.output - sink_output.input = fitandscore.outputs['fittedestimator'] - - source_data = {'estimator_source': estimatordata, - 'traintest': traintest_files, - 'parameters': parameter_files} - sink_data = {'output': ("vfs://tmp/{}/{}/output_{{sample_id}}_{{cardinality}}{{ext}}").format('GS', name)} - - network.execute(source_data, sink_data, - tmpdir=os.path.join(tempfolder, 'tmp'), - execution_plugin=self.fastr_plugin) - - # Read in the output data once finished - # TODO: expanding fastr url is probably a nicer way - sink_files = glob.glob(os.path.join(fastr.config.mounts['tmp'], 'GS', name) + '/output*.hdf5') - save_data = list() - for output in sink_files: - data = pd.read_hdf(output) - save_data.extend(list(data['RET'])) - - # if one choose to see train score, "out" will contain train score info - try: - if self.return_train_score: - (train_scores, test_scores, test_sample_counts, - fit_time, score_time, parameters_est, parameters_all) =\ - zip(*save_data) - else: - (test_scores, test_sample_counts, - fit_time, score_time, parameters_est, parameters_all) =\ - zip(*save_data) - except ValueError as e: - print(e) - message = ('Fitting classifiers has failed. The temporary ' + - 'results where not deleted and can be found in {}. ' + - 'Probably your fitting and scoring failed: check out ' + - 'the tmp/fitandscore folder within the tempfolder for ' + - 'the fastr job temporary results.').format(tempfolder) - raise PREDICTexceptions.PREDICTValueError(message) - - # Remove the temporary folder used - shutil.rmtree(tempfolder) - - # Process the results of the fitting procedure - self.process_fit(n_splits=n_splits, - parameters_est=parameters_est, - parameters_all=parameters_all, - test_sample_counts=test_sample_counts, - test_scores=test_scores, - train_scores=train_scores, - fit_time=fit_time, - score_time=score_time, - cv_iter=cv_iter, - X=X, y=y) - - -class RandomizedSearchCVfastr(BaseSearchCVfastr): - """Randomized search on hyper parameters. - - RandomizedSearchCV implements a "fit" and a "score" method. - It also implements "predict", "predict_proba", "decision_function", - "transform" and "inverse_transform" if they are implemented in the - estimator used. - - The parameters of the estimator used to apply these methods are optimized - by cross-validated search over parameter settings. - - In contrast to GridSearchCV, not all parameter values are tried out, but - rather a fixed number of parameter settings is sampled from the specified - distributions. The number of parameter settings that are tried is - given by n_iter. - - If all parameters are presented as a list, - sampling without replacement is performed. If at least one parameter - is given as a distribution, sampling with replacement is used. - It is highly recommended to use continuous distributions for continuous - parameters. - - Read more in the :ref:`User Guide `. - - Parameters - ---------- - estimator : estimator object. - A object of that type is instantiated for each grid point. - This is assumed to implement the scikit-learn estimator interface. - Either estimator needs to provide a ``score`` function, - or ``scoring`` must be passed. - - param_distributions : dict - Dictionary with parameters names (string) as keys and distributions - or lists of parameters to try. Distributions must provide a ``rvs`` - method for sampling (such as those from scipy.stats.distributions). - If a list is given, it is sampled uniformly. - - n_iter : int, default=10 - Number of parameter settings that are sampled. n_iter trades - off runtime vs quality of the solution. - - scoring : string, callable or None, default=None - A string (see model evaluation documentation) or - a scorer callable object / function with signature - ``scorer(estimator, X, y)``. - If ``None``, the ``score`` method of the estimator is used. - - fit_params : dict, optional - Parameters to pass to the fit method. - - n_jobs : int, default=1 - Number of jobs to run in parallel. - - pre_dispatch : int, or string, optional - Controls the number of jobs that get dispatched during parallel - execution. Reducing this number can be useful to avoid an - explosion of memory consumption when more jobs get dispatched - than CPUs can process. This parameter can be: - - - None, in which case all the jobs are immediately - created and spawned. Use this for lightweight and - fast-running jobs, to avoid delays due to on-demand - spawning of the jobs - - - An int, giving the exact number of total jobs that are - spawned - - - A string, giving an expression as a function of n_jobs, - as in '2*n_jobs' - - iid : boolean, default=True - If True, the data is assumed to be identically distributed across - the folds, and the loss minimized is the total loss per sample, - and not the mean loss across the folds. - - cv : int, cross-validation generator or an iterable, optional - Determines the cross-validation splitting strategy. - Possible inputs for cv are: - - None, to use the default 3-fold cross validation, - - integer, to specify the number of folds in a `(Stratified)KFold`, - - An object to be used as a cross-validation generator. - - An iterable yielding train, test splits. - - For integer/None inputs, if the estimator is a classifier and ``y`` is - either binary or multiclass, :class:`StratifiedKFold` is used. In all - other cases, :class:`KFold` is used. - - Refer :ref:`User Guide ` for the various - cross-validation strategies that can be used here. - - refit : boolean, default=True - Refit the best estimator with the entire dataset. - If "False", it is impossible to make predictions using - this RandomizedSearchCV instance after fitting. - - verbose : integer - Controls the verbosity: the higher, the more messages. - - random_state : int or RandomState - Pseudo random number generator state used for random uniform sampling - from lists of possible values instead of scipy.stats distributions. - - error_score : 'raise' (default) or numeric - Value to assign to the score if an error occurs in estimator fitting. - If set to 'raise', the error is raised. If a numeric value is given, - FitFailedWarning is raised. This parameter does not affect the refit - step, which will always raise the error. - - return_train_score : boolean, default=True - If ``'False'``, the ``cv_results_`` attribute will not include training - scores. - - Attributes - ---------- - cv_results_ : dict of numpy (masked) ndarrays - A dict with keys as column headers and values as columns, that can be - imported into a pandas ``DataFrame``. - - For instance the below given table - - +--------------+-------------+-------------------+---+---------------+ - | param_kernel | param_gamma | split0_test_score |...|rank_test_score| - +==============+=============+===================+===+===============+ - | 'rbf' | 0.1 | 0.8 |...| 2 | - +--------------+-------------+-------------------+---+---------------+ - | 'rbf' | 0.2 | 0.9 |...| 1 | - +--------------+-------------+-------------------+---+---------------+ - | 'rbf' | 0.3 | 0.7 |...| 1 | - +--------------+-------------+-------------------+---+---------------+ - - will be represented by a ``cv_results_`` dict of:: - - { - 'param_kernel' : masked_array(data = ['rbf', 'rbf', 'rbf'], - mask = False), - 'param_gamma' : masked_array(data = [0.1 0.2 0.3], mask = False), - 'split0_test_score' : [0.8, 0.9, 0.7], - 'split1_test_score' : [0.82, 0.5, 0.7], - 'mean_test_score' : [0.81, 0.7, 0.7], - 'std_test_score' : [0.02, 0.2, 0.], - 'rank_test_score' : [3, 1, 1], - 'split0_train_score' : [0.8, 0.9, 0.7], - 'split1_train_score' : [0.82, 0.5, 0.7], - 'mean_train_score' : [0.81, 0.7, 0.7], - 'std_train_score' : [0.03, 0.03, 0.04], - 'mean_fit_time' : [0.73, 0.63, 0.43, 0.49], - 'std_fit_time' : [0.01, 0.02, 0.01, 0.01], - 'mean_score_time' : [0.007, 0.06, 0.04, 0.04], - 'std_score_time' : [0.001, 0.002, 0.003, 0.005], - 'params' : [{'kernel' : 'rbf', 'gamma' : 0.1}, ...], - } - - NOTE that the key ``'params'`` is used to store a list of parameter - settings dict for all the parameter candidates. - - The ``mean_fit_time``, ``std_fit_time``, ``mean_score_time`` and - ``std_score_time`` are all in seconds. - - best_estimator_ : estimator - Estimator that was chosen by the search, i.e. estimator - which gave highest score (or smallest loss if specified) - on the left out data. Not available if refit=False. - - best_score_ : float - Score of best_estimator on the left out data. - - best_params_ : dict - Parameter setting that gave the best results on the hold out data. - - best_index_ : int - The index (of the ``cv_results_`` arrays) which corresponds to the best - candidate parameter setting. - - The dict at ``search.cv_results_['params'][search.best_index_]`` gives - the parameter setting for the best model, that gives the highest - mean score (``search.best_score_``). - - scorer_ : function - Scorer function used on the held out data to choose the best - parameters for the model. - - n_splits_ : int - The number of cross-validation splits (folds/iterations). - - Notes - ----- - The parameters selected are those that maximize the score of the held-out - data, according to the scoring parameter. - - If `n_jobs` was set to a value higher than one, the data is copied for each - parameter setting(and not `n_jobs` times). This is done for efficiency - reasons if individual jobs take very little time, but may raise errors if - the dataset is large and not enough memory is available. A workaround in - this case is to set `pre_dispatch`. Then, the memory is copied only - `pre_dispatch` many times. A reasonable value for `pre_dispatch` is `2 * - n_jobs`. - - See Also - -------- - :class:`GridSearchCV`: - Does exhaustive search over a grid of parameters. - - :class:`ParameterSampler`: - A generator over parameter settings, constructed from - param_distributions. - - """ - - def __init__(self, param_distributions={}, n_iter=10, scoring=None, - fit_params=None, n_jobs=1, iid=True, refit=True, cv=None, - verbose=0, pre_dispatch='2*n_jobs', random_state=None, - error_score='raise', return_train_score=True, - n_jobspercore=100, fastr_plugin=None): - super(RandomizedSearchCVfastr, self).__init__( - param_distributions=param_distributions, scoring=scoring, fit_params=fit_params, - n_iter=n_iter, random_state=random_state, n_jobs=n_jobs, iid=iid, refit=refit, cv=cv, verbose=verbose, - pre_dispatch=pre_dispatch, error_score=error_score, - return_train_score=return_train_score, - n_jobspercore=n_jobspercore, fastr_plugin=None) - - def fit(self, X, y=None, groups=None): - """Run fit on the estimator with randomly drawn parameters. - - Parameters - ---------- - X : array-like, shape = [n_samples, n_features] - Training vector, where n_samples in the number of samples and - n_features is the number of features. - - y : array-like, shape = [n_samples] or [n_samples, n_output], optional - Target relative to X for classification or regression; - None for unsupervised learning. - - groups : array-like, with shape (n_samples,), optional - Group labels for the samples used while splitting the dataset into - train/test set. - """ - print("Fit: " + str(self.n_iter)) - sampled_params = ParameterSampler(self.param_distributions, - self.n_iter, - random_state=self.random_state) - return self._fit(X, y, groups, sampled_params) - - -class BaseSearchCVJoblib(BaseSearchCV): - """Base class for hyper parameter search with cross-validation.""" - - def _fit(self, X, y, groups, parameter_iterable): - """Actual fitting, performing the search over parameters.""" - - regressors = ['SVR', 'RFR', 'SGDR', 'Lasso', 'ElasticNet'] - isclassifier =\ - not any(clf in regressors for clf in self.param_distributions['classifiers']) - - cv = check_cv(self.cv, y, classifier=isclassifier) - - X, y, groups = indexable(X, y, groups) - n_splits = cv.get_n_splits(X, y, groups) - if self.verbose > 0 and isinstance(parameter_iterable, Sized): - n_candidates = len(parameter_iterable) - print("Fitting {0} folds for each of {1} candidates, totalling" - " {2} fits".format(n_splits, n_candidates, - n_candidates * n_splits)) - - pre_dispatch = self.pre_dispatch - cv_iter = list(cv.split(X, y, groups)) - - out = Parallel( - n_jobs=self.n_jobs, verbose=self.verbose, - pre_dispatch=pre_dispatch - )(delayed(fit_and_score)(X, y, self.scoring, - train, test, parameters, - fit_params=self.fit_params, - return_train_score=self.return_train_score, - return_n_test_samples=True, - return_times=True, return_parameters=True, - error_score=self.error_score, - verbose=self.verbose, - return_all=False) - for parameters in parameter_iterable - for train, test in cv_iter) - save_data = zip(*out) - - # if one choose to see train score, "out" will contain train score info - if self.return_train_score: - (train_scores, test_scores, test_sample_counts, - fit_time, score_time, parameters_est, parameters_all) =\ - save_data - else: - (test_scores, test_sample_counts, - fit_time, score_time, parameters_est, parameters_all) =\ - save_data - - self.process_fit(n_splits=n_splits, - parameters_est=parameters_est, - parameters_all=parameters_all, - test_sample_counts=test_sample_counts, - test_scores=test_scores, - train_scores=train_scores, - fit_time=fit_time, - score_time=score_time, - cv_iter=cv_iter, - X=X, y=y) - - return self - - -class GridSearchCVfastr(BaseSearchCVfastr): - """Exhaustive search over specified parameter values for an estimator. - - Important members are fit, predict. - - GridSearchCV implements a "fit" and a "score" method. - It also implements "predict", "predict_proba", "decision_function", - "transform" and "inverse_transform" if they are implemented in the - estimator used. - - The parameters of the estimator used to apply these methods are optimized - by cross-validated grid-search over a parameter grid. - - Read more in the :ref:`User Guide `. - - Parameters - ---------- - estimator : estimator object. - This is assumed to implement the scikit-learn estimator interface. - Either estimator needs to provide a ``score`` function, - or ``scoring`` must be passed. - - param_grid : dict or list of dictionaries - Dictionary with parameters names (string) as keys and lists of - parameter settings to try as values, or a list of such - dictionaries, in which case the grids spanned by each dictionary - in the list are explored. This enables searching over any sequence - of parameter settings. - - scoring : string, callable or None, default=None - A string (see model evaluation documentation) or - a scorer callable object / function with signature - ``scorer(estimator, X, y)``. - If ``None``, the ``score`` method of the estimator is used. - - fit_params : dict, optional - Parameters to pass to the fit method. - - n_jobs : int, default=1 - Number of jobs to run in parallel. - - pre_dispatch : int, or string, optional - Controls the number of jobs that get dispatched during parallel - execution. Reducing this number can be useful to avoid an - explosion of memory consumption when more jobs get dispatched - than CPUs can process. This parameter can be: - - - None, in which case all the jobs are immediately - created and spawned. Use this for lightweight and - fast-running jobs, to avoid delays due to on-demand - spawning of the jobs - - - An int, giving the exact number of total jobs that are - spawned - - - A string, giving an expression as a function of n_jobs, - as in '2*n_jobs' - - iid : boolean, default=True - If True, the data is assumed to be identically distributed across - the folds, and the loss minimized is the total loss per sample, - and not the mean loss across the folds. - - cv : int, cross-validation generator or an iterable, optional - Determines the cross-validation splitting strategy. - Possible inputs for cv are: - - None, to use the default 3-fold cross validation, - - integer, to specify the number of folds in a `(Stratified)KFold`, - - An object to be used as a cross-validation generator. - - An iterable yielding train, test splits. - - For integer/None inputs, if the estimator is a classifier and ``y`` is - either binary or multiclass, :class:`StratifiedKFold` is used. In all - other cases, :class:`KFold` is used. - - Refer :ref:`User Guide ` for the various - cross-validation strategies that can be used here. - - refit : boolean, default=True - Refit the best estimator with the entire dataset. - If "False", it is impossible to make predictions using - this GridSearchCV instance after fitting. - - verbose : integer - Controls the verbosity: the higher, the more messages. - - error_score : 'raise' (default) or numeric - Value to assign to the score if an error occurs in estimator fitting. - If set to 'raise', the error is raised. If a numeric value is given, - FitFailedWarning is raised. This parameter does not affect the refit - step, which will always raise the error. - - return_train_score : boolean, default=True - If ``'False'``, the ``cv_results_`` attribute will not include training - scores. - - - Examples - -------- - >>> from sklearn import svm, datasets - >>> from sklearn.model_selection import GridSearchCV - >>> iris = datasets.load_iris() - >>> parameters = {'kernel':('linear', 'rbf'), 'C':[1, 10]} - >>> svr = svm.SVC() - >>> clf = GridSearchCV(svr, parameters) - >>> clf.fit(iris.data, iris.target) - ... # doctest: +NORMALIZE_WHITESPACE +ELLIPSIS - GridSearchCV(cv=None, error_score=..., - estimator=SVC(C=1.0, cache_size=..., class_weight=..., coef0=..., - decision_function_shape=None, degree=..., gamma=..., - kernel='rbf', max_iter=-1, probability=False, - random_state=None, shrinking=True, tol=..., - verbose=False), - fit_params={}, iid=..., n_jobs=1, - param_grid=..., pre_dispatch=..., refit=..., return_train_score=..., - scoring=..., verbose=...) - >>> sorted(clf.cv_results_.keys()) - ... # doctest: +NORMALIZE_WHITESPACE +ELLIPSIS - ['mean_fit_time', 'mean_score_time', 'mean_test_score',... - 'mean_train_score', 'param_C', 'param_kernel', 'params',... - 'rank_test_score', 'split0_test_score',... - 'split0_train_score', 'split1_test_score', 'split1_train_score',... - 'split2_test_score', 'split2_train_score',... - 'std_fit_time', 'std_score_time', 'std_test_score', 'std_train_score'...] - - Attributes - ---------- - cv_results_ : dict of numpy (masked) ndarrays - A dict with keys as column headers and values as columns, that can be - imported into a pandas ``DataFrame``. - - For instance the below given table - - +------------+-----------+------------+-----------------+---+---------+ - |param_kernel|param_gamma|param_degree|split0_test_score|...|rank_....| - +============+===========+============+=================+===+=========+ - | 'poly' | -- | 2 | 0.8 |...| 2 | - +------------+-----------+------------+-----------------+---+---------+ - | 'poly' | -- | 3 | 0.7 |...| 4 | - +------------+-----------+------------+-----------------+---+---------+ - | 'rbf' | 0.1 | -- | 0.8 |...| 3 | - +------------+-----------+------------+-----------------+---+---------+ - | 'rbf' | 0.2 | -- | 0.9 |...| 1 | - +------------+-----------+------------+-----------------+---+---------+ - - will be represented by a ``cv_results_`` dict of:: - - { - 'param_kernel': masked_array(data = ['poly', 'poly', 'rbf', 'rbf'], - mask = [False False False False]...) - 'param_gamma': masked_array(data = [-- -- 0.1 0.2], - mask = [ True True False False]...), - 'param_degree': masked_array(data = [2.0 3.0 -- --], - mask = [False False True True]...), - 'split0_test_score' : [0.8, 0.7, 0.8, 0.9], - 'split1_test_score' : [0.82, 0.5, 0.7, 0.78], - 'mean_test_score' : [0.81, 0.60, 0.75, 0.82], - 'std_test_score' : [0.02, 0.01, 0.03, 0.03], - 'rank_test_score' : [2, 4, 3, 1], - 'split0_train_score' : [0.8, 0.9, 0.7], - 'split1_train_score' : [0.82, 0.5, 0.7], - 'mean_train_score' : [0.81, 0.7, 0.7], - 'std_train_score' : [0.03, 0.03, 0.04], - 'mean_fit_time' : [0.73, 0.63, 0.43, 0.49], - 'std_fit_time' : [0.01, 0.02, 0.01, 0.01], - 'mean_score_time' : [0.007, 0.06, 0.04, 0.04], - 'std_score_time' : [0.001, 0.002, 0.003, 0.005], - 'params' : [{'kernel': 'poly', 'degree': 2}, ...], - } - - NOTE that the key ``'params'`` is used to store a list of parameter - settings dict for all the parameter candidates. - - The ``mean_fit_time``, ``std_fit_time``, ``mean_score_time`` and - ``std_score_time`` are all in seconds. - - best_estimator_ : estimator - Estimator that was chosen by the search, i.e. estimator - which gave highest score (or smallest loss if specified) - on the left out data. Not available if refit=False. - - best_score_ : float - Score of best_estimator on the left out data. - - best_params_ : dict - Parameter setting that gave the best results on the hold out data. - - best_index_ : int - The index (of the ``cv_results_`` arrays) which corresponds to the best - candidate parameter setting. - - The dict at ``search.cv_results_['params'][search.best_index_]`` gives - the parameter setting for the best model, that gives the highest - mean score (``search.best_score_``). - - scorer_ : function - Scorer function used on the held out data to choose the best - parameters for the model. - - n_splits_ : int - The number of cross-validation splits (folds/iterations). - - Notes - ------ - The parameters selected are those that maximize the score of the left out - data, unless an explicit score is passed in which case it is used instead. - - If `n_jobs` was set to a value higher than one, the data is copied for each - point in the grid (and not `n_jobs` times). This is done for efficiency - reasons if individual jobs take very little time, but may raise errors if - the dataset is large and not enough memory is available. A workaround in - this case is to set `pre_dispatch`. Then, the memory is copied only - `pre_dispatch` many times. A reasonable value for `pre_dispatch` is `2 * - n_jobs`. - - See Also - --------- - :class:`ParameterGrid`: - generates all the combinations of a hyperparameter grid. - - :func:`sklearn.model_selection.train_test_split`: - utility function to split the data into a development set usable - for fitting a GridSearchCV instance and an evaluation set for - its final evaluation. - - :func:`sklearn.metrics.make_scorer`: - Make a scorer from a performance metric or loss function. - - """ - - def __init__(self, estimator, param_grid, scoring=None, fit_params=None, - n_jobs=1, iid=True, refit=True, cv=None, verbose=0, - pre_dispatch='2*n_jobs', error_score='raise', - return_train_score=True): - super(GridSearchCVfastr, self).__init__( - scoring=scoring, fit_params=fit_params, - n_jobs=n_jobs, iid=iid, refit=refit, cv=cv, verbose=verbose, - pre_dispatch=pre_dispatch, error_score=error_score, - return_train_score=return_train_score, fastr_plugin=None) - self.param_grid = param_grid - _check_param_grid(param_grid) - - def fit(self, X, y=None, groups=None): - """Run fit with all sets of parameters. - - Parameters - ---------- - - X : array-like, shape = [n_samples, n_features] - Training vector, where n_samples is the number of samples and - n_features is the number of features. - - y : array-like, shape = [n_samples] or [n_samples, n_output], optional - Target relative to X for classification or regression; - None for unsupervised learning. - - groups : array-like, with shape (n_samples,), optional - Group labels for the samples used while splitting the dataset into - train/test set. - """ - return self._fit(X, y, groups, ParameterGrid(self.param_grid)) - - -class RandomizedSearchCVJoblib(BaseSearchCVJoblib): - """Randomized search on hyper parameters. - - RandomizedSearchCV implements a "fit" and a "score" method. - It also implements "predict", "predict_proba", "decision_function", - "transform" and "inverse_transform" if they are implemented in the - estimator used. - - The parameters of the estimator used to apply these methods are optimized - by cross-validated search over parameter settings. - - In contrast to GridSearchCV, not all parameter values are tried out, but - rather a fixed number of parameter settings is sampled from the specified - distributions. The number of parameter settings that are tried is - given by n_iter. - - If all parameters are presented as a list, - sampling without replacement is performed. If at least one parameter - is given as a distribution, sampling with replacement is used. - It is highly recommended to use continuous distributions for continuous - parameters. - - Read more in the :ref:`User Guide `. - - Parameters - ---------- - estimator : estimator object. - A object of that type is instantiated for each grid point. - This is assumed to implement the scikit-learn estimator interface. - Either estimator needs to provide a ``score`` function, - or ``scoring`` must be passed. - - param_distributions : dict - Dictionary with parameters names (string) as keys and distributions - or lists of parameters to try. Distributions must provide a ``rvs`` - method for sampling (such as those from scipy.stats.distributions). - If a list is given, it is sampled uniformly. - - n_iter : int, default=10 - Number of parameter settings that are sampled. n_iter trades - off runtime vs quality of the solution. - - scoring : string, callable or None, default=None - A string (see model evaluation documentation) or - a scorer callable object / function with signature - ``scorer(estimator, X, y)``. - If ``None``, the ``score`` method of the estimator is used. - - fit_params : dict, optional - Parameters to pass to the fit method. - - n_jobs : int, default=1 - Number of jobs to run in parallel. - - pre_dispatch : int, or string, optional - Controls the number of jobs that get dispatched during parallel - execution. Reducing this number can be useful to avoid an - explosion of memory consumption when more jobs get dispatched - than CPUs can process. This parameter can be: - - - None, in which case all the jobs are immediately - created and spawned. Use this for lightweight and - fast-running jobs, to avoid delays due to on-demand - spawning of the jobs - - - An int, giving the exact number of total jobs that are - spawned - - - A string, giving an expression as a function of n_jobs, - as in '2*n_jobs' - - iid : boolean, default=True - If True, the data is assumed to be identically distributed across - the folds, and the loss minimized is the total loss per sample, - and not the mean loss across the folds. - - cv : int, cross-validation generator or an iterable, optional - Determines the cross-validation splitting strategy. - Possible inputs for cv are: - - None, to use the default 3-fold cross validation, - - integer, to specify the number of folds in a `(Stratified)KFold`, - - An object to be used as a cross-validation generator. - - An iterable yielding train, test splits. - - For integer/None inputs, if the estimator is a classifier and ``y`` is - either binary or multiclass, :class:`StratifiedKFold` is used. In all - other cases, :class:`KFold` is used. - - Refer :ref:`User Guide ` for the various - cross-validation strategies that can be used here. - - refit : boolean, default=True - Refit the best estimator with the entire dataset. - If "False", it is impossible to make predictions using - this RandomizedSearchCV instance after fitting. - - verbose : integer - Controls the verbosity: the higher, the more messages. - - random_state : int or RandomState - Pseudo random number generator state used for random uniform sampling - from lists of possible values instead of scipy.stats distributions. - - error_score : 'raise' (default) or numeric - Value to assign to the score if an error occurs in estimator fitting. - If set to 'raise', the error is raised. If a numeric value is given, - FitFailedWarning is raised. This parameter does not affect the refit - step, which will always raise the error. - - return_train_score : boolean, default=True - If ``'False'``, the ``cv_results_`` attribute will not include training - scores. - - Attributes - ---------- - cv_results_ : dict of numpy (masked) ndarrays - A dict with keys as column headers and values as columns, that can be - imported into a pandas ``DataFrame``. - - For instance the below given table - - +--------------+-------------+-------------------+---+---------------+ - | param_kernel | param_gamma | split0_test_score |...|rank_test_score| - +==============+=============+===================+===+===============+ - | 'rbf' | 0.1 | 0.8 |...| 2 | - +--------------+-------------+-------------------+---+---------------+ - | 'rbf' | 0.2 | 0.9 |...| 1 | - +--------------+-------------+-------------------+---+---------------+ - | 'rbf' | 0.3 | 0.7 |...| 1 | - +--------------+-------------+-------------------+---+---------------+ - - will be represented by a ``cv_results_`` dict of:: - - { - 'param_kernel' : masked_array(data = ['rbf', 'rbf', 'rbf'], - mask = False), - 'param_gamma' : masked_array(data = [0.1 0.2 0.3], mask = False), - 'split0_test_score' : [0.8, 0.9, 0.7], - 'split1_test_score' : [0.82, 0.5, 0.7], - 'mean_test_score' : [0.81, 0.7, 0.7], - 'std_test_score' : [0.02, 0.2, 0.], - 'rank_test_score' : [3, 1, 1], - 'split0_train_score' : [0.8, 0.9, 0.7], - 'split1_train_score' : [0.82, 0.5, 0.7], - 'mean_train_score' : [0.81, 0.7, 0.7], - 'std_train_score' : [0.03, 0.03, 0.04], - 'mean_fit_time' : [0.73, 0.63, 0.43, 0.49], - 'std_fit_time' : [0.01, 0.02, 0.01, 0.01], - 'mean_score_time' : [0.007, 0.06, 0.04, 0.04], - 'std_score_time' : [0.001, 0.002, 0.003, 0.005], - 'params' : [{'kernel' : 'rbf', 'gamma' : 0.1}, ...], - } - - NOTE that the key ``'params'`` is used to store a list of parameter - settings dict for all the parameter candidates. - - The ``mean_fit_time``, ``std_fit_time``, ``mean_score_time`` and - ``std_score_time`` are all in seconds. - - best_estimator_ : estimator - Estimator that was chosen by the search, i.e. estimator - which gave highest score (or smallest loss if specified) - on the left out data. Not available if refit=False. - - best_score_ : float - Score of best_estimator on the left out data. - - best_params_ : dict - Parameter setting that gave the best results on the hold out data. - - best_index_ : int - The index (of the ``cv_results_`` arrays) which corresponds to the best - candidate parameter setting. - - The dict at ``search.cv_results_['params'][search.best_index_]`` gives - the parameter setting for the best model, that gives the highest - mean score (``search.best_score_``). - - scorer_ : function - Scorer function used on the held out data to choose the best - parameters for the model. - - n_splits_ : int - The number of cross-validation splits (folds/iterations). - - Notes - ----- - The parameters selected are those that maximize the score of the held-out - data, according to the scoring parameter. - - If `n_jobs` was set to a value higher than one, the data is copied for each - parameter setting(and not `n_jobs` times). This is done for efficiency - reasons if individual jobs take very little time, but may raise errors if - the dataset is large and not enough memory is available. A workaround in - this case is to set `pre_dispatch`. Then, the memory is copied only - `pre_dispatch` many times. A reasonable value for `pre_dispatch` is `2 * - n_jobs`. - - See Also - -------- - :class:`GridSearchCV`: - Does exhaustive search over a grid of parameters. - - :class:`ParameterSampler`: - A generator over parameter settins, constructed from - param_distributions. - - """ - - def __init__(self, param_distributions={}, n_iter=10, scoring=None, - fit_params=None, n_jobs=1, iid=True, refit=True, cv=None, - verbose=0, pre_dispatch='2*n_jobs', random_state=None, - error_score='raise', return_train_score=True, - n_jobspercore=100): - super(RandomizedSearchCVJoblib, self).__init__( - param_distributions=param_distributions, - n_iter=n_iter, scoring=scoring, fit_params=fit_params, - n_jobs=n_jobs, iid=iid, refit=refit, cv=cv, verbose=verbose, - pre_dispatch=pre_dispatch, error_score=error_score, - return_train_score=return_train_score, - n_jobspercore=n_jobspercore, random_state=random_state) - - def fit(self, X, y=None, groups=None): - """Run fit on the estimator with randomly drawn parameters. - - Parameters - ---------- - X : array-like, shape = [n_samples, n_features] - Training vector, where n_samples in the number of samples and - n_features is the number of features. - - y : array-like, shape = [n_samples] or [n_samples, n_output], optional - Target relative to X for classification or regression; - None for unsupervised learning. - - groups : array-like, with shape (n_samples,), optional - Group labels for the samples used while splitting the dataset into - train/test set. - """ - sampled_params = ParameterSampler(self.param_distributions, - self.n_iter, - random_state=self.random_state) - return self._fit(X, y, groups, sampled_params) - - -class GridSearchCVJoblib(BaseSearchCVJoblib): - """Exhaustive search over specified parameter values for an estimator. - - Important members are fit, predict. - - GridSearchCV implements a "fit" and a "score" method. - It also implements "predict", "predict_proba", "decision_function", - "transform" and "inverse_transform" if they are implemented in the - estimator used. - - The parameters of the estimator used to apply these methods are optimized - by cross-validated grid-search over a parameter grid. - - Read more in the :ref:`User Guide `. - - Parameters - ---------- - estimator : estimator object. - This is assumed to implement the scikit-learn estimator interface. - Either estimator needs to provide a ``score`` function, - or ``scoring`` must be passed. - - param_grid : dict or list of dictionaries - Dictionary with parameters names (string) as keys and lists of - parameter settings to try as values, or a list of such - dictionaries, in which case the grids spanned by each dictionary - in the list are explored. This enables searching over any sequence - of parameter settings. - - scoring : string, callable or None, default=None - A string (see model evaluation documentation) or - a scorer callable object / function with signature - ``scorer(estimator, X, y)``. - If ``None``, the ``score`` method of the estimator is used. - - fit_params : dict, optional - Parameters to pass to the fit method. - - n_jobs : int, default=1 - Number of jobs to run in parallel. - - pre_dispatch : int, or string, optional - Controls the number of jobs that get dispatched during parallel - execution. Reducing this number can be useful to avoid an - explosion of memory consumption when more jobs get dispatched - than CPUs can process. This parameter can be: - - - None, in which case all the jobs are immediately - created and spawned. Use this for lightweight and - fast-running jobs, to avoid delays due to on-demand - spawning of the jobs - - - An int, giving the exact number of total jobs that are - spawned - - - A string, giving an expression as a function of n_jobs, - as in '2*n_jobs' - - iid : boolean, default=True - If True, the data is assumed to be identically distributed across - the folds, and the loss minimized is the total loss per sample, - and not the mean loss across the folds. - - cv : int, cross-validation generator or an iterable, optional - Determines the cross-validation splitting strategy. - Possible inputs for cv are: - - None, to use the default 3-fold cross validation, - - integer, to specify the number of folds in a `(Stratified)KFold`, - - An object to be used as a cross-validation generator. - - An iterable yielding train, test splits. - - For integer/None inputs, if the estimator is a classifier and ``y`` is - either binary or multiclass, :class:`StratifiedKFold` is used. In all - other cases, :class:`KFold` is used. - - Refer :ref:`User Guide ` for the various - cross-validation strategies that can be used here. - - refit : boolean, default=True - Refit the best estimator with the entire dataset. - If "False", it is impossible to make predictions using - this GridSearchCV instance after fitting. - - verbose : integer - Controls the verbosity: the higher, the more messages. - - error_score : 'raise' (default) or numeric - Value to assign to the score if an error occurs in estimator fitting. - If set to 'raise', the error is raised. If a numeric value is given, - FitFailedWarning is raised. This parameter does not affect the refit - step, which will always raise the error. - - return_train_score : boolean, default=True - If ``'False'``, the ``cv_results_`` attribute will not include training - scores. - - - Examples - -------- - >>> from sklearn import svm, datasets - >>> from sklearn.model_selection import GridSearchCV - >>> iris = datasets.load_iris() - >>> parameters = {'kernel':('linear', 'rbf'), 'C':[1, 10]} - >>> svr = svm.SVC() - >>> clf = GridSearchCV(svr, parameters) - >>> clf.fit(iris.data, iris.target) - ... # doctest: +NORMALIZE_WHITESPACE +ELLIPSIS - GridSearchCV(cv=None, error_score=..., - estimator=SVC(C=1.0, cache_size=..., class_weight=..., coef0=..., - decision_function_shape=None, degree=..., gamma=..., - kernel='rbf', max_iter=-1, probability=False, - random_state=None, shrinking=True, tol=..., - verbose=False), - fit_params={}, iid=..., n_jobs=1, - param_grid=..., pre_dispatch=..., refit=..., return_train_score=..., - scoring=..., verbose=...) - >>> sorted(clf.cv_results_.keys()) - ... # doctest: +NORMALIZE_WHITESPACE +ELLIPSIS - ['mean_fit_time', 'mean_score_time', 'mean_test_score',... - 'mean_train_score', 'param_C', 'param_kernel', 'params',... - 'rank_test_score', 'split0_test_score',... - 'split0_train_score', 'split1_test_score', 'split1_train_score',... - 'split2_test_score', 'split2_train_score',... - 'std_fit_time', 'std_score_time', 'std_test_score', 'std_train_score'...] - - Attributes - ---------- - cv_results_ : dict of numpy (masked) ndarrays - A dict with keys as column headers and values as columns, that can be - imported into a pandas ``DataFrame``. - - For instance the below given table - - +------------+-----------+------------+-----------------+---+---------+ - |param_kernel|param_gamma|param_degree|split0_test_score|...|rank_....| - +============+===========+============+=================+===+=========+ - | 'poly' | -- | 2 | 0.8 |...| 2 | - +------------+-----------+------------+-----------------+---+---------+ - | 'poly' | -- | 3 | 0.7 |...| 4 | - +------------+-----------+------------+-----------------+---+---------+ - | 'rbf' | 0.1 | -- | 0.8 |...| 3 | - +------------+-----------+------------+-----------------+---+---------+ - | 'rbf' | 0.2 | -- | 0.9 |...| 1 | - +------------+-----------+------------+-----------------+---+---------+ - - will be represented by a ``cv_results_`` dict of:: - - { - 'param_kernel': masked_array(data = ['poly', 'poly', 'rbf', 'rbf'], - mask = [False False False False]...) - 'param_gamma': masked_array(data = [-- -- 0.1 0.2], - mask = [ True True False False]...), - 'param_degree': masked_array(data = [2.0 3.0 -- --], - mask = [False False True True]...), - 'split0_test_score' : [0.8, 0.7, 0.8, 0.9], - 'split1_test_score' : [0.82, 0.5, 0.7, 0.78], - 'mean_test_score' : [0.81, 0.60, 0.75, 0.82], - 'std_test_score' : [0.02, 0.01, 0.03, 0.03], - 'rank_test_score' : [2, 4, 3, 1], - 'split0_train_score' : [0.8, 0.9, 0.7], - 'split1_train_score' : [0.82, 0.5, 0.7], - 'mean_train_score' : [0.81, 0.7, 0.7], - 'std_train_score' : [0.03, 0.03, 0.04], - 'mean_fit_time' : [0.73, 0.63, 0.43, 0.49], - 'std_fit_time' : [0.01, 0.02, 0.01, 0.01], - 'mean_score_time' : [0.007, 0.06, 0.04, 0.04], - 'std_score_time' : [0.001, 0.002, 0.003, 0.005], - 'params' : [{'kernel': 'poly', 'degree': 2}, ...], - } - - NOTE that the key ``'params'`` is used to store a list of parameter - settings dict for all the parameter candidates. - - The ``mean_fit_time``, ``std_fit_time``, ``mean_score_time`` and - ``std_score_time`` are all in seconds. - - best_estimator_ : estimator - Estimator that was chosen by the search, i.e. estimator - which gave highest score (or smallest loss if specified) - on the left out data. Not available if refit=False. - - best_score_ : float - Score of best_estimator on the left out data. - - best_params_ : dict - Parameter setting that gave the best results on the hold out data. - - best_index_ : int - The index (of the ``cv_results_`` arrays) which corresponds to the best - candidate parameter setting. - - The dict at ``search.cv_results_['params'][search.best_index_]`` gives - the parameter setting for the best model, that gives the highest - mean score (``search.best_score_``). - - scorer_ : function - Scorer function used on the held out data to choose the best - parameters for the model. - - n_splits_ : int - The number of cross-validation splits (folds/iterations). - - Notes - ------ - The parameters selected are those that maximize the score of the left out - data, unless an explicit score is passed in which case it is used instead. - - If `n_jobs` was set to a value higher than one, the data is copied for each - point in the grid (and not `n_jobs` times). This is done for efficiency - reasons if individual jobs take very little time, but may raise errors if - the dataset is large and not enough memory is available. A workaround in - this case is to set `pre_dispatch`. Then, the memory is copied only - `pre_dispatch` many times. A reasonable value for `pre_dispatch` is `2 * - n_jobs`. - - See Also - --------- - :class:`ParameterGrid`: - generates all the combinations of a hyperparameter grid. - - :func:`sklearn.model_selection.train_test_split`: - utility function to split the data into a development set usable - for fitting a GridSearchCV instance and an evaluation set for - its final evaluation. - - :func:`sklearn.metrics.make_scorer`: - Make a scorer from a performance metric or loss function. - - """ - - def __init__(self, estimator, param_grid, scoring=None, fit_params=None, - n_jobs=1, iid=True, refit=True, cv=None, verbose=0, - pre_dispatch='2*n_jobs', error_score='raise', - return_train_score=True): - super(GridSearchCVJoblib, self).__init__( - scoring=scoring, fit_params=fit_params, - n_jobs=n_jobs, iid=iid, refit=refit, cv=cv, verbose=verbose, - pre_dispatch=pre_dispatch, error_score=error_score, - return_train_score=return_train_score) - self.param_grid = param_grid - _check_param_grid(param_grid) - - def fit(self, X, y=None, groups=None): - """Run fit with all sets of parameters. - - Parameters - ---------- - - X : array-like, shape = [n_samples, n_features] - Training vector, where n_samples is the number of samples and - n_features is the number of features. - - y : array-like, shape = [n_samples] or [n_samples, n_output], optional - Target relative to X for classification or regression; - None for unsupervised learning. - - groups : array-like, with shape (n_samples,), optional - Group labels for the samples used while splitting the dataset into - train/test set. - """ - return self._fit(X, y, groups, ParameterGrid(self.param_grid)) diff --git a/build/lib/WORC/classification/construct_classifier.py b/build/lib/WORC/classification/construct_classifier.py deleted file mode 100644 index ac1a61b7..00000000 --- a/build/lib/WORC/classification/construct_classifier.py +++ /dev/null @@ -1,242 +0,0 @@ -#!/usr/bin/env python - -# Copyright 2016-2019 Biomedical Imaging Group Rotterdam, Departments of -# Medical Informatics and Radiology, Erasmus MC, Rotterdam, The Netherlands -# -# 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. - -from sklearn.svm import SVC -from sklearn.svm import SVR as SVMR -from sklearn.ensemble import RandomForestClassifier, RandomForestRegressor -from sklearn.linear_model import SGDClassifier, ElasticNet, SGDRegressor -from sklearn.linear_model import LogisticRegression, Lasso -from sklearn.naive_bayes import GaussianNB, ComplementNB -from sklearn.discriminant_analysis import LinearDiscriminantAnalysis as LDA -from sklearn.discriminant_analysis import QuadraticDiscriminantAnalysis as QDA -import scipy -from WORC.classification.estimators import RankedSVM -from WORC.classification.AdvancedSampler import log_uniform, discrete_uniform -import WORC.addexceptions as ae - - -def construct_classifier(config): - """Interface to create classification - - Different classifications can be created using this common interface - - Parameters - ---------- - config: dict, mandatory - Contains the required config settings. See the Github Wiki for - all available fields. - - Returns: - Constructed classifier - """ - - # NOTE: Function is not working anymore for regression: need - # to move param grid creation to the create_param_grid function - max_iter = config['max_iter'] - if 'SVM' in config['classifiers']: - # Support Vector Machine - classifier = construct_SVM(config) - - elif config['classifiers'] == 'SVR': - # Support Vector Regression - classifier = construct_SVM(config, True) - - elif config['classifiers'] == 'RF': - # Random forest kernel - classifier = RandomForestClassifier(verbose=0, - class_weight='balanced', - n_estimators=config['RFn_estimators'], - min_samples_split=config['RFmin_samples_split'], - max_depth=config['RFmax_depth']) - - elif config['classifiers'] == 'RFR': - # Random forest kernel regression - classifier = RandomForestRegressor(verbose=0, - n_estimators=config['RFn_estimators'], - min_samples_split=config['RFmin_samples_split'], - max_depth=config['RFmax_depth']) - - elif config['classifiers'] == 'ElasticNet': - # Elastic Net Regression - classifier = ElasticNet(alpha=config['ElasticNet_alpha'], - l1_ratio=config['ElasticNet_l1_ratio'], - max_iter=max_iter) - - elif config['classifiers'] == 'Lasso': - # LASSO Regression - param_grid = {'alpha': scipy.stats.uniform(loc=1.0, scale=0.5)} - classifier = Lasso(max_iter=max_iter) - - elif config['classifiers'] == 'SGD': - # Stochastic Gradient Descent classifier - classifier = SGDClassifier(n_iter=config['max_iter'], - alpha=config['SGD_alpha'], - l1_ratio=config['SGD_l1_ratio'], - loss=config['SGD_loss'], - penalty=config['SGD_penalty']) - - elif config['classifiers'] == 'SGDR': - # Stochastic Gradient Descent regressor - classifier = SGDRegressor(n_iter=config['max_iter'], - alpha=config['SGD_alpha'], - l1_ratio=config['SGD_l1_ratio'], - loss=config['SGD_loss'], - penalty=config['SGD_penalty']) - - elif config['classifiers'] == 'LR': - # Logistic Regression - classifier = LogisticRegression(max_iter=max_iter, - penalty=config['LRpenalty'], - C=config['LRC']) - elif config['classifiers'] == 'GaussianNB': - # Naive Bayes classifier using Gaussian distributions - classifier = GaussianNB() - - elif config['classifiers'] == 'ComplementNB': - # Complement Naive Bayes classifier - classifier = ComplementNB() - - elif config['classifiers'] == 'LDA': - # Linear Discriminant Analysis - if config['LDA_solver'] == 'svd': - # Shrinkage does not work with svd solver - shrinkage = None - else: - shrinkage = config['LDA_shrinkage'] - - classifier = LDA(solver=config['LDA_solver'], - shrinkage=shrinkage) - - elif config['classifiers'] == 'QDA': - # Linear Discriminant Analysis - classifier = QDA(reg_param=config['QDA_reg_param']) - else: - message = ('Classifier {} unknown.').format(str(config['classifiers'])) - raise ae.WORCKeyError(message) - - return classifier - - -def construct_SVM(config, regression=False): - """ - Constructs a SVM classifier - - Args: - config (dict): Dictionary of the required config settings - features (pandas dataframe): A pandas dataframe containing the features - to be used for classification - - Returns: - SVM/SVR classifier, parameter grid - """ - - max_iter = config['max_iter'] - if not regression: - clf = SVC(class_weight='balanced', probability=True, max_iter=max_iter) - else: - clf = SVMR(max_iter=max_iter) - - clf.kernel = str(config['SVMKernel']) - clf.C = config['SVMC'] - clf.degree = config['SVMdegree'] - clf.coef0 = config['SVMcoef0'] - clf.gamma = config['SVMgamma'] - - # Check if we need to use a ranked SVM - if config['classifiers'] == 'RankedSVM': - clf = RankedSVM() - param_grid = {'svm': ['Poly'], - 'degree': [2, 3, 4, 5], - 'gamma': scipy.stats.uniform(loc=0, scale=1e-3), - 'coefficient': scipy.stats.uniform(loc=0, scale=1e-2), - } - - return clf - - -def create_param_grid(config): - ''' Create a parameter grid for the WORC classifiers based on the - provided configuration. ''' - - # We only need parameters from the Classification part of the config - config = config['Classification'] - - # Create grid and put in name of classifiers and maximum iterations - param_grid = dict() - param_grid['classifiers'] = config['classifiers'] - param_grid['max_iter'] = config['max_iter'] - - # SVM parameters - param_grid['SVMKernel'] = config['SVMKernel'] - param_grid['SVMC'] = log_uniform(loc=config['SVMC'][0], - scale=config['SVMC'][1]) - param_grid['SVMdegree'] = scipy.stats.uniform(loc=config['SVMdegree'][0], - scale=config['SVMdegree'][1]) - param_grid['SVMcoef0'] = scipy.stats.uniform(loc=config['SVMcoef0'][0], - scale=config['SVMcoef0'][1]) - param_grid['SVMgamma'] = log_uniform(loc=config['SVMgamma'][0], - scale=config['SVMgamma'][1]) - - # RF parameters - # RF parameters - param_grid['RFn_estimators'] =\ - discrete_uniform(loc=config['RFn_estimators'][0], - scale=config['RFn_estimators'][1]) - param_grid['RFmin_samples_split'] =\ - discrete_uniform(loc=config['RFmin_samples_split'][0], - scale=config['RFmin_samples_split'][1]) - param_grid['RFmax_depth'] =\ - discrete_uniform(loc=config['RFmax_depth'][0], - scale=config['RFmax_depth'][1]) - - # Logistic Regression parameters - param_grid['LRpenalty'] = config['LRpenalty'] - param_grid['LRC'] = scipy.stats.uniform(loc=config['LRC'][0], - scale=config['LRC'][1]) - - # LDA/QDA parameters - param_grid['LDA_solver'] = config['LDA_solver'] - param_grid['LDA_shrinkage'] = log_uniform(loc=config['LDA_shrinkage'][0], - scale=config['LDA_shrinkage'][1]) - param_grid['QDA_reg_param'] = log_uniform(loc=config['QDA_reg_param'][0], - scale=config['QDA_reg_param'][1]) - - # ElasticNet parameters - param_grid['ElasticNet_alpha'] =\ - log_uniform(loc=config['ElasticNet_alpha'][0], - scale=config['ElasticNet_alpha'][1]) - param_grid['ElasticNet_l1_ratio'] =\ - scipy.stats.uniform(loc=config['ElasticNet_l1_ratio'][0], - scale=config['ElasticNet_l1_ratio'][1]) - - # SGD Regression parameters - param_grid['SGD_alpha'] =\ - log_uniform(loc=config['SGD_alpha'][0], - scale=config['SGD_alpha'][1]) - - param_grid['SGD_l1_ratio'] =\ - scipy.stats.uniform(loc=config['SGD_l1_ratio'][0], - scale=config['SGD_l1_ratio'][1]) - param_grid['SGD_loss'] = config['SGD_loss'] - param_grid['SGD_penalty'] = config['SGD_penalty'] - - # Naive Bayes parameters - param_grid['CNB_alpha'] =\ - scipy.stats.uniform(loc=config['CNB_alpha'][0], - scale=config['CNB_alpha'][1]) - - return param_grid diff --git a/build/lib/WORC/classification/crossval.py b/build/lib/WORC/classification/crossval.py deleted file mode 100644 index b58d2812..00000000 --- a/build/lib/WORC/classification/crossval.py +++ /dev/null @@ -1,501 +0,0 @@ -#!/usr/bin/env python - -# Copyright 2016-2019 Biomedical Imaging Group Rotterdam, Departments of -# Medical Informatics and Radiology, Erasmus MC, Rotterdam, The Netherlands -# -# 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 numpy as np -import pandas as pd -import logging -import os -from sklearn.model_selection import train_test_split -import xlrd -from .parameter_optimization import random_search_parameters -import WORC.addexceptions as ae - - -def crossval(config, label_data, image_features, - param_grid=None, use_fastr=False, - fastr_plugin=None, tempsave=False, - fixedsplits=None, ensemble={'Use': False}, outputfolder=None, - modus='singlelabel'): - """ - Constructs multiple individual classifiers based on the label settings - - Parameters - ---------- - config: dict, mandatory - Dictionary with config settings. See the Github Wiki for the - available fields and formatting. - - label_data: dict, mandatory - Should contain the following: - patient_IDs (list): IDs of the patients, used to keep track of test and - training sets, and label data - label (list): List of lists, where each list contains the - label status for that patient for each - label - label_name (list): Contains the different names that are stored - in the label object - - image_features: numpy array, mandatory - Consists of a tuple of two lists for each patient: - (feature_values, feature_labels) - - param_grid: dictionary, optional - Contains the parameters and their values wich are used in the - grid or randomized search hyperparamater optimization. See the - construct_classifier function for some examples. - - use_fastr: boolean, default False - If False, parallel execution through Joblib is used for fast - execution of the hyperparameter optimization. Especially suited - for execution on mutlicore (H)PC's. The settings used are - specified in the config.ini file in the IOparser folder, which you - can adjust to your system. - - If True, fastr is used to split the hyperparameter optimization in - separate jobs. Parameters for the splitting can be specified in the - config file. Especially suited for clusters. - - fastr_plugin: string, default None - Determines which plugin is used for fastr executions. - When None, uses the default plugin from the fastr config. - - tempsave: boolean, default False - If True, create a .hdf5 file after each cross validation containing - the classifier and results from that that split. This is written to - the GSOut folder in your fastr output mount. If False, only - the result of all combined cross validations will be saved to a .hdf5 - file. This will also be done if set to True. - - fixedsplits: string, optional - By default, random split cross validation is used to train and - evaluate the machine learning methods. Optionally, you can provide - a .xlsx file containing fixed splits to be used. See the Github Wiki - for the format. - - ensemble: dictionary, optional - Contains the configuration for constructing an ensemble. - - modus: string, default 'singlelabel' - Determine whether one-vs-all classification (or regression) for - each single label is used ('singlelabel') or if multilabel - classification is performed ('multilabel'). - - Returns - ---------- - panda_data: pandas dataframe - Contains all information on the trained classifier. - - """ - if tempsave: - import fastr - - - # Define all possible regressors - regressors = ['SVR', 'RFR', 'SGDR', 'Lasso', 'ElasticNet'] - - # Process input data - patient_IDs = label_data['patient_IDs'] - label_value = label_data['label'] - label_name = label_data['label_name'] - - if outputfolder is None: - logfilename = os.path.join(os.getcwd(), 'classifier.log') - else: - logfilename = os.path.join(outputfolder, 'classifier.log') - print("Logging to file " + str(logfilename)) - - for handler in logging.root.handlers[:]: - logging.root.removeHandler(handler) - - logging.basicConfig(filename=logfilename, level=logging.DEBUG) - N_iterations = config['CrossValidation']['N_iterations'] - test_size = config['CrossValidation']['test_size'] - - classifier_labelss = dict() - logging.debug('Starting classifier') - - # We only need one label instance, assuming they are all the sample - feature_labels = image_features[0][1] - - # Check if we need to use fixedsplits: - if fixedsplits is not None and '.xlsx' in fixedsplits: - # fixedsplits = '/home/mstarmans/Settings/RandomSufflingOfData.xlsx' - wb = xlrd.open_workbook(fixedsplits) - wb = wb.sheet_by_index(1) - - if modus == 'singlelabel': - print('Performing Single class classification.') - logging.debug('Performing Single class classification.') - elif modus == 'multilabel': - print('Performing Multi label classification.') - logging.debug('Performing Multi class classification.') - label_value = [label_value] - label_name = [label_name] - else: - m = ('{} is not a valid modus!').format(modus) - logging.debug(m) - raise ae.WORCKeyError(m) - - for i_class, i_name in zip(label_value, label_name): - if modus == 'singlelabel': - i_class_temp = i_class.ravel() - - save_data = list() - - for i in range(0, N_iterations): - print(('Cross validation iteration {} / {} .').format(str(i + 1), str(N_iterations))) - logging.debug(('Cross validation iteration {} / {} .').format(str(i + 1), str(N_iterations))) - random_seed = np.random.randint(5000) - - # Split into test and training set, where the percentage of each - # label is maintained - if any(clf in regressors for clf in param_grid['classifiers']): - # We cannot do a stratified shuffle split with regression - stratify = None - else: - if modus == 'singlelabel': - stratify = i_class_temp - elif modus == 'multilabel': - # Create a stratification object from the labels - # Label = 0 means no label equals one - # Other label numbers refer to the label name that is 1 - stratify = list() - for pnum in range(0, len(i_class[0])): - plabel = 0 - for lnum, slabel in enumerate(i_class): - if slabel[pnum] == 1: - plabel = lnum + 1 - stratify.append(plabel) - - # Sklearn multiclass requires rows to be objects/patients - # i_class = i_class.reshape(i_class.shape[1], i_class.shape[0]) - i_class_temp = np.zeros((i_class.shape[1], i_class.shape[0])) - for n_patient in range(0, i_class.shape[1]): - for n_label in range(0, i_class.shape[0]): - i_class_temp[n_patient, n_label] = i_class[n_label, n_patient] - i_class_temp = i_class_temp - else: - raise ae.WORCKeyError('{} is not a valid modus!').format(modus) - - if fixedsplits is None: - # Use Random Split. Split per patient, not per sample - unique_patient_IDs, unique_indices =\ - np.unique(np.asarray(patient_IDs), return_index=True) - if any(clf in regressors for clf in param_grid['classifiers']): - unique_stratify = None - else: - unique_stratify = [stratify[i] for i in unique_indices] - - try: - unique_PID_train, indices_PID_test\ - = train_test_split(unique_patient_IDs, - test_size=test_size, - random_state=random_seed, - stratify=unique_stratify) - except ValueError as e: - e = str(e) + ' Increase the size of your validation set.' - raise ae.WORCValueError(e) - - # Check for all IDs if they are in test or training - indices_train = list() - indices_test = list() - patient_ID_train = list() - patient_ID_test = list() - for num, pid in enumerate(patient_IDs): - if pid in unique_PID_train: - indices_train.append(num) - - # Make sure we get a unique ID - if pid in patient_ID_train: - n = 1 - while str(pid + '_' + str(n)) in patient_ID_train: - n += 1 - pid = str(pid + '_' + str(n)) - patient_ID_train.append(pid) - else: - indices_test.append(num) - - # Make sure we get a unique ID - if pid in patient_ID_test: - n = 1 - while str(pid + '_' + str(n)) in patient_ID_test: - n += 1 - pid = str(pid + '_' + str(n)) - patient_ID_test.append(pid) - - # Split features and labels accordingly - X_train = [image_features[i] for i in indices_train] - X_test = [image_features[i] for i in indices_test] - if modus == 'singlelabel': - Y_train = i_class_temp[indices_train] - Y_test = i_class_temp[indices_test] - elif modus == 'multilabel': - Y_train = i_class_temp[indices_train, :] - Y_test = i_class_temp[indices_test, :] - else: - raise ae.WORCKeyError('{} is not a valid modus!').format(modus) - - else: - # Use pre defined splits - indices = wb.col_values(i) - indices = [int(j) for j in indices[1:]] # First element is "Iteration x" - train = indices[0:121] - test = indices[121:] - - # Convert the numbers to the correct indices - ind_train = list() - for j in train: - success = False - for num, p in enumerate(patient_IDs): - if str(j).zfill(3) == p[0:3]: - ind_train.append(num) - success = True - if not success: - raise ae.WORCIOError("Patient " + str(j).zfill(3) + " is not included!") - - ind_test = list() - for j in test: - success = False - for num, p in enumerate(patient_IDs): - if str(j).zfill(3) == p[0:3]: - ind_test.append(num) - success = True - if not success: - raise ae.WORCIOError("Patient " + str(j).zfill(3) + " is not included!") - - X_train = np.asarray(image_features)[ind_train].tolist() - Y_train = np.asarray(i_class_temp)[ind_train].tolist() - patient_ID_train = patient_IDs[ind_train] - X_test = np.asarray(image_features)[ind_test].tolist() - Y_test = np.asarray(i_class_temp)[ind_test].tolist() - patient_ID_test = patient_IDs[ind_test] - - # Find best hyperparameters and construct classifier - config['HyperOptimization']['use_fastr'] = use_fastr - config['HyperOptimization']['fastr_plugin'] = fastr_plugin - n_cores = config['General']['Joblib_ncores'] - trained_classifier = random_search_parameters(features=X_train, - labels=Y_train, - param_grid=param_grid, - n_cores=n_cores, - **config['HyperOptimization']) - - # Create an ensemble if required - if ensemble['Use']: - trained_classifier.create_ensemble(X_train, Y_train) - - # We only want to save the feature values and one label array - X_train = [x[0] for x in X_train] - X_test = [x[0] for x in X_test] - - temp_save_data = (trained_classifier, X_train, X_test, Y_train, - Y_test, patient_ID_train, patient_ID_test, random_seed) - - save_data.append(temp_save_data) - - # Create a temporary save - if tempsave: - panda_labels = ['trained_classifier', 'X_train', 'X_test', 'Y_train', 'Y_test', - 'config', 'patient_ID_train', 'patient_ID_test', - 'random_seed'] - - panda_data_temp =\ - pd.Series([trained_classifier, X_train, X_test, Y_train, - Y_test, config, patient_ID_train, - patient_ID_test, random_seed], - index=panda_labels, - name='Constructed crossvalidation') - - panda_data = pd.DataFrame(panda_data_temp) - n = 0 - filename = os.path.join(fastr.config.mounts['tmp'], 'GSout', 'RS_' + str(i) + '.hdf5') - while os.path.exists(filename): - n += 1 - filename = os.path.join(fastr.config.mounts['tmp'], 'GSout', 'RS_' + str(i + n) + '.hdf5') - - if not os.path.exists(os.path.dirname(filename)): - os.makedirs(os.path.dirname(filename)) - - panda_data.to_hdf(filename, 'SVMdata') - del panda_data, panda_data_temp - - [classifiers, X_train_set, X_test_set, Y_train_set, Y_test_set, - patient_ID_train_set, patient_ID_test_set, seed_set] =\ - zip(*save_data) - - panda_labels = ['classifiers', 'X_train', 'X_test', 'Y_train', 'Y_test', - 'config', 'patient_ID_train', 'patient_ID_test', - 'random_seed', 'feature_labels'] - - panda_data_temp =\ - pd.Series([classifiers, X_train_set, X_test_set, Y_train_set, - Y_test_set, config, patient_ID_train_set, - patient_ID_test_set, seed_set, feature_labels], - index=panda_labels, - name='Constructed crossvalidation') - - if modus == 'singlelabel': - i_name = ''.join(i_name) - elif modus == 'multilabel': - i_name = ','.join(i_name) - - classifier_labelss[i_name] = panda_data_temp - - panda_data = pd.DataFrame(classifier_labelss) - - return panda_data - - -def nocrossval(config, label_data_train, label_data_test, image_features_train, - image_features_test, param_grid=None, use_fastr=False, - fastr_plugin=None, ensemble={'Use': False}, - modus='singlelabel'): - """ - Constructs multiple individual classifiers based on the label settings - - Arguments: - config (Dict): Dictionary with config settings - label_data (Dict): should contain: - patient_IDs (list): IDs of the patients, used to keep track of test and - training sets, and label data - label (list): List of lists, where each list contains the - label status for that patient for each - label - label_name (list): Contains the different names that are stored - in the label object - image_features (numpy array): Consists of a tuple of two lists for each patient: - (feature_values, feature_labels) - - ensemble: dictionary, optional - Contains the configuration for constructing an ensemble. - - modus: string, default 'singlelabel' - Determine whether one-vs-all classification (or regression) for - each single label is used ('singlelabel') or if multilabel - classification is performed ('multilabel'). - - Returns: - classifier_data (pandas dataframe) - """ - - patient_IDs_train = label_data_train['patient_IDs'] - label_value_train = label_data_train['label'] - label_name_train = label_data_train['label_name'] - - patient_IDs_test = label_data_test['patient_IDs'] - if 'label' in label_data_test.keys(): - label_value_test = label_data_test['label'] - else: - label_value_test = [None] * len(patient_IDs_test) - - logfilename = os.path.join(os.getcwd(), 'classifier.log') - logging.basicConfig(filename=logfilename, level=logging.DEBUG) - - classifier_labelss = dict() - - print('features') - logging.debug('Starting classifier') - print(len(image_features_train)) - - # Determine modus - if modus == 'singlelabel': - print('Performing Single class classification.') - logging.debug('Performing Single class classification.') - elif modus == 'multilabel': - print('Performing Multi label classification.') - logging.debug('Performing Multi class classification.') - label_name_train = [label_name_train] - else: - m = ('{} is not a valid modus!').format(modus) - logging.debug(m) - raise ae.WORCKeyError(m) - - # We only need one label instance, assuming they are all the sample - feature_labels = image_features_train[0][1] - for i_name in label_name_train: - - save_data = list() - - random_seed = np.random.randint(5000) - - # Split into test and training set, where the percentage of each - # label is maintained - X_train = image_features_train - X_test = image_features_test - if modus == 'singlelabel': - Y_train = label_value_train.ravel() - Y_test = label_value_test.ravel() - else: - # Sklearn multiclass requires rows to be objects/patients - Y_train = label_value_train - Y_train_temp = np.zeros((Y_train.shape[1], Y_train.shape[0])) - for n_patient in range(0, Y_train.shape[1]): - for n_label in range(0, Y_train.shape[0]): - Y_train_temp[n_patient, n_label] = Y_train[n_label, n_patient] - Y_train = Y_train_temp - - Y_test = label_value_test - Y_test_temp = np.zeros((Y_test.shape[1], Y_test.shape[0])) - for n_patient in range(0, Y_test.shape[1]): - for n_label in range(0, Y_test.shape[0]): - Y_test_temp[n_patient, n_label] = Y_test[n_label, n_patient] - Y_test = Y_test_temp - - # Find best hyperparameters and construct classifier - config['HyperOptimization']['use_fastr'] = use_fastr - config['HyperOptimization']['fastr_plugin'] = fastr_plugin - n_cores = config['General']['Joblib_ncores'] - trained_classifier = random_search_parameters(features=X_train, - labels=Y_train, - param_grid=param_grid, - n_cores=n_cores, - **config['HyperOptimization']) - - # Create an ensemble if required - if ensemble['Use']: - trained_classifier.create_ensemble(X_train, Y_train) - - # Extract the feature values - X_train = np.asarray([x[0] for x in X_train]) - X_test = np.asarray([x[0] for x in X_test]) - - temp_save_data = (trained_classifier, X_train, X_test, Y_train, - Y_test, patient_IDs_train, patient_IDs_test, random_seed) - - save_data.append(temp_save_data) - - [classifiers, X_train_set, X_test_set, Y_train_set, Y_test_set, - patient_ID_train_set, patient_ID_test_set, seed_set] =\ - zip(*save_data) - - panda_labels = ['classifiers', 'X_train', 'X_test', 'Y_train', 'Y_test', - 'config', 'patient_ID_train', 'patient_ID_test', - 'random_seed', 'feature_labels'] - - panda_data_temp =\ - pd.Series([classifiers, X_train_set, X_test_set, Y_train_set, - Y_test_set, config, patient_ID_train_set, - patient_ID_test_set, seed_set, feature_labels], - index=panda_labels, - name='Constructed crossvalidation') - - i_name = ''.join(i_name) - classifier_labelss[i_name] = panda_data_temp - - panda_data = pd.DataFrame(classifier_labelss) - - return panda_data diff --git a/build/lib/WORC/classification/estimators.py b/build/lib/WORC/classification/estimators.py deleted file mode 100644 index 0c71d46e..00000000 --- a/build/lib/WORC/classification/estimators.py +++ /dev/null @@ -1,151 +0,0 @@ -#!/usr/bin/env python - -# Copyright 2016-2019 Biomedical Imaging Group Rotterdam, Departments of -# Medical Informatics and Radiology, Erasmus MC, Rotterdam, The Netherlands -# -# 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 numpy as np -from sklearn.base import BaseEstimator, ClassifierMixin -from sklearn.utils.validation import check_is_fitted -from sklearn.utils.multiclass import unique_labels -import WORC.classification.RankedSVM as RSVM - - -class RankedSVM(BaseEstimator, ClassifierMixin): - """ An example classifier which implements a 1-NN algorithm. - - Parameters - ---------- - demo_param : str, optional - A parameter used for demonstation of how to pass and store paramters. - - Attributes - ---------- - X_ : array, shape = [n_samples, n_features] - The input passed during :meth:`fit` - y_ : array, shape = [n_samples] - The labels passed during :meth:`fit` - """ - def __init__(self, cost=1, lambda_tol=1e-6, - norm_tol=1e-4, max_iter=500, svm='Poly', gamma=0.05, - coefficient=0.05, degree=3): - self.cost = cost - self.lambda_tol = lambda_tol - self.norm_tol = norm_tol - self.max_iter = max_iter - self.svm = svm - self.gamma = gamma - self.coefficient = coefficient - self.degree = 3 - - def fit(self, X, y): - """A reference implementation of a fitting function for a classifier. - - Parameters - ---------- - X : array-like, shape = [n_samples, n_features] - The training input samples. - y : array-like, shape = [n_samples] - The target values. An array of int. - - Returns - ------- - self : object - Returns self. - """ - - # Store the classes seen during fit - self.classes_ = unique_labels(y) - - # RankedSVM requires a very specific format of y - # Each row should represent a label, consisiting of ones and minus ones - y = np.transpose(y).astype(np.int16) - y[y == 0] = -1 - self.X_ = X - self.y_ = y - self.num_class = y.shape[0] - - Weights, Bias, SVs =\ - RSVM.RankSVM_train(train_data=X, - train_target=y, - cost=self.cost, - lambda_tol=self.lambda_tol, - norm_tol=self.norm_tol, - max_iter=self.max_iter, - svm=self.svm, gamma=self.gamma, - coefficient=self.coefficient, - degree=self.degree) - - self.Weights = Weights - self.Bias = Bias - self.SVs = SVs - - return self - - def predict(self, X, y=None): - """ A reference implementation of a prediction for a classifier. - - Parameters - ---------- - X : array-like of shape = [n_samples, n_features] - The input samples. - - Returns - ------- - y : array of int of shape = [n_samples] - The label for each sample is the label of the closest sample - seen udring fit. - """ - # Check is fit had been called - check_is_fitted(self, ['X_', 'y_']) - - _, Predicted_Labels =\ - RSVM.RankSVM_test(test_data=X, - num_class=self.num_class, - Weights=self.Weights, - Bias=self.Bias, - SVs=self.SVs, - svm=self.svm, gamma=self.gamma, - coefficient=self.coefficient, - degree=self.degree) - - return Predicted_Labels - - def predict_proba(self, X, y): - """ A reference implementation of a prediction for a classifier. - - Parameters - ---------- - X : array-like of shape = [n_samples, n_features] - The input samples. - - Returns - ------- - y : array of int of shape = [n_samples] - The label for each sample is the label of the closest sample - seen udring fit. - """ - # Check is fit had been called - check_is_fitted(self, ['X_', 'y_']) - - Probs, _ =\ - RSVM.RankSVM_test(test_data=X, - num_class=self.num_class, - Weights=self.Weights, - Bias=self.Bias, - svm=self.svm, gamma=self.gamma, - coefficient=self.coefficient, - degree=self.degree) - - return Probs diff --git a/build/lib/WORC/classification/fitandscore.py b/build/lib/WORC/classification/fitandscore.py deleted file mode 100644 index ac756dbc..00000000 --- a/build/lib/WORC/classification/fitandscore.py +++ /dev/null @@ -1,782 +0,0 @@ -#!/usr/bin/env python - -# Copyright 2016-2019 Biomedical Imaging Group Rotterdam, Departments of -# Medical Informatics and Radiology, Erasmus MC, Rotterdam, The Netherlands -# -# 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. - -from sklearn.preprocessing import StandardScaler -from sklearn.preprocessing import MinMaxScaler -from sklearn.model_selection._validation import _fit_and_score -import numpy as np -from sklearn.linear_model import Lasso -from sklearn.feature_selection import SelectFromModel -import scipy -from sklearn.decomposition import PCA -from sklearn.multiclass import OneVsRestClassifier -from imblearn.over_sampling import SMOTE, RandomOverSampler -from sklearn.utils import check_random_state -import random -from sklearn.metrics import make_scorer, average_precision_score -from WORC.classification.estimators import RankedSVM -from WORC.classification import construct_classifier as cc -from WORC.classification.metrics import check_scoring -from WORC.featureprocessing.Relief import SelectMulticlassRelief -from WORC.featureprocessing.Imputer import Imputer -from WORC.featureprocessing.VarianceThreshold import selfeat_variance -from WORC.featureprocessing.StatisticalTestThreshold import StatisticalTestThreshold -from WORC.featureprocessing.SelectGroups import SelectGroups - - -def fit_and_score(X, y, scoring, - train, test, para, - fit_params=None, - return_train_score=True, - return_n_test_samples=True, - return_times=True, return_parameters=True, - error_score='raise', verbose=True, - return_all=True): - ''' - Fit an estimator to a dataset and score the performance. The following - methods can currently be applied as preprocessing before fitting, in - this order: - 1. Select features based on feature type group (e.g. shape, histogram). - 2. Oversampling - 3. Apply feature imputation (WIP). - 4. Apply feature selection based on variance of feature among patients. - 5. Univariate statistical testing (e.g. t-test, Wilcoxon). - 6. Scale features with e.g. z-scoring. - 7. Use Relief feature selection. - 8. Select features based on a fit with a LASSO model. - 9. Select features using PCA. - 10. If a SingleLabel classifier is used for a MultiLabel problem, - a OneVsRestClassifier is employed around it. - - All of the steps are optional. - - Parameters - ---------- - estimator: sklearn estimator, mandatory - Unfitted estimator which will be fit. - - X: array, mandatory - Array containingfor each object (rows) the feature values - (1st Column) and the associated feature label (2nd Column). - - y: list(?), mandatory - List containing the labels of the objects. - - scorer: sklearn scorer, mandatory - Function used as optimization criterion for the hyperparamater optimization. - - train: list, mandatory - Indices of the objects to be used as training set. - - test: list, mandatory - Indices of the objects to be used as testing set. - - para: dictionary, mandatory - Contains the settings used for the above preprocessing functions - and the fitting. TODO: Create a default object and show the - fields. - - fit_params:dictionary, default None - Parameters supplied to the estimator for fitting. See the SKlearn - site for the parameters of the estimators. - - return_train_score: boolean, default True - Save the training score to the final SearchCV object. - - return_n_test_samples: boolean, default True - Save the number of times each sample was used in the test set - to the final SearchCV object. - - return_times: boolean, default True - Save the time spend for each fit to the final SearchCV object. - - return_parameters: boolean, default True - Return the parameters used in the final fit to the final SearchCV - object. - - error_score: numeric or "raise" by default - Value to assign to the score if an error occurs in estimator - fitting. If set to "raise", the error is raised. If a numeric - value is given, FitFailedWarning is raised. This parameter - does not affect the refit step, which will always raise the error. - - verbose: boolean, default=True - If True, print intermediate progress to command line. Warnings are - always printed. - - return_all: boolean, default=True - If False, only the ret object containing the performance will be - returned. If True, the ret object plus all fitted objects will be - returned. - - Returns - ---------- - Depending on the return_all input parameter, either only ret or all objects - below are returned. - - ret: list - Contains optionally the train_scores and the test_scores, - test_sample_counts, fit_time, score_time, parameters_est - and parameters_all. - - GroupSel: WORC GroupSel Object - Either None if the groupwise feature selection is not used, or - the fitted object. - - VarSel: WORC VarSel Object - Either None if the variance threshold feature selection is not used, or - the fitted object. - - SelectModel: WORC SelectModel Object - Either None if the feature selection based on a fittd model is not - used, or the fitted object. - - feature_labels: list - Labels of the features. Only one list is returned, not one per - feature object, as we assume all samples have the same feature names. - - scaler: scaler object - Either None if feature scaling is not used, or - the fitted object. - - imputer: WORC Imputater Object - Either None if feature imputation is not used, or - the fitted object. - - pca: WORC PCA Object - Either None if PCA based feature selection is not used, or - the fitted object. - - StatisticalSel: WORC StatisticalSel Object - Either None if the statistical test feature selection is not used, or - the fitted object. - - ReliefSel: WORC ReliefSel Object - Either None if the RELIEF feature selection is not used, or - the fitted object. - - sm: WORC SMOTE Object - Either None if the SMOTE oversampling is not used, or - the fitted object. - - ros: WORC ROS Object - Either None if Random Oversampling is not used, or - the fitted object. - - ''' - # We copy the parameter object so we can alter it and keep the original - para_estimator = para.copy() - estimator = cc.construct_classifier(para_estimator) - if scoring != 'average_precision_weighted': - scorer = check_scoring(estimator, scoring=scoring) - else: - scorer = make_scorer(average_precision_score, average='weighted') - - para_estimator = delete_cc_para(para_estimator) - - # X is a tuple: split in two arrays - feature_values = np.asarray([x[0] for x in X]) - feature_labels = np.asarray([x[1] for x in X]) - - # ------------------------------------------------------------------------ - # Feature imputation - if 'Imputation' in para_estimator.keys(): - if para_estimator['Imputation'] == 'True': - imp_type = para_estimator['ImputationMethod'] - if verbose: - message = ('Imputing NaN with {}.').format(imp_type) - print(message) - imp_nn = para_estimator['ImputationNeighbours'] - - imputer = Imputer(missing_values=np.nan, strategy=imp_type, - n_neighbors=imp_nn) - imputer.fit(feature_values) - feature_values = imputer.transform(feature_values) - else: - imputer = None - else: - imputer = None - - if 'Imputation' in para_estimator.keys(): - del para_estimator['Imputation'] - del para_estimator['ImputationMethod'] - del para_estimator['ImputationNeighbours'] - - # Delete the object if we do not need to return it - if not return_all: - del imputer - - # ------------------------------------------------------------------------ - # Use SMOTE oversampling - if 'SampleProcessing_SMOTE' in para_estimator.keys(): - if para_estimator['SampleProcessing_SMOTE'] == 'True': - - # Determine our starting balance - pos_initial = int(np.sum(y)) - neg_initial = int(len(y) - pos_initial) - len_in = len(y) - - # Fit SMOTE object and transform dataset - # NOTE: need to save random state for this one as well! - sm = SMOTE(random_state=None, - ratio=para_estimator['SampleProcessing_SMOTE_ratio'], - m_neighbors=para_estimator['SampleProcessing_SMOTE_neighbors'], - kind='borderline1', - n_jobs=para_estimator['SampleProcessing_SMOTE_n_cores']) - - feature_values, y = sm.fit_sample(feature_values, y) - - # Also make sure our feature label object has the same size - # NOTE: Not sure if this is the best implementation - feature_labels = np.asarray([feature_labels[0] for x in X]) - - # Note the user what SMOTE did - pos = int(np.sum(y)) - neg = int(len(y) - pos) - if verbose: - message = ("Sampling with SMOTE from {} ({} pos, {} neg) to {} ({} pos, {} neg) patients.").format(str(len_in), - str(pos_initial), - str(neg_initial), - str(len(y)), - str(pos), - str(neg)) - print(message) - else: - sm = None - - if 'SampleProcessing_SMOTE' in para_estimator.keys(): - del para_estimator['SampleProcessing_SMOTE'] - del para_estimator['SampleProcessing_SMOTE_ratio'] - del para_estimator['SampleProcessing_SMOTE_neighbors'] - del para_estimator['SampleProcessing_SMOTE_n_cores'] - - # Delete the object if we do not need to return it - if not return_all: - del sm - - # ------------------------------------------------------------------------ - # Full Oversampling: To Do - if 'SampleProcessing_Oversampling' in para_estimator.keys(): - if para_estimator['SampleProcessing_Oversampling'] == 'True': - if verbose: - print('Oversample underrepresented classes in training.') - - # Oversample underrepresented classes in training - # We always use a factor 1, e.g. all classes end up with an - # equal number of samples - if len(y.shape) == 1: - # Single Class, use imblearn oversampling - - # Create another random state - # NOTE: Also need to save this random seed. Can be same as SMOTE - random_seed2 = np.random.randint(5000) - random_state2 = check_random_state(random_seed2) - - ros = RandomOverSampler(random_state=random_state2) - feature_values, y = ros.fit_sample(feature_values, y) - - else: - # Multi class, use own method as imblearn cannot do this - sumclass = [np.sum(y[:, i]) for i in range(y.shape[1])] - maxclass = np.argmax(sumclass) - for i in range(y.shape[1]): - if i != maxclass: - # Oversample - nz = np.nonzero(y[:, i])[0] - noversample = sumclass[maxclass] - sumclass[i] - while noversample > 0: - n_sample = random.randint(0, len(nz) - 1) - n_sample = nz[n_sample] - i_sample = y[n_sample, :] - x_sample = feature_values[n_sample] - y = np.vstack((y, i_sample)) - feature_values.append(x_sample) - noversample -= 1 - else: - ros = None - - if 'SampleProcessing_Oversampling' in para_estimator.keys(): - del para_estimator['SampleProcessing_Oversampling'] - - # Delete the object if we do not need to return it - if not return_all: - del ros - - # ------------------------------------------------------------------------ - # Groupwise feature selection - if 'SelectGroups' in para_estimator: - if verbose: - print("Selecting groups of features.") - del para_estimator['SelectGroups'] - # TODO: more elegant way to solve this - feature_groups = ["histogram_features", "orientation_features", - "patient_features", "semantic_features", - "shape_features", - "coliage_features", 'vessel_features', - "phase_features", "log_features", - "texture_gabor_features", "texture_glcm_features", - "texture_glcmms_features", "texture_glrlm_features", - "texture_glszm_features", "texture_ngtdm_features", - "texture_lbp_features"] - - # Backwards compatability - if 'texture_features' in para_estimator.keys(): - feature_groups.append('texture_features') - - # Check per feature group if the parameter is present - parameters_featsel = dict() - for group in feature_groups: - if group not in para_estimator: - # Default: do use the group, except for texture features - if group == 'texture_features': - value = 'False' - else: - value = 'True' - else: - value = para_estimator[group] - del para_estimator[group] - - parameters_featsel[group] = value - - GroupSel = SelectGroups(parameters=parameters_featsel) - GroupSel.fit(feature_labels[0]) - if verbose: - print("Original Length: " + str(len(feature_values[0]))) - feature_values = GroupSel.transform(feature_values) - if verbose: - print("New Length: " + str(len(feature_values[0]))) - feature_labels = GroupSel.transform(feature_labels) - else: - GroupSel = None - - # Delete the object if we do not need to return it - if not return_all: - del GroupSel - - # Check whether there are any features left - if len(feature_values[0]) == 0: - # TODO: Make a specific WORC exception for this warning. - if verbose: - print('[WARNING]: No features are selected! Probably all feature groups were set to False. Parameters:') - print(para) - - # Return a zero performance dummy - VarSel = None - scaler = None - SelectModel = None - pca = None - StatisticalSel = None - ReliefSel = None - - # Delete the non-used fields - para_estimator = delete_nonestimator_parameters(para_estimator) - - ret = [0, 0, 0, 0, 0, para_estimator, para] - if return_all: - return ret, GroupSel, VarSel, SelectModel, feature_labels[0], scaler, imputer, pca, StatisticalSel, ReliefSel, sm, ros - else: - return ret - - # ------------------------------------------------------------------------ - # FIXME: When only using LBP feature, X is 3 dimensional with 3rd dimension length 1 - if len(feature_values.shape) == 3: - feature_values = np.reshape(feature_values, (feature_values.shape[0], feature_values.shape[1])) - if len(feature_labels.shape) == 3: - feature_labels = np.reshape(feature_labels, (feature_labels.shape[0], feature_labels.shape[1])) - - # Remove any NaN feature values if these are still left after imputation - feature_values = replacenan(feature_values, verbose=verbose, feature_labels=feature_labels[0]) - - # -------------------------------------------------------------------- - # Feature selection based on variance - if para_estimator['Featsel_Variance'] == 'True': - if verbose: - print("Selecting features based on variance.") - if verbose: - print("Original Length: " + str(len(feature_values[0]))) - try: - feature_values, feature_labels, VarSel =\ - selfeat_variance(feature_values, feature_labels) - except ValueError: - if verbose: - print('[WARNING]: No features meet the selected Variance threshold! Skipping selection.') - VarSel = None - if verbose: - print("New Length: " + str(len(feature_values[0]))) - else: - VarSel = None - del para_estimator['Featsel_Variance'] - - # Delete the object if we do not need to return it - if not return_all: - del VarSel - - # Check whether there are any features left - if len(feature_values[0]) == 0: - # TODO: Make a specific WORC exception for this warning. - if verbose: - print('[WARNING]: No features are selected! Probably you selected a feature group that is not in your feature file. Parameters:') - print(para) - para_estimator = delete_nonestimator_parameters(para_estimator) - - # Return a zero performance dummy - scaler = None - SelectModel = None - pca = None - StatisticalSel = None - ret = [0, 0, 0, 0, 0, para_estimator, para] - if return_all: - return ret, GroupSel, VarSel, SelectModel, feature_labels[0], scaler, imputer, pca, StatisticalSel, ReliefSel, sm, ros - else: - return ret - - # -------------------------------------------------------------------- - # Feature selection based on a statistical test - if 'StatisticalTestUse' in para_estimator.keys(): - if para_estimator['StatisticalTestUse'] == 'True': - metric = para_estimator['StatisticalTestMetric'] - threshold = para_estimator['StatisticalTestThreshold'] - if verbose: - print("Selecting features based on statistical test. Method {}, threshold {}.").format(metric, str(round(threshold, 2))) - if verbose: - print("Original Length: " + str(len(feature_values[0]))) - - StatisticalSel = StatisticalTestThreshold(metric=metric, - threshold=threshold) - - StatisticalSel.fit(feature_values, y) - feature_values = StatisticalSel.transform(feature_values) - feature_labels = StatisticalSel.transform(feature_labels) - if verbose: - print("New Length: " + str(len(feature_values[0]))) - else: - StatisticalSel = None - del para_estimator['StatisticalTestUse'] - del para_estimator['StatisticalTestMetric'] - del para_estimator['StatisticalTestThreshold'] - else: - StatisticalSel = None - - # Delete the object if we do not need to return it - if not return_all: - del StatisticalSel - - # Check whether there are any features left - if len(feature_values[0]) == 0: - # TODO: Make a specific WORC exception for this warning. - if verbose: - print('[WARNING]: No features are selected! Probably you selected a feature group that is not in your feature file. Parameters:') - print(para) - - para_estimator = delete_nonestimator_parameters(para_estimator) - - # Return a zero performance dummy - scaler = None - SelectModel = None - pca = None - ret = [0, 0, 0, 0, 0, para_estimator, para] - if return_all: - return ret, GroupSel, VarSel, SelectModel, feature_labels[0], scaler, imputer, pca, StatisticalSel, ReliefSel, sm, ros - else: - return ret - - # ------------------------------------------------------------------------ - # Feature scaling - if 'FeatureScaling' in para_estimator: - if verbose: - print("Fitting scaler and transforming features.") - - if para_estimator['FeatureScaling'] == 'z_score': - scaler = StandardScaler().fit(feature_values) - elif para_estimator['FeatureScaling'] == 'minmax': - scaler = MinMaxScaler().fit(feature_values) - else: - scaler = None - - if scaler is not None: - feature_values = scaler.transform(feature_values) - del para_estimator['FeatureScaling'] - else: - scaler = None - - # Delete the object if we do not need to return it - if not return_all: - del scaler - - # -------------------------------------------------------------------- - # Relief feature selection, possibly multi classself. - # Needs to be done after scaling! - # para_estimator['ReliefUse'] = 'True' - if 'ReliefUse' in para_estimator.keys(): - if para_estimator['ReliefUse'] == 'True': - if verbose: - print("Selecting features using relief.") - - # Get parameters from para_estimator - n_neighbours = para_estimator['ReliefNN'] - sample_size = para_estimator['ReliefSampleSize'] - distance_p = para_estimator['ReliefDistanceP'] - numf = para_estimator['ReliefNumFeatures'] - - ReliefSel = SelectMulticlassRelief(n_neighbours=n_neighbours, - sample_size=sample_size, - distance_p=distance_p, - numf=numf) - ReliefSel.fit(feature_values, y) - if verbose: - print("Original Length: " + str(len(feature_values[0]))) - feature_values = ReliefSel.transform(feature_values) - if verbose: - print("New Length: " + str(len(feature_values[0]))) - feature_labels = ReliefSel.transform(feature_labels) - else: - ReliefSel = None - else: - ReliefSel = None - - # Delete the object if we do not need to return it - if not return_all: - del ReliefSel - - if 'ReliefUse' in para_estimator.keys(): - del para_estimator['ReliefUse'] - del para_estimator['ReliefNN'] - del para_estimator['ReliefSampleSize'] - del para_estimator['ReliefDistanceP'] - del para_estimator['ReliefNumFeatures'] - - # ------------------------------------------------------------------------ - # Perform feature selection using a model - if 'SelectFromModel' in para_estimator.keys() and para_estimator['SelectFromModel'] == 'True': - if verbose: - print("Selecting features using lasso model.") - # Use lasso model for feature selection - - # First, draw a random value for alpha and the penalty ratio - alpha = scipy.stats.uniform(loc=0.0, scale=1.5).rvs() - # l1_ratio = scipy.stats.uniform(loc=0.5, scale=0.4).rvs() - - # Create and fit lasso model - lassomodel = Lasso(alpha=alpha) - lassomodel.fit(feature_values, y) - - # Use fit to select optimal features - SelectModel = SelectFromModel(lassomodel, prefit=True) - if verbose: - print("Original Length: " + str(len(feature_values[0]))) - feature_values = SelectModel.transform(feature_values) - if verbose: - print("New Length: " + str(len(feature_values[0]))) - feature_labels = SelectModel.transform(feature_labels) - else: - SelectModel = None - if 'SelectFromModel' in para_estimator.keys(): - del para_estimator['SelectFromModel'] - - # Delete the object if we do not need to return it - if not return_all: - del SelectModel - - # ---------------------------------------------------------------- - # PCA dimensionality reduction - # Principle Component Analysis - if 'UsePCA' in para_estimator.keys() and para_estimator['UsePCA'] == 'True': - if verbose: - print('Fitting PCA') - print("Original Length: " + str(len(feature_values[0]))) - if para_estimator['PCAType'] == '95variance': - # Select first X components that describe 95 percent of the explained variance - pca = PCA(n_components=None) - pca.fit(feature_values) - evariance = pca.explained_variance_ratio_ - num = 0 - sum = 0 - while sum < 0.95: - sum += evariance[num] - num += 1 - - # Make a PCA based on the determined amound of components - pca = PCA(n_components=num) - pca.fit(feature_values) - feature_values = pca.transform(feature_values) - - else: - # Assume a fixed number of components - n_components = int(para_estimator['PCAType']) - pca = PCA(n_components=n_components) - pca.fit(feature_values) - feature_values = pca.transform(feature_values) - - if verbose: - print("New Length: " + str(len(feature_values[0]))) - else: - pca = None - - # Delete the object if we do not need to return it - if not return_all: - del pca - - if 'UsePCA' in para_estimator.keys(): - del para_estimator['UsePCA'] - del para_estimator['PCAType'] - - # ---------------------------------------------------------------- - # Fitting and scoring - # Only when using fastr this is an entry - if 'Number' in para_estimator.keys(): - del para_estimator['Number'] - - # For certainty, we delete all parameters again - para_estimator = delete_nonestimator_parameters(para_estimator) - - # NOTE: This just has to go to the construct classifier function, - # although it is more convenient here due to the hyperparameter search - if type(y) is list: - labellength = 1 - else: - try: - labellength = y.shape[1] - except IndexError: - labellength = 1 - - if labellength > 1 and type(estimator) != RankedSVM: - # Multiclass, hence employ a multiclass classifier for e.g. SVM, RF - estimator.set_params(**para_estimator) - estimator = OneVsRestClassifier(estimator) - para_estimator = {} - - if verbose: - print("Fitting ML.") - ret = _fit_and_score(estimator, feature_values, y, - scorer, train, - test, verbose, - para_estimator, fit_params, return_train_score, - return_parameters, - return_n_test_samples, - return_times, error_score) - - # Remove 'estimator object', it's the causes of a bug. - # Somewhere between scikit-learn 0.18.2 and 0.20.2 - # the estimator object return value was added - # removing this element fixes a bug that occurs later - # in SearchCV.py, where an array without estimator - # object is expected. - del ret[-1] - - # Paste original parameters in performance - ret.append(para) - - if return_all: - return ret, GroupSel, VarSel, SelectModel, feature_labels[0], scaler, imputer, pca, StatisticalSel, ReliefSel, sm, ros - else: - return ret - - -def delete_nonestimator_parameters(parameters): - ''' - Delete all parameters in a parameter dictionary that are not used for the - actual estimator. - ''' - if 'Number' in parameters.keys(): - del parameters['Number'] - - if 'UsePCA' in parameters.keys(): - del parameters['UsePCA'] - del parameters['PCAType'] - - if 'Imputation' in parameters.keys(): - del parameters['Imputation'] - del parameters['ImputationMethod'] - del parameters['ImputationNeighbours'] - - if 'SelectFromModel' in parameters.keys(): - del parameters['SelectFromModel'] - - if 'Featsel_Variance' in parameters.keys(): - del parameters['Featsel_Variance'] - - if 'FeatureScaling' in parameters.keys(): - del parameters['FeatureScaling'] - - if 'StatisticalTestUse' in parameters.keys(): - del parameters['StatisticalTestUse'] - del parameters['StatisticalTestMetric'] - del parameters['StatisticalTestThreshold'] - - if 'SampleProcessing_SMOTE' in parameters.keys(): - del parameters['SampleProcessing_SMOTE'] - del parameters['SampleProcessing_SMOTE_ratio'] - del parameters['SampleProcessing_SMOTE_neighbors'] - del parameters['SampleProcessing_SMOTE_n_cores'] - - if 'SampleProcessing_Oversampling' in parameters.keys(): - del parameters['SampleProcessing_Oversampling'] - - return parameters - - -def replacenan(image_features, verbose=True, feature_labels=None): - ''' - Replace the NaNs in an image feature matrix. - ''' - image_features_temp = image_features.copy() - for pnum, x in enumerate(image_features_temp): - for fnum, value in enumerate(x): - if np.isnan(value): - if verbose: - if feature_labels is not None: - print("[WORC WARNING] NaN found, patient {}, label {}. Replacing with zero.").format(pnum, feature_labels[fnum]) - else: - print("[WORC WARNING] NaN found, patient {}, label {}. Replacing with zero.").format(pnum, fnum) - # Note: X is a list of lists, hence we cannot index the element directly - image_features_temp[pnum, fnum] = 0 - - return image_features_temp - - -def delete_cc_para(para): - ''' - Delete all parameters that are involved in classifier construction. - ''' - deletekeys = ['classifiers', - 'max_iter', - 'SVMKernel', - 'SVMC', - 'SVMdegree', - 'SVMcoef0', - 'SVMgamma', - 'RFn_estimators', - 'RFmin_samples_split', - 'RFmax_depth', - 'LRpenalty', - 'LRC', - 'LDA_solver', - 'LDA_shrinkage', - 'QDA_reg_param', - 'ElasticNet_alpha', - 'ElasticNet_l1_ratio', - 'SGD_alpha', - 'SGD_l1_ratio', - 'SGD_loss', - 'SGD_penalty', - 'CNB_alpha'] - - for k in deletekeys: - if k in para.keys(): - del para[k] - - return para diff --git a/build/lib/WORC/classification/metrics.py b/build/lib/WORC/classification/metrics.py deleted file mode 100644 index 3af31449..00000000 --- a/build/lib/WORC/classification/metrics.py +++ /dev/null @@ -1,293 +0,0 @@ -#!/usr/bin/env python - -# Copyright 2016-2019 Biomedical Imaging Group Rotterdam, Departments of -# Medical Informatics and Radiology, Erasmus MC, Rotterdam, The Netherlands -# -# 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. - -from __future__ import division -from sklearn.metrics import accuracy_score -from sklearn.metrics import roc_auc_score -from sklearn.metrics import confusion_matrix -from sklearn.metrics import f1_score -import numpy as np -from sklearn import metrics -from scipy.stats import pearsonr, spearmanr -from sklearn.metrics import make_scorer, average_precision_score -from sklearn.metrics import check_scoring as check_scoring_sklearn -from scipy.linalg import pinv - - -def performance_singlelabel(y_truth, y_prediction, y_score, regression=False): - ''' - Singleclass performance metrics - ''' - if regression: - r2score = metrics.r2_score(y_truth, y_prediction) - MSE = metrics.mean_squared_error(y_truth, y_prediction) - coefICC = ICC(np.column_stack((y_prediction, y_truth))) - C = pearsonr(y_prediction, y_truth) - PearsonC = C[0] - PearsonP = C[1] - C = spearmanr(y_prediction, y_truth) - SpearmanC = C.correlation - SpearmanP = C.pvalue - - return r2score, MSE, coefICC, PearsonC, PearsonP, SpearmanC, SpearmanP - - else: - # Compute confuction matrics and extract measures - c_mat = confusion_matrix(y_truth, y_prediction) - TN = c_mat[0, 0] - FN = c_mat[1, 0] - TP = c_mat[1, 1] - FP = c_mat[0, 1] - - # compute confusion metric based statistics - if FN == 0 and TP == 0: - sensitivity = 0 - else: - sensitivity = float(TP)/(TP+FN) - - if FP == 0 and TN == 0: - specificity = 0 - else: - specificity = float(TN)/(FP+TN) - - if TP == 0 and FP == 0: - precision = 0 - else: - precision = float(TP)/(TP+FP) - - if TN == 0 and FN == 0: - NPV = 0 - else: - NPV = float(TN) / (TN + FN) - - # Additionally, compute accuracy, AUC and f1-score - accuracy = accuracy_score(y_truth, y_prediction) - auc = roc_auc_score(y_truth, y_score) - f1_score_out = f1_score(y_truth, y_prediction, average='weighted') - - return accuracy, sensitivity, specificity, precision, f1_score_out, auc - - -def performance_multilabel(y_truth, y_prediction, y_score=None, beta=1): - ''' - Multiclass performance metrics. - - y_truth and y_prediction should both be lists with the multiclass label of each - object, e.g. - - y_truth = [0, 0, 0, 0, 0, 0, 2, 2, 1, 1, 2] ### Groundtruth - y_prediction = [0, 0, 0, 0, 0, 0, 1, 2, 1, 2, 2] ### Predicted labels - - - Calculation of accuracy accorading to formula suggested in CAD Dementia Grand Challege http://caddementia.grand-challenge.org - Calculation of Multi Class AUC according to classpy: https://bitbucket.org/bigr_erasmusmc/classpy/src/master/classpy/multi_class_auc.py - - ''' - cm = confusion_matrix(y_truth, y_prediction) - - # Determine no. of classes - labels_class = np.unique(y_truth) - n_class = len(labels_class) - - # Splits confusion matrix in true and false positives and negatives - TP = np.zeros(shape=(1, n_class), dtype=int) - FN = np.zeros(shape=(1, n_class), dtype=int) - FP = np.zeros(shape=(1, n_class), dtype=int) - TN = np.zeros(shape=(1, n_class), dtype=int) - n = np.zeros(shape=(1, n_class), dtype=int) - for i in range(n_class): - TP[:, i] = cm[i, i] - FN[:, i] = np.sum(cm[i, :])-cm[i, i] - FP[:, i] = np.sum(cm[:, i])-cm[i, i] - TN[:, i] = np.sum(cm[:])-TP[:, i]-FP[:, i]-FN[:, i] - n[:, i] = np.sum(cm[:, i]) - - # Calculation of accuracy accorading to formula suggested in CAD Dementia Grand Challege http://caddementia.grand-challenge.org - Accuracy = (np.sum(TP))/(np.sum(n)) - - # Determine total positives and negatives - P = TP + FN - N = FP + TN - - # Calculation of sensitivity - Sensitivity = TP/P - Sensitivity = np.mean(Sensitivity) - - # Calculation of specifitity - Specificity = TN/N - Specificity = np.mean(Specificity) - - # Calculation of precision - Precision = TP/(TP+FP) - Precision = np.nan_to_num(Precision) - Precision = np.mean(Precision) - - # Calculation of F1_Score - F1_score = ((1+(beta**2))*(Sensitivity*Precision))/((beta**2)*(Precision + Sensitivity)) - F1_score = np.nan_to_num(F1_score) - F1_score = np.mean(F1_score) - - # Calculation of Multi Class AUC according to classpy: https://bitbucket.org/bigr_erasmusmc/classpy/src/master/classpy/multi_class_auc.py - if y_score is not None: - AUC = multi_class_auc(y_truth, y_score) - else: - AUC = None - - return Accuracy, Sensitivity, Specificity, Precision, F1_score, AUC - - -def pairwise_auc(y_truth, y_score, class_i, class_j): - # Filter out the probabilities for class_i and class_j - y_score = [est[class_i] for ref, est in zip(y_truth, y_score) if ref in (class_i, class_j)] - y_truth = [ref for ref in y_truth if ref in (class_i, class_j)] - - # Sort the y_truth by the estimated probabilities - sorted_y_truth = [y for x, y in sorted(zip(y_score, y_truth), key=lambda p: p[0])] - - # Calculated the sum of ranks for class_i - sum_rank = 0 - for index, element in enumerate(sorted_y_truth): - if element == class_i: - sum_rank += index + 1 - sum_rank = float(sum_rank) - - # Get the counts for class_i and class_j - n_class_i = float(y_truth.count(class_i)) - n_class_j = float(y_truth.count(class_j)) - - # If a class in empty, AUC is 0.0 - if n_class_i == 0 or n_class_j == 0: - return 0.0 - - # Calculate the pairwise AUC - return (sum_rank - (0.5 * n_class_i * (n_class_i + 1))) / (n_class_i * n_class_j) - - -def multi_class_auc(y_truth, y_score): - classes = np.unique(y_truth) - - if any(t == 0.0 for t in np.sum(y_score, axis=1)): - raise ValueError('No AUC is calculated, output probabilities are missing') - - pairwise_auc_list = [0.5 * (pairwise_auc(y_truth, y_score, i, j) + - pairwise_auc(y_truth, y_score, j, i)) for i in classes for j in classes if i < j] - - c = len(classes) - return (2.0 * sum(pairwise_auc_list)) / (c * (c - 1)) - - -def multi_class_auc_score(y_truth, y_score): - return metrics.make_scorer(multi_class_auc, needs_proba=True) - - -def check_scoring(estimator, scoring=None, allow_none=False): - ''' - Surrogate for sklearn's check_scoring to enable use of some other - scoring metrics. - ''' - if scoring == 'average_precision_weighted': - scorer = make_scorer(average_precision_score, average='weighted') - else: - scorer = check_scoring_sklearn(estimator, scoring=scoring) - return scorer - - -def ICC(M, ICCtype='inter'): - ''' - Input: - M is matrix of observations. Rows: patients, columns: observers. - type: ICC type, currently "inter" or "intra". - ''' - - n, k = M.shape - - SStotal = np.var(M, ddof=1) * (n*k - 1) - MSR = np.var(np.mean(M, 1), ddof=1) * k - MSW = np.sum(np.var(M, 1, ddof=1)) / n - MSC = np.var(np.mean(M, 0), ddof=1) * n - MSE = (SStotal - MSR * (n - 1) - MSC * (k -1)) / ((n - 1) * (k - 1)) - - if ICCtype == 'intra': - r = (MSR - MSW) / (MSR + (k-1)*MSW) - elif ICCtype == 'inter': - r = (MSR - MSE) / (MSR + (k-1)*MSE + k*(MSC-MSE)/n) - else: - raise ValueError('No valid ICC type given.') - - return r - - -def ICC_anova(Y, ICCtype='inter', more=False): - ''' - Adopted from Nipype with a slight alteration to distinguish inter and intra. - the data Y are entered as a 'table' ie subjects are in rows and repeated - measures in columns - One Sample Repeated measure ANOVA - Y = XB + E with X = [FaTor / Subjects] - ''' - - [nb_subjects, nb_conditions] = Y.shape - dfc = nb_conditions - 1 - dfe = (nb_subjects - 1) * dfc - dfr = nb_subjects - 1 - - # Compute the repeated measure effect - # ------------------------------------ - - # Sum Square Total - mean_Y = np.mean(Y) - SST = ((Y - mean_Y) ** 2).sum() - - # create the design matrix for the different levels - x = np.kron(np.eye(nb_conditions), np.ones((nb_subjects, 1))) # sessions - x0 = np.tile(np.eye(nb_subjects), (nb_conditions, 1)) # subjects - X = np.hstack([x, x0]) - - # Sum Square Error - predicted_Y = np.dot(np.dot(np.dot(X, pinv(np.dot(X.T, X))), X.T), Y.flatten('F')) - residuals = Y.flatten('F') - predicted_Y - SSE = (residuals ** 2).sum() - - residuals.shape = Y.shape - - MSE = SSE / dfe - - # Sum square session effect - between colums/sessions - SSC = ((np.mean(Y, 0) - mean_Y) ** 2).sum() * nb_subjects - MSC = SSC / dfc / nb_subjects - - session_effect_F = MSC / MSE - - # Sum Square subject effect - between rows/subjects - SSR = SST - SSC - SSE - MSR = SSR / dfr - - # ICC(3,1) = (mean square subjeT - mean square error) / (mean square subjeT + (k-1)*-mean square error) - if ICCtype == 'intra': - ICC = (MSR - MSE) / (MSR + dfc*MSE) - elif ICCtype == 'inter': - ICC = (MSR - MSE) / (MSR + dfc*MSE + nb_conditions*(MSC-MSE)/nb_subjects) - else: - raise ValueError('No valid ICC type given.') - - e_var = MSE # variance of error - r_var = (MSR - MSE) / nb_conditions # variance between subjects - - if more: - return ICC, r_var, e_var, session_effect_F, dfc, dfe - else: - return ICC diff --git a/build/lib/WORC/classification/parameter_optimization.py b/build/lib/WORC/classification/parameter_optimization.py deleted file mode 100644 index 1a600a68..00000000 --- a/build/lib/WORC/classification/parameter_optimization.py +++ /dev/null @@ -1,88 +0,0 @@ -#!/usr/bin/env python - -# Copyright 2016-2019 Biomedical Imaging Group Rotterdam, Departments of -# Medical Informatics and Radiology, Erasmus MC, Rotterdam, The Netherlands -# -# 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 numpy as np -from sklearn.utils import check_random_state -from sklearn.model_selection import StratifiedShuffleSplit, ShuffleSplit -from WORC.classification.SearchCV import RandomizedSearchCVfastr, RandomizedSearchCVJoblib - - -def random_search_parameters(features, labels, N_iter, test_size, - param_grid, scoring_method, - n_jobspercore=200, use_fastr=False, - n_cores=1, fastr_plugin=None): - """ - Train a classifier and simultaneously optimizes hyperparameters using a - randomized search. - - Arguments: - features: numpy array containing the training features. - labels: list containing the object labels to be trained on. - N_iter: integer listing the number of iterations to be used in the - hyperparameter optimization. - test_size: float listing the test size percentage used in the cross - validation. - classifier: sklearn classifier to be tested - param_grid: dictionary containing all possible hyperparameters and their - values or distrubitions. - scoring_method: string defining scoring method used in optimization, - e.g. f1_weighted for a SVM. - n_jobsperscore: integer listing the number of jobs that are ran on a - single core when using the fastr randomized search. - use_fastr: Boolean determining of either fastr or joblib should be used - for the opimization. - fastr_plugin: determines which plugin is used for fastr executions. - When None, uses the default plugin from the fastr config. - - Returns: - random_search: sklearn randomsearch object containing the results. - """ - - random_seed = np.random.randint(1, 5000) - random_state = check_random_state(random_seed) - - regressors = ['SVR', 'RFR', 'SGDR', 'Lasso', 'ElasticNet'] - if any(clf in regressors for clf in param_grid['classifiers']): - # We cannot do a stratified shuffle split with regression - cv = ShuffleSplit(n_splits=5, test_size=test_size, - random_state=random_state) - else: - cv = StratifiedShuffleSplit(n_splits=5, test_size=test_size, - random_state=random_state) - - if use_fastr: - random_search = RandomizedSearchCVfastr(param_distributions=param_grid, - n_iter=N_iter, - scoring=scoring_method, - n_jobs=n_cores, - n_jobspercore=n_jobspercore, - verbose=1, cv=cv, - fastr_plugin=fastr_plugin) - else: - random_search = RandomizedSearchCVJoblib(param_distributions=param_grid, - n_iter=N_iter, - scoring=scoring_method, - n_jobs=n_cores, - verbose=1, cv=cv) - random_search.fit(features, labels) - print("Best found parameters:") - for i in random_search.best_params_: - print(f'{i}: {random_search.best_params_[i]}.') - print("\n Best score using best parameters:") - print(random_search.best_score_) - - return random_search diff --git a/build/lib/WORC/classification/trainclassifier.py b/build/lib/WORC/classification/trainclassifier.py deleted file mode 100644 index 5b784756..00000000 --- a/build/lib/WORC/classification/trainclassifier.py +++ /dev/null @@ -1,326 +0,0 @@ -#!/usr/bin/env python - -# Copyright 2016-2019 Biomedical Imaging Group Rotterdam, Departments of -# Medical Informatics and Radiology, Erasmus MC, Rotterdam, The Netherlands -# -# 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 json -import os -import sklearn - -from WORC.classification import crossval as cv -from WORC.classification import construct_classifier as cc -from WORC.plotting.plot_SVM import plot_SVM -from WORC.plotting.plot_SVR import plot_single_SVR -import WORC.IOparser.file_io as file_io -import WORC.IOparser.config_io_classifier as config_io -from scipy.stats import uniform -from WORC.classification.AdvancedSampler import discrete_uniform - - -def trainclassifier(feat_train, patientinfo_train, config, - output_hdf, output_json, - feat_test=None, patientinfo_test=None, - fixedsplits=None, verbose=True): - ''' - Train a classifier using machine learning from features. By default, if no - split in training and test is supplied, a cross validation - will be performed. - - Parameters - ---------- - feat_train: string, mandatory - contains the paths to all .hdf5 feature files used. - modalityname1=file1,file2,file3,... modalityname2=file1,... - Thus, modalities names are always between a space and a equal - sign, files are split by commas. We assume that the lists of - files for each modality has the same length. Files on the - same position on each list should belong to the same patient. - - patientinfo: string, mandatory - Contains the path referring to a .txt file containing the - patient label(s) and value(s) to be used for learning. See - the Github Wiki for the format. - - config: string, mandatory - path referring to a .ini file containing the parameters - used for feature extraction. See the Github Wiki for the possible - fields and their description. - - output_hdf: string, mandatory - path refering to a .hdf5 file to which the final classifier and - it's properties will be written to. - - output_json: string, mandatory - path refering to a .json file to which the performance of the final - classifier will be written to. This file is generated through one of - the WORC plotting functions. - - feat_test: string, optional - When this argument is supplied, the machine learning will not be - trained using a cross validation, but rather using a fixed training - and text split. This field should contain paths of the test set - feature files, similar to the feat_train argument. - - patientinfo_test: string, optional - When feat_test is supplied, you can supply optionally a patient label - file through which the performance will be evaluated. - - fixedsplits: string, optional - By default, random split cross validation is used to train and - evaluate the machine learning methods. Optionally, you can provide - a .xlsx file containing fixed splits to be used. See the Github Wiki - for the format. - - verbose: boolean, default True - print final feature values and labels to command line or not. - - ''' - - # Convert inputs from lists to strings - if type(patientinfo_train) is list: - patientinfo_train = ''.join(patientinfo_train) - - if type(patientinfo_test) is list: - patientinfo_test = ''.join(patientinfo_test) - - if type(config) is list: - if len(config) == 1: - config = ''.join(config) - else: - # FIXME - print('[WORC Warning] You provided multiple configuration files: only the first one will be used!') - config = config[0] - - if type(output_hdf) is list: - if len(output_hdf) == 1: - output_hdf = ''.join(output_hdf) - else: - # FIXME - print('[WORC Warning] You provided multiple output hdf files: only the first one will be used!') - output_hdf = output_hdf[0] - - if type(output_json) is list: - if len(output_json) == 1: - output_json = ''.join(output_json) - else: - # FIXME - print('[WORC Warning] You provided multiple output json files: only the first one will be used!') - output_json = output_json[0] - - # Load variables from the config file - config = config_io.load_config(config) - label_type = config['Labels']['label_names'] - modus = config['Labels']['modus'] - - # Load the feature files and match to label data - label_data_train, image_features_train =\ - load_features(feat_train, patientinfo_train, label_type) - - if feat_test: - label_data_test, image_features_test =\ - load_features(feat_test, patientinfo_test, label_type) - - # Create tempdir name from patientinfo file name - basename = os.path.basename(patientinfo_train) - filename, _ = os.path.splitext(basename) - path = patientinfo_train - for i in range(4): - # Use temp dir: result -> sample# -> parameters - > temppath - path = os.path.dirname(path) - - _, path = os.path.split(path) - path = os.path.join(path, 'trainclassifier', filename) - - # Construct the required classifier grid - param_grid = cc.create_param_grid(config) - - # IF at least once groupwise search is turned on, add it to the param grid - if 'True'in config['Featsel']['GroupwiseSearch']: - param_grid['SelectGroups'] = config['Featsel']['GroupwiseSearch'] - for group in config['SelectFeatGroup'].keys(): - param_grid[group] = config['SelectFeatGroup'][group] - - # If scaling is to be applied, add to parameters - if config['FeatureScaling']['scale_features']: - if type(config['FeatureScaling']['scaling_method']) is not list: - param_grid['FeatureScaling'] = [config['FeatureScaling']['scaling_method']] - else: - param_grid['FeatureScaling'] = config['FeatureScaling']['scaling_method'] - - # Add parameters for oversampling methods - param_grid['SampleProcessing_SMOTE'] = config['SampleProcessing']['SMOTE'] - param_grid['SampleProcessing_SMOTE_ratio'] =\ - uniform(loc=config['SampleProcessing']['SMOTE_ratio'][0], - scale=config['SampleProcessing']['SMOTE_ratio'][1]) - param_grid['SampleProcessing_SMOTE_neighbors'] =\ - discrete_uniform(loc=config['SampleProcessing']['SMOTE_neighbors'][0], - scale=config['SampleProcessing']['SMOTE_neighbors'][1]) - param_grid['SampleProcessing_SMOTE_n_cores'] = [config['General']['Joblib_ncores']] - param_grid['SampleProcessing_Oversampling'] = config['SampleProcessing']['Oversampling'] - - # Extract hyperparameter grid settings for SearchCV from config - param_grid['Featsel_Variance'] = config['Featsel']['Variance'] - - param_grid['Imputation'] = config['Imputation']['use'] - param_grid['ImputationMethod'] = config['Imputation']['strategy'] - param_grid['ImputationNeighbours'] =\ - discrete_uniform(loc=config['Imputation']['n_neighbors'][0], - scale=config['Imputation']['n_neighbors'][1]) - - param_grid['SelectFromModel'] = config['Featsel']['SelectFromModel'] - - param_grid['UsePCA'] = config['Featsel']['UsePCA'] - param_grid['PCAType'] = config['Featsel']['PCAType'] - - param_grid['StatisticalTestUse'] =\ - config['Featsel']['StatisticalTestUse'] - param_grid['StatisticalTestMetric'] =\ - config['Featsel']['StatisticalTestMetric'] - param_grid['StatisticalTestThreshold'] =\ - uniform(loc=config['Featsel']['StatisticalTestThreshold'][0], - scale=config['Featsel']['StatisticalTestThreshold'][1]) - - param_grid['ReliefUse'] =\ - config['Featsel']['ReliefUse'] - - param_grid['ReliefNN'] =\ - discrete_uniform(loc=config['Featsel']['ReliefNN'][0], - scale=config['Featsel']['ReliefNN'][1]) - - param_grid['ReliefSampleSize'] =\ - discrete_uniform(loc=config['Featsel']['ReliefSampleSize'][0], - scale=config['Featsel']['ReliefSampleSize'][1]) - - param_grid['ReliefDistanceP'] =\ - discrete_uniform(loc=config['Featsel']['ReliefDistanceP'][0], - scale=config['Featsel']['ReliefDistanceP'][1]) - - param_grid['ReliefNumFeatures'] =\ - discrete_uniform(loc=config['Featsel']['ReliefNumFeatures'][0], - scale=config['Featsel']['ReliefNumFeatures'][1]) - - # For N_iter, perform k-fold crossvalidation - outputfolder = os.path.dirname(output_hdf) - if feat_test is None: - trained_classifier = cv.crossval(config, label_data_train, - image_features_train, - param_grid, - modus=modus, - use_fastr=config['Classification']['fastr'], - fastr_plugin=config['Classification']['fastr_plugin'], - fixedsplits=fixedsplits, - ensemble=config['Ensemble'], - outputfolder=outputfolder, - tempsave=config['General']['tempsave']) - else: - trained_classifier = cv.nocrossval(config, label_data_train, - label_data_test, - image_features_train, - image_features_test, - param_grid, - modus=modus, - use_fastr=config['Classification']['fastr'], - fastr_plugin=config['Classification']['fastr_plugin'], - ensemble=config['Ensemble']) - - if not os.path.exists(os.path.dirname(output_hdf)): - os.makedirs(os.path.dirname(output_hdf)) - - trained_classifier.to_hdf(output_hdf, 'SVMdata') - - # Check whether we do regression or classification - regressors = ['SVR', 'RFR', 'SGDR', 'Lasso', 'ElasticNet'] - isclassifier =\ - not any(clf in regressors for clf in config['Classification']['classifiers']) - - # Calculate statistics of performance - if feat_test is None: - if not isclassifier: - statistics = plot_single_SVR(trained_classifier, label_data_train, - label_type) - else: - statistics = plot_SVM(trained_classifier, label_data_train, - label_type, modus=modus) - else: - if patientinfo_test is not None: - if not isclassifier: - statistics = plot_single_SVR(trained_classifier, - label_data_test, - label_type) - else: - statistics = plot_SVM(trained_classifier, - label_data_test, - label_type, - modus=modus) - else: - statistics = None - - # Save output - savedict = dict() - savedict["Statistics"] = statistics - - if not os.path.exists(os.path.dirname(output_json)): - os.makedirs(os.path.dirname(output_json)) - - with open(output_json, 'w') as fp: - json.dump(savedict, fp, indent=4) - - print("Saved data!") - - -def load_features(feat, patientinfo, label_type): - ''' Read feature files and stack the features per patient in an array. - Additionally, if a patient label file is supplied, the features from - a patient will be matched to the labels. - - Parameters - ---------- - featurefiles: list, mandatory - List containing all paths to the .hdf5 feature files to be loaded. - The argument should contain a list per modelity, e.g. - [[features_mod1_patient1, features_mod1_patient2, ...], - [features_mod2_patient1, features_mod2_patient2, ...]]. - - patientinfo: string, optional - Path referring to the .txt file to be used to read patient - labels from. See the Github Wiki for the format. - - label_names: list, optional - List containing all the labels that should be extracted from - the patientinfo file. - - ''' - # Split the feature files per modality - feat_temp = list() - modnames = list() - for feat_mod in feat: - feat_mod_temp = [str(item).strip() for item in feat_mod.split(',')] - - # The first item contains the name of the modality, followed by a = sign - temp = [str(item).strip() for item in feat_mod_temp[0].split('=')] - modnames.append(temp[0]) - feat_mod_temp[0] = temp[1] - - # Append the files to the main list - feat_temp.append(feat_mod_temp) - - feat = feat_temp - - # Read the features and classification data - label_data, image_features =\ - file_io.load_data(feat, patientinfo, - label_type, modnames) - - return label_data, image_features diff --git a/build/lib/WORC/doc/Makefile b/build/lib/WORC/doc/Makefile deleted file mode 100644 index 99f77e53..00000000 --- a/build/lib/WORC/doc/Makefile +++ /dev/null @@ -1,130 +0,0 @@ -# Makefile for Sphinx documentation -# - -# You can set these variables from the command line. -SPHINXOPTS = -SPHINXBUILD = sphinx-build -PAPER = -BUILDDIR = _build - -# Internal variables. -PAPEROPT_a4 = -D latex_paper_size=a4 -PAPEROPT_letter = -D latex_paper_size=letter -ALLSPHINXOPTS = -d $(BUILDDIR)/doctrees $(PAPEROPT_$(PAPER)) $(SPHINXOPTS) . - -.PHONY: help clean html dirhtml singlehtml pickle json htmlhelp qthelp devhelp epub latex latexpdf text man changes linkcheck doctest - -help: - @echo "Please use \`make ' where is one of" - @echo " html to make standalone HTML files" - @echo " dirhtml to make HTML files named index.html in directories" - @echo " singlehtml to make a single large HTML file" - @echo " pickle to make pickle files" - @echo " json to make JSON files" - @echo " htmlhelp to make HTML files and a HTML help project" - @echo " qthelp to make HTML files and a qthelp project" - @echo " devhelp to make HTML files and a Devhelp project" - @echo " epub to make an epub" - @echo " latex to make LaTeX files, you can set PAPER=a4 or PAPER=letter" - @echo " latexpdf to make LaTeX files and run them through pdflatex" - @echo " text to make text files" - @echo " man to make manual pages" - @echo " changes to make an overview of all changed/added/deprecated items" - @echo " linkcheck to check all external links for integrity" - @echo " doctest to run all doctests embedded in the documentation (if enabled)" - -clean: - -rm -rf $(BUILDDIR)/* - -html: - $(SPHINXBUILD) -b html $(ALLSPHINXOPTS) $(BUILDDIR)/html - @echo - @echo "Build finished. The HTML pages are in $(BUILDDIR)/html." - -dirhtml: - $(SPHINXBUILD) -b dirhtml $(ALLSPHINXOPTS) $(BUILDDIR)/dirhtml - @echo - @echo "Build finished. The HTML pages are in $(BUILDDIR)/dirhtml." - -singlehtml: - $(SPHINXBUILD) -b singlehtml $(ALLSPHINXOPTS) $(BUILDDIR)/singlehtml - @echo - @echo "Build finished. The HTML page is in $(BUILDDIR)/singlehtml." - -pickle: - $(SPHINXBUILD) -b pickle $(ALLSPHINXOPTS) $(BUILDDIR)/pickle - @echo - @echo "Build finished; now you can process the pickle files." - -json: - $(SPHINXBUILD) -b json $(ALLSPHINXOPTS) $(BUILDDIR)/json - @echo - @echo "Build finished; now you can process the JSON files." - -htmlhelp: - $(SPHINXBUILD) -b htmlhelp $(ALLSPHINXOPTS) $(BUILDDIR)/htmlhelp - @echo - @echo "Build finished; now you can run HTML Help Workshop with the" \ - ".hhp project file in $(BUILDDIR)/htmlhelp." - -qthelp: - $(SPHINXBUILD) -b qthelp $(ALLSPHINXOPTS) $(BUILDDIR)/qthelp - @echo - @echo "Build finished; now you can run "qcollectiongenerator" with the" \ - ".qhcp project file in $(BUILDDIR)/qthelp, like this:" - @echo "# qcollectiongenerator $(BUILDDIR)/qthelp/BIGR-FAST.qhcp" - @echo "To view the help file:" - @echo "# assistant -collectionFile $(BUILDDIR)/qthelp/BIGR-FAST.qhc" - -devhelp: - $(SPHINXBUILD) -b devhelp $(ALLSPHINXOPTS) $(BUILDDIR)/devhelp - @echo - @echo "Build finished." - @echo "To view the help file:" - @echo "# mkdir -p $$HOME/.local/share/devhelp/BIGR-FAST" - @echo "# ln -s $(BUILDDIR)/devhelp $$HOME/.local/share/devhelp/BIGR-FAST" - @echo "# devhelp" - -epub: - $(SPHINXBUILD) -b epub $(ALLSPHINXOPTS) $(BUILDDIR)/epub - @echo - @echo "Build finished. The epub file is in $(BUILDDIR)/epub." - -latex: - $(SPHINXBUILD) -b latex $(ALLSPHINXOPTS) $(BUILDDIR)/latex - @echo - @echo "Build finished; the LaTeX files are in $(BUILDDIR)/latex." - @echo "Run \`make' in that directory to run these through (pdf)latex" \ - "(use \`make latexpdf' here to do that automatically)." - -latexpdf: - $(SPHINXBUILD) -b latex $(ALLSPHINXOPTS) $(BUILDDIR)/latex - @echo "Running LaTeX files through pdflatex..." - make -C $(BUILDDIR)/latex all-pdf - @echo "pdflatex finished; the PDF files are in $(BUILDDIR)/latex." - -text: - $(SPHINXBUILD) -b text $(ALLSPHINXOPTS) $(BUILDDIR)/text - @echo - @echo "Build finished. The text files are in $(BUILDDIR)/text." - -man: - $(SPHINXBUILD) -b man $(ALLSPHINXOPTS) $(BUILDDIR)/man - @echo - @echo "Build finished. The manual pages are in $(BUILDDIR)/man." - -changes: - $(SPHINXBUILD) -b changes $(ALLSPHINXOPTS) $(BUILDDIR)/changes - @echo - @echo "The overview file is in $(BUILDDIR)/changes." - -linkcheck: - $(SPHINXBUILD) -b linkcheck $(ALLSPHINXOPTS) $(BUILDDIR)/linkcheck - @echo - @echo "Link check complete; look for any errors in the above output " \ - "or in $(BUILDDIR)/linkcheck/output.txt." - -doctest: - $(SPHINXBUILD) -b doctest $(ALLSPHINXOPTS) $(BUILDDIR)/doctest - @echo "Testing of doctests in the sources finished, look at the " \ - "results in $(BUILDDIR)/doctest/output.txt." diff --git a/build/lib/WORC/doc/README b/build/lib/WORC/doc/README deleted file mode 100644 index 1048afac..00000000 --- a/build/lib/WORC/doc/README +++ /dev/null @@ -1,10 +0,0 @@ -This readme explains how to generate the docs. - -There are two scripts you may need: doc_generate.py and doc_clean.py -- doc_generate.py -This script calls the generate_modules.py script to generate the documentation of the complete bigr-fastr package family. Before doing this all *.rst are removed with doc_clean.py. -After cleaning and creating the rst files, `make html` is called which generates the html output in ./_build/html. - -- doc_clean.py -This script basically removes all *.rst files from this directory. - diff --git a/build/lib/WORC/doc/__placeholder__ b/build/lib/WORC/doc/__placeholder__ deleted file mode 100644 index e69de29b..00000000 diff --git a/build/lib/WORC/doc/_build/doctrees/autogen/WORC.IOparser.doctree b/build/lib/WORC/doc/_build/doctrees/autogen/WORC.IOparser.doctree deleted file mode 100644 index 144d0b3a..00000000 Binary files a/build/lib/WORC/doc/_build/doctrees/autogen/WORC.IOparser.doctree and /dev/null differ diff --git a/build/lib/WORC/doc/_build/doctrees/autogen/WORC.classification.doctree b/build/lib/WORC/doc/_build/doctrees/autogen/WORC.classification.doctree deleted file mode 100644 index e9eb4275..00000000 Binary files a/build/lib/WORC/doc/_build/doctrees/autogen/WORC.classification.doctree and /dev/null differ diff --git a/build/lib/WORC/doc/_build/doctrees/autogen/WORC.doctree b/build/lib/WORC/doc/_build/doctrees/autogen/WORC.doctree deleted file mode 100644 index abde9ab4..00000000 Binary files a/build/lib/WORC/doc/_build/doctrees/autogen/WORC.doctree and /dev/null differ diff --git a/build/lib/WORC/doc/_build/doctrees/autogen/WORC.featureprocessing.doctree b/build/lib/WORC/doc/_build/doctrees/autogen/WORC.featureprocessing.doctree deleted file mode 100644 index 144f1f7f..00000000 Binary files a/build/lib/WORC/doc/_build/doctrees/autogen/WORC.featureprocessing.doctree and /dev/null differ diff --git a/build/lib/WORC/doc/_build/doctrees/autogen/WORC.plotting.doctree b/build/lib/WORC/doc/_build/doctrees/autogen/WORC.plotting.doctree deleted file mode 100644 index ba08584c..00000000 Binary files a/build/lib/WORC/doc/_build/doctrees/autogen/WORC.plotting.doctree and /dev/null differ diff --git a/build/lib/WORC/doc/_build/doctrees/autogen/WORC.processing.doctree b/build/lib/WORC/doc/_build/doctrees/autogen/WORC.processing.doctree deleted file mode 100644 index c2828745..00000000 Binary files a/build/lib/WORC/doc/_build/doctrees/autogen/WORC.processing.doctree and /dev/null differ diff --git a/build/lib/WORC/doc/_build/doctrees/autogen/WORC.resources.fastr_tests.doctree b/build/lib/WORC/doc/_build/doctrees/autogen/WORC.resources.fastr_tests.doctree deleted file mode 100644 index 4af21a7e..00000000 Binary files a/build/lib/WORC/doc/_build/doctrees/autogen/WORC.resources.fastr_tests.doctree and /dev/null differ diff --git a/build/lib/WORC/doc/_build/doctrees/autogen/WORC.tools.doctree b/build/lib/WORC/doc/_build/doctrees/autogen/WORC.tools.doctree deleted file mode 100644 index 2e070ec8..00000000 Binary files a/build/lib/WORC/doc/_build/doctrees/autogen/WORC.tools.doctree and /dev/null differ diff --git a/build/lib/WORC/doc/_build/doctrees/environment.pickle b/build/lib/WORC/doc/_build/doctrees/environment.pickle deleted file mode 100644 index bed3fc86..00000000 Binary files a/build/lib/WORC/doc/_build/doctrees/environment.pickle and /dev/null differ diff --git a/build/lib/WORC/doc/_build/doctrees/index.doctree b/build/lib/WORC/doc/_build/doctrees/index.doctree deleted file mode 100644 index 7b423f22..00000000 Binary files a/build/lib/WORC/doc/_build/doctrees/index.doctree and /dev/null differ diff --git a/build/lib/WORC/doc/_build/doctrees/static/changelog.doctree b/build/lib/WORC/doc/_build/doctrees/static/changelog.doctree deleted file mode 100644 index 3a568d1b..00000000 Binary files a/build/lib/WORC/doc/_build/doctrees/static/changelog.doctree and /dev/null differ diff --git a/build/lib/WORC/doc/_build/doctrees/static/configuration.doctree b/build/lib/WORC/doc/_build/doctrees/static/configuration.doctree deleted file mode 100644 index 9e13f773..00000000 Binary files a/build/lib/WORC/doc/_build/doctrees/static/configuration.doctree and /dev/null differ diff --git a/build/lib/WORC/doc/_build/doctrees/static/development.doctree b/build/lib/WORC/doc/_build/doctrees/static/development.doctree deleted file mode 100644 index 1e2122df..00000000 Binary files a/build/lib/WORC/doc/_build/doctrees/static/development.doctree and /dev/null differ diff --git a/build/lib/WORC/doc/_build/doctrees/static/file_description.doctree b/build/lib/WORC/doc/_build/doctrees/static/file_description.doctree deleted file mode 100644 index b4bdbd41..00000000 Binary files a/build/lib/WORC/doc/_build/doctrees/static/file_description.doctree and /dev/null differ diff --git a/build/lib/WORC/doc/_build/doctrees/static/introduction.doctree b/build/lib/WORC/doc/_build/doctrees/static/introduction.doctree deleted file mode 100644 index 1be86cf6..00000000 Binary files a/build/lib/WORC/doc/_build/doctrees/static/introduction.doctree and /dev/null differ diff --git a/build/lib/WORC/doc/_build/doctrees/static/quick_start.doctree b/build/lib/WORC/doc/_build/doctrees/static/quick_start.doctree deleted file mode 100644 index e140196c..00000000 Binary files a/build/lib/WORC/doc/_build/doctrees/static/quick_start.doctree and /dev/null differ diff --git a/build/lib/WORC/doc/_build/doctrees/static/reference.doctree b/build/lib/WORC/doc/_build/doctrees/static/reference.doctree deleted file mode 100644 index 61e89750..00000000 Binary files a/build/lib/WORC/doc/_build/doctrees/static/reference.doctree and /dev/null differ diff --git a/build/lib/WORC/doc/_build/doctrees/static/tools.doctree b/build/lib/WORC/doc/_build/doctrees/static/tools.doctree deleted file mode 100644 index 4a6da9c5..00000000 Binary files a/build/lib/WORC/doc/_build/doctrees/static/tools.doctree and /dev/null differ diff --git a/build/lib/WORC/doc/_build/doctrees/static/user_manual.doctree b/build/lib/WORC/doc/_build/doctrees/static/user_manual.doctree deleted file mode 100644 index f7dbe551..00000000 Binary files a/build/lib/WORC/doc/_build/doctrees/static/user_manual.doctree and /dev/null differ diff --git a/build/lib/WORC/doc/_build/doctrees/user_reference/user_reference.doctree b/build/lib/WORC/doc/_build/doctrees/user_reference/user_reference.doctree deleted file mode 100644 index 3ed68111..00000000 Binary files a/build/lib/WORC/doc/_build/doctrees/user_reference/user_reference.doctree and /dev/null differ diff --git a/build/lib/WORC/doc/_build/html/.buildinfo b/build/lib/WORC/doc/_build/html/.buildinfo deleted file mode 100644 index 866db818..00000000 --- a/build/lib/WORC/doc/_build/html/.buildinfo +++ /dev/null @@ -1,4 +0,0 @@ -# Sphinx build info version 1 -# This file hashes the configuration used when building these files. When it is not found, a full rebuild will be done. -config: b0849071a31325117937fe1500f9c73f -tags: 645f666f9bcd5a90fca523b33c5a78b7 diff --git a/build/lib/WORC/doc/_build/html/_images/CASH.png b/build/lib/WORC/doc/_build/html/_images/CASH.png deleted file mode 100644 index 064f3e63..00000000 Binary files a/build/lib/WORC/doc/_build/html/_images/CASH.png and /dev/null differ diff --git a/build/lib/WORC/doc/_build/html/_images/RadiomicsSteps.png b/build/lib/WORC/doc/_build/html/_images/RadiomicsSteps.png deleted file mode 100644 index 2c3fbe25..00000000 Binary files a/build/lib/WORC/doc/_build/html/_images/RadiomicsSteps.png and /dev/null differ diff --git a/build/lib/WORC/doc/_build/html/_images/WORC_small.png b/build/lib/WORC/doc/_build/html/_images/WORC_small.png deleted file mode 100644 index 5a2623f5..00000000 Binary files a/build/lib/WORC/doc/_build/html/_images/WORC_small.png and /dev/null differ diff --git a/build/lib/WORC/doc/_build/html/_images/datatype_diagram.svg b/build/lib/WORC/doc/_build/html/_images/datatype_diagram.svg deleted file mode 100644 index 6624b7cf..00000000 --- a/build/lib/WORC/doc/_build/html/_images/datatype_diagram.svg +++ /dev/null @@ -1,1667 +0,0 @@ - - - - - - image/svg+xml - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - fastr.core.serializable.Serializable - - - fastr.core.serializable.Serializable - - - - - - - - - - - - - - - - - - - - - - fastr.plugins.managers.datatypemanager.ValueType - - - fastr.plugins.managers.datatypemanager.ValueType - - - - - - - - - - - - - - - - - - - - - - fastr.plugins.managers.datatypemanager.URLType - - - fastr.plugins.managers.datatypemanager.URLType - - - - - - - - - - - - - - - - - - - - - - fastr.plugins.managers.datatypemanager.TypeGroup - - - fastr.plugins.managers.datatypemanager.TypeGroup - - - - - - - - - - - - - - - - - - - - - - fastr.plugins.managers.datatypemanager.DataType - - - fastr.plugins.managers.datatypemanager.DataType - - - - - - - - - - - - - - - - - - - - - - fastr.plugins.managers.datatypemanager.BaseDataType - - - fastr.plugins.managers.datatypemanager.BaseDataType - - - - - - - - - - - - - - - - - - - - - - fastr.plugins.managers.datatypemanager.EnumType - - - fastr.plugins.managers.datatypemanager.EnumType - - - - - - - - - - - - - - - - - - diff --git a/build/lib/WORC/doc/_build/html/_images/flow_broadcast.svg b/build/lib/WORC/doc/_build/html/_images/flow_broadcast.svg deleted file mode 100644 index 29120978..00000000 --- a/build/lib/WORC/doc/_build/html/_images/flow_broadcast.svg +++ /dev/null @@ -1,1338 +0,0 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - image/svg+xml - - - - - - - - - - - (im0) - - - - (im1) - - - - (im2) - - - - (im3) - - - dim_moving - - - dim_fixed - dim_moving - - - - - (tf0,m0,p0) - - - - (tf1,m0,p0) - - - - (tf2,m0,p0) - - - - - - (tf0,m1,p0) - - - - (tf1,m1,p0) - - - - (tf2,m1,p0) - - - - - - (tf0,m2,p0) - - - - (tf1,m2,p0) - - - - (tf2,m2,p0) - - - - - - (tf0,m3,p0) - - - - (tf1,m3,p0) - - - - (tf2,m3,p0) - - - - - - dim_fixed - dim_moving - - - - - (if0,m0,p0) - - - - (if1,m0,p0) - - - - (if2,m0,p0) - - - - - - (if0,m1,p0) - - - - (if1,m1,p0) - - - - (if2,m1,p0) - - - - - - (if0,m2,p0) - - - - (if1,m2,p0) - - - - (if2,m2,p0) - - - - - - (if0,m3,p0) - - - - (if1,m3,p0) - - - - (if2,m3,p0) - - - - - - - (p0) - - - - - - - - - - - (m0) - - - - (m1) - - - - (m2) - - - - (m3) - - - dim_moving - - - - - - (f0) - - - - (f1) - - - - (f2) - - - dim_fixed - - - NodeRun: elastix - - NodeRun: transformix - - diff --git a/build/lib/WORC/doc/_build/html/_images/flow_collapse.svg b/build/lib/WORC/doc/_build/html/_images/flow_collapse.svg deleted file mode 100644 index 265b7f2f..00000000 --- a/build/lib/WORC/doc/_build/html/_images/flow_collapse.svg +++ /dev/null @@ -1,363 +0,0 @@ - - - - - - - - - - - - - - - - image/svg+xml - - - - - - - - - - (a0) - - - - (b0) - - - - (c0) - - - - - - - - (b1) - - - - (c1) - - dim1 - dim2 - - - - - (a0 ,b0, c0) - - - - (b1, c1) - - dim2 - - - - collapse(dim1) - - - diff --git a/build/lib/WORC/doc/_build/html/_images/flow_cross_three_sample.svg b/build/lib/WORC/doc/_build/html/_images/flow_cross_three_sample.svg deleted file mode 100644 index 512b05cb..00000000 --- a/build/lib/WORC/doc/_build/html/_images/flow_cross_three_sample.svg +++ /dev/null @@ -1,700 +0,0 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - image/svg+xml - - - - - - - - - (p0) - - - - results in - - - - - (f0) - - - - (f1) - - - - (f2) - - - - - (m0) - - - - (m1) - - - - (m2) - - - - - - - - - (m3) - - - - - (tf0,m0,p0) - - - - (tf1,m0,p0) - - - - (tf2,m0,p0) - - - - - - (tf0,m1,p0) - - - - (tf1,m1,p0) - - - - (tf2,m1,p0) - - - - - - (tf0,m2,p0) - - - - (tf1,m2,p0) - - - - (tf2,m2,p0) - - - - - - (tf0,m3,p0) - - - - (tf1,m3,p0) - - - - (tf2,m3,p0) - - - - diff --git a/build/lib/WORC/doc/_build/html/_images/flow_expand.svg b/build/lib/WORC/doc/_build/html/_images/flow_expand.svg deleted file mode 100644 index 661deff5..00000000 --- a/build/lib/WORC/doc/_build/html/_images/flow_expand.svg +++ /dev/null @@ -1,379 +0,0 @@ - - - - - - - - - - - - - - - - image/svg+xml - - - - - - - - - - (a0) - - - - (b0, b1) - - - - (c0, c1) - - dim1 - - - - - (a0) - - - - (b0) - - - - (c0) - - - - - - - - (b1) - - - - (c1) - - dim1 - dim2 - - - - expand - - - diff --git a/build/lib/WORC/doc/_build/html/_images/flow_expand_collapse.svg b/build/lib/WORC/doc/_build/html/_images/flow_expand_collapse.svg deleted file mode 100644 index 81d995d8..00000000 --- a/build/lib/WORC/doc/_build/html/_images/flow_expand_collapse.svg +++ /dev/null @@ -1,301 +0,0 @@ - - - - - - - - - - - - - - - - - - - image/svg+xml - - - - - - - - - - (a0) - - - - (b0, b1) - - - - (c0, c1) - - dim1 - - - - - (a0 ,b0, c0) - - - - (b1, c1) - - dim2 - - expand & - - collapse(dim1) - - diff --git a/build/lib/WORC/doc/_build/html/_images/flow_simple_one_sample.svg b/build/lib/WORC/doc/_build/html/_images/flow_simple_one_sample.svg deleted file mode 100644 index b8e78a64..00000000 --- a/build/lib/WORC/doc/_build/html/_images/flow_simple_one_sample.svg +++ /dev/null @@ -1,210 +0,0 @@ - - - - - - - - - - - - - - - - - image/svg+xml - - - - - - - - - (f0) - - - - (m0) - - - - (p0) - - - (tf0,m0,p0) - - - results in - - - diff --git a/build/lib/WORC/doc/_build/html/_images/flow_simple_one_sample_two_cardinality.svg b/build/lib/WORC/doc/_build/html/_images/flow_simple_one_sample_two_cardinality.svg deleted file mode 100644 index 3e36e7d6..00000000 --- a/build/lib/WORC/doc/_build/html/_images/flow_simple_one_sample_two_cardinality.svg +++ /dev/null @@ -1,214 +0,0 @@ - - - - - - - - - - - - - - - - - image/svg+xml - - - - - - - - - (f0) - - - - (m0) - - - - (p0, p1) - - - (tf0,m0,p0, tt0,m0,p1) - - - results in - - - diff --git a/build/lib/WORC/doc/_build/html/_images/flow_simple_three_sample.svg b/build/lib/WORC/doc/_build/html/_images/flow_simple_three_sample.svg deleted file mode 100644 index f17bb03b..00000000 --- a/build/lib/WORC/doc/_build/html/_images/flow_simple_three_sample.svg +++ /dev/null @@ -1,345 +0,0 @@ - - - - - - - - - - - - - - - - - - - - image/svg+xml - - - - - - - - - - (p0) - - - - results in - - - - - (f0) - - - - (f1) - - - - (f2) - - - - - - (m0) - - - - - - (tf0,m0,p0) - - - - (tf1,m0,p0) - - - - (tf2,m0,p0) - - - - - diff --git a/build/lib/WORC/doc/_build/html/_images/flow_simple_three_sample_two_cardinality.svg b/build/lib/WORC/doc/_build/html/_images/flow_simple_three_sample_two_cardinality.svg deleted file mode 100644 index 169572bc..00000000 --- a/build/lib/WORC/doc/_build/html/_images/flow_simple_three_sample_two_cardinality.svg +++ /dev/null @@ -1,411 +0,0 @@ - - - - - - - - - - - - - - - - - - - - - - - image/svg+xml - - - - - - - - - - (p0, p1) - - - - results in - - - - - (f0) - - - - (f1) - - - - (f2) - - - - - - (m0) - - - - (m1) - - - - (m2) - - - - - (tf0,m0,p0, tf0,m0,p1) - - (tf1,m1,p0, tf1,m1,p1) - - (tf2,m2,p0, tf2,m2,p1) - - - - diff --git a/build/lib/WORC/doc/_build/html/_images/network1.svg b/build/lib/WORC/doc/_build/html/_images/network1.svg deleted file mode 100644 index 6dfbcb26..00000000 --- a/build/lib/WORC/doc/_build/html/_images/network1.svg +++ /dev/null @@ -1,64 +0,0 @@ - - - - - - -G - - -source1 - -source1 - - - -output - - -addint - -addint - -left_hand - -right_hand - -result - - -source1:output->addint:left_hand - - - - -const1 - -const1 - -[['1'], ['3'], ['3'], ['7']] - - -const1:output->addint:right_hand - - - - -sink1 - -sink1 - -input - - - - -addint:result->sink1:input - - - - - diff --git a/build/lib/WORC/doc/_build/html/_images/network2.svg b/build/lib/WORC/doc/_build/html/_images/network2.svg deleted file mode 100644 index 6f20f857..00000000 --- a/build/lib/WORC/doc/_build/html/_images/network2.svg +++ /dev/null @@ -1,151 +0,0 @@ - - - - - - -G - - -fixed_img - -fixed_img - - - -output - - -elastix - -elastix - -fixed - -moving - -parameters - -fixedMask - -movingMask - -initialTransform - -priority - -threads - -directory - -transform - -log - - -fixed_img:output->elastix:fixed - - - - -moving_img - -moving_img - - - -output - - -transformix - -transformix - -transform - -input_image - -input_points - -detjac - -jacmat - -priority - -threads - -directory - -output_image - -output_points - -output_jac - -output_jacmat - -log - - -moving_img:output->transformix:input_image - - - - -moving_img:output->elastix:moving - - - - -param_file - -param_file - - - -output - - -param_file:output->elastix:parameters - - - - -sink_image - -sink_image - -input - - - - -transformix:output_image->sink_image:input - - - - -elastix:transform->transformix:transform - - - - -sink_trans - -sink_trans - -input - - - - -elastix:transform->sink_trans:input - - - - - diff --git a/build/lib/WORC/doc/_build/html/_images/network_multi_atlas.svg b/build/lib/WORC/doc/_build/html/_images/network_multi_atlas.svg deleted file mode 100644 index 44237e96..00000000 --- a/build/lib/WORC/doc/_build/html/_images/network_multi_atlas.svg +++ /dev/null @@ -1,816 +0,0 @@ - - - - - - - - - - image/svg+xml - - - - - - - - - G - - - - target_img - - target_img - - - - output [N] - - - - elastix - - elastix - - [N] fixed_image - - [M] moving_image - - [R] parameters - - fixed_mask - - moving_mask - - initial_transform - - priority - - threads - - directory - - transform [NxM] - - log_file - - - - target_img:o_output->elastix:i_fixed_image - - - - - - mask_image - - mask_image - - - - output [M] - - - - transformix - - transformix - - [NxM] transform - - [M] image - - points - - determinant_of_jacobian_flag - - jacobian_matrix_flag - - priority - - threads - - directory - - image [NxM] - - points - - determinant_of_jacobian - - jacobian_matrix - - log_file - - - - mask_image:o_output->transformix:i_image - - - - - - template_img - - template_img - - - - output [M] - - - - template_img:o_output->elastix:i_moving_image - - - - - - param_file - - param_file - - - - output [O] - - - - param_file:o_output->elastix:i_parameters - - - - - - const_combine_method - - const_combine_method - - [['VOTE']] [P] - - - - combine - - combine - - [N] images - - [P] method - - [Q] number_of_classes - - original_labels - - substitute_labels - - hard_segment [N] - - soft_segment - - - - const_combine_method:o_output->combine:i_method - - - - - - const_combine_number_of_classes - - const_combine_number_of_classes - - [['3']] [Q] - - - - const_combine_number_of_classes:o_output->combine:i_number_of_classes - - - - - - sink_image - - sink_image - - [N] input - - - - - - combine:o_hard_segment->sink_image:i_input - - - - - - transformix:o_image->combine:i_images - - - - - - elastix:o_transform->transformix:i_transform - - - - - diff --git a/build/lib/WORC/doc/_build/html/_images/provo.svg b/build/lib/WORC/doc/_build/html/_images/provo.svg deleted file mode 100644 index 8bbaa836..00000000 --- a/build/lib/WORC/doc/_build/html/_images/provo.svg +++ /dev/null @@ -1,3 +0,0 @@ - - -2012-11-25 17:39ZCanvas 1Layer 1usedendedAtTimewasAssociatedWithactedOnBehalfOfwasGeneratedBywasAttributedTowasDerivedFromwasInformedByActivityEntityAgentxsd:dateTimestartedAtTimexsd:dateTime diff --git a/build/lib/WORC/doc/_build/html/_images/tooldefresolveflowchart.png b/build/lib/WORC/doc/_build/html/_images/tooldefresolveflowchart.png deleted file mode 100644 index 37037bfb..00000000 Binary files a/build/lib/WORC/doc/_build/html/_images/tooldefresolveflowchart.png and /dev/null differ diff --git a/build/lib/WORC/doc/_build/html/_modules/WORC/IOparser/config_WORC.html b/build/lib/WORC/doc/_build/html/_modules/WORC/IOparser/config_WORC.html deleted file mode 100644 index da54aa30..00000000 --- a/build/lib/WORC/doc/_build/html/_modules/WORC/IOparser/config_WORC.html +++ /dev/null @@ -1,253 +0,0 @@ - - - - - - - - - - - WORC.IOparser.config_WORC — WORC 3.0.0 documentation - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
                        - - - -
                        - - - - - -
                        - -
                        - - - - - - - - - - - - - - - - - -
                        - -
                          - -
                        • Docs »
                        • - -
                        • Module code »
                        • - -
                        • WORC.IOparser.config_WORC
                        • - - -
                        • - -
                        • - -
                        - - -
                        -
                        -
                        -
                        - -

                        Source code for WORC.IOparser.config_WORC

                        -#!/usr/bin/env python
                        -
                        -# Copyright 2016-2019 Biomedical Imaging Group Rotterdam, Departments of
                        -# Medical Informatics and Radiology, Erasmus MC, Rotterdam, The Netherlands
                        -#
                        -# 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 configparser
                        -
                        -
                        -
                        [docs]def load_config(config_file_path): - """ Parse a WORC configuration file. - - Arguments: - config_file_path: path to the configuration file to be parsed. - - Returns: - settings_dict: dictionary containing all parsed settings. - """ - - settings = configparser.ConfigParser() - settings.read(config_file_path) - - settings_dict = {'ImageFeatures': dict(), 'General': dict(), - 'SVMFeatures': dict()} - - settings_dict['ImageFeatures']['image_type'] =\ - str(settings['ImageFeatures']['image_type']) - - settings_dict['General']['FeatureCalculator'] =\ - str(settings['General']['FeatureCalculator']) - - settings_dict['General']['Preprocessing'] =\ - str(settings['General']['Preprocessing']) - - settings_dict['General']['PCE'] =\ - settings['General'].getboolean('PCE') - - settings_dict['General']['Segmentix'] =\ - settings['General'].getboolean('Segmentix') - - return settings_dict
                        -
                        - -
                        - -
                        -
                        - - -
                        - -
                        -

                        - © Copyright 2016 -- 2019, Biomedical Imaging Group Rotterdam, Departments of Medical Informatics and Radiology, Erasmus MC, Rotterdam, The Netherlands - -

                        -
                        - Built with Sphinx using a theme provided by Read the Docs. - -
                        - -
                        -
                        - -
                        - -
                        - - - - - - - - - - - - \ No newline at end of file diff --git a/build/lib/WORC/doc/_build/html/_modules/WORC/IOparser/config_io_classifier.html b/build/lib/WORC/doc/_build/html/_modules/WORC/IOparser/config_io_classifier.html deleted file mode 100644 index 620fe105..00000000 --- a/build/lib/WORC/doc/_build/html/_modules/WORC/IOparser/config_io_classifier.html +++ /dev/null @@ -1,471 +0,0 @@ - - - - - - - - - - - WORC.IOparser.config_io_classifier — WORC 3.0.0 documentation - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
                        - - - -
                        - - - - - -
                        - -
                        - - - - - - - - - - - - - - - - - -
                        - -
                          - -
                        • Docs »
                        • - -
                        • Module code »
                        • - -
                        • WORC.IOparser.config_io_classifier
                        • - - -
                        • - -
                        • - -
                        - - -
                        -
                        -
                        -
                        - -

                        Source code for WORC.IOparser.config_io_classifier

                        -#!/usr/bin/env python
                        -
                        -# Copyright 2016-2019 Biomedical Imaging Group Rotterdam, Departments of
                        -# Medical Informatics and Radiology, Erasmus MC, Rotterdam, The Netherlands
                        -#
                        -# 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 configparser
                        -
                        -
                        -
                        [docs]def load_config(config_file_path): - """ - Load the config ini, parse settings to WORC - - Args: - config_file_path (String): path of the .ini config file - - Returns: - settings_dict (dict): dict with the loaded settings - """ - - settings = configparser.ConfigParser() - settings.read(config_file_path) - print(settings.keys()) - - settings_dict = {'General': dict(), 'CrossValidation': dict(), - 'Labels': dict(), 'HyperOptimization': dict(), - 'Classification': dict(), 'SelectFeatGroup': dict(), - 'Featsel': dict(), 'FeatureScaling': dict(), - 'SampleProcessing': dict(), 'Imputation': dict(), - 'Ensemble': dict()} - - settings_dict['General']['cross_validation'] =\ - settings['General'].getboolean('cross_validation') - - settings_dict['General']['Joblib_ncores'] =\ - settings['General'].getint('Joblib_ncores') - - settings_dict['General']['Joblib_backend'] =\ - str(settings['General']['Joblib_backend']) - - settings_dict['General']['tempsave'] =\ - settings['General'].getboolean('tempsave') - - settings_dict['Featsel']['Variance'] =\ - [str(item).strip() for item in - settings['Featsel']['Variance'].split(',')] - - settings_dict['Featsel']['SelectFromModel'] =\ - [str(item).strip() for item in - settings['Featsel']['SelectFromModel'].split(',')] - - settings_dict['Featsel']['GroupwiseSearch'] =\ - [str(item).strip() for item in - settings['Featsel']['GroupwiseSearch'].split(',')] - - settings_dict['Featsel']['UsePCA'] =\ - [str(item).strip() for item in - settings['Featsel']['UsePCA'].split(',')] - - settings_dict['Featsel']['PCAType'] =\ - [str(item).strip() for item in - settings['Featsel']['PCAType'].split(',')] - - settings_dict['Featsel']['StatisticalTestUse'] =\ - [str(item).strip() for item in - settings['Featsel']['StatisticalTestUse'].split(',')] - - settings_dict['Featsel']['StatisticalTestMetric'] =\ - [str(item).strip() for item in - settings['Featsel']['StatisticalTestMetric'].split(',')] - - settings_dict['Featsel']['StatisticalTestThreshold'] =\ - [float(str(item).strip()) for item in - settings['Featsel']['StatisticalTestThreshold'].split(',')] - - settings_dict['Featsel']['ReliefUse'] =\ - [str(item).strip() for item in - settings['Featsel']['ReliefUse'].split(',')] - - settings_dict['Featsel']['ReliefNN'] =\ - [int(str(item).strip()) for item in - settings['Featsel']['ReliefNN'].split(',')] - - settings_dict['Featsel']['ReliefSampleSize'] =\ - [int(str(item).strip()) for item in - settings['Featsel']['ReliefSampleSize'].split(',')] - - settings_dict['Featsel']['ReliefDistanceP'] =\ - [int(str(item).strip()) for item in - settings['Featsel']['ReliefDistanceP'].split(',')] - - settings_dict['Featsel']['ReliefNumFeatures'] =\ - [int(str(item).strip()) for item in - settings['Featsel']['ReliefNumFeatures'].split(',')] - - settings_dict['Imputation']['use'] =\ - [str(item).strip() for item in - settings['Imputation']['use'].split(',')] - - settings_dict['Imputation']['strategy'] =\ - [str(item).strip() for item in - settings['Imputation']['strategy'].split(',')] - - settings_dict['Imputation']['n_neighbors'] =\ - [int(str(item).strip()) for item in - settings['Imputation']['n_neighbors'].split(',')] - - settings_dict['General']['FeatureCalculator'] =\ - str(settings['General']['FeatureCalculator']) - - # Feature selection options - for key in settings['SelectFeatGroup'].keys(): - settings_dict['SelectFeatGroup'][key] =\ - [str(item).strip() for item in - settings['SelectFeatGroup'][key].split(',')] - - # Classification options - settings_dict['Classification']['fastr'] =\ - settings['Classification'].getboolean('fastr') - - settings_dict['Classification']['fastr_plugin'] =\ - str(settings['Classification']['fastr_plugin']) - - settings_dict['Classification']['classifiers'] =\ - [str(item).strip() for item in - settings['Classification']['classifiers'].split(',')] - - settings_dict['Classification']['max_iter'] =\ - [int(str(item).strip()) for item in - settings['Classification']['max_iter'].split(',')] - - # Specific SVM options - settings_dict['Classification']['SVMKernel'] =\ - [str(item).strip() for item in - settings['Classification']['SVMKernel'].split(',')] - - settings_dict['Classification']['SVMC'] =\ - [int(str(item).strip()) for item in - settings['Classification']['SVMC'].split(',')] - - settings_dict['Classification']['SVMdegree'] =\ - [int(str(item).strip()) for item in - settings['Classification']['SVMdegree'].split(',')] - - settings_dict['Classification']['SVMcoef0'] =\ - [int(str(item).strip()) for item in - settings['Classification']['SVMcoef0'].split(',')] - - settings_dict['Classification']['SVMgamma'] =\ - [int(str(item).strip()) for item in - settings['Classification']['SVMgamma'].split(',')] - - # Specific RF options - settings_dict['Classification']['RFn_estimators'] =\ - [int(str(item).strip()) for item in - settings['Classification']['RFn_estimators'].split(',')] - settings_dict['Classification']['RFmin_samples_split'] =\ - [int(str(item).strip()) for item in - settings['Classification']['RFmin_samples_split'].split(',')] - settings_dict['Classification']['RFmax_depth'] =\ - [int(str(item).strip()) for item in - settings['Classification']['RFmax_depth'].split(',')] - - # Specific LR options - settings_dict['Classification']['LRpenalty'] =\ - [str(item).strip() for item in - settings['Classification']['LRpenalty'].split(',')] - settings_dict['Classification']['LRC'] =\ - [float(str(item).strip()) for item in - settings['Classification']['LRC'].split(',')] - - # Specific LDA/QDA options - settings_dict['Classification']['LDA_solver'] =\ - [str(item).strip() for item in - settings['Classification']['LDA_solver'].split(',')] - settings_dict['Classification']['LDA_shrinkage'] =\ - [int(str(item).strip()) for item in - settings['Classification']['LDA_shrinkage'].split(',')] - settings_dict['Classification']['QDA_reg_param'] =\ - [int(str(item).strip()) for item in - settings['Classification']['QDA_reg_param'].split(',')] - - # ElasticNet options - settings_dict['Classification']['ElasticNet_alpha'] =\ - [int(str(item).strip()) for item in - settings['Classification']['ElasticNet_alpha'].split(',')] - settings_dict['Classification']['ElasticNet_l1_ratio'] =\ - [float(str(item).strip()) for item in - settings['Classification']['ElasticNet_l1_ratio'].split(',')] - - # SGD (R) options - settings_dict['Classification']['SGD_alpha'] =\ - [int(str(item).strip()) for item in - settings['Classification']['SGD_alpha'].split(',')] - settings_dict['Classification']['SGD_l1_ratio'] =\ - [float(str(item).strip()) for item in - settings['Classification']['SGD_l1_ratio'].split(',')] - settings_dict['Classification']['SGD_loss'] =\ - [str(item).strip() for item in - settings['Classification']['SGD_loss'].split(',')] - settings_dict['Classification']['SGD_penalty'] =\ - [str(item).strip() for item in - settings['Classification']['SGD_penalty'].split(',')] - - # Naive Bayes options - settings_dict['Classification']['CNB_alpha'] =\ - [int(str(item).strip()) for item in - settings['Classification']['CNB_alpha'].split(',')] - - # Cross validation settings - settings_dict['CrossValidation']['N_iterations'] =\ - settings['CrossValidation'].getint('N_iterations') - - settings_dict['CrossValidation']['test_size'] =\ - settings['CrossValidation'].getfloat('test_size') - - # Genetic settings - settings_dict['Labels']['label_names'] =\ - [str(item).strip() for item in - settings['Labels']['label_names'].split(',')] - - settings_dict['Labels']['modus'] =\ - str(settings['Labels']['modus']) - - # Settings for hyper optimization - settings_dict['HyperOptimization']['scoring_method'] =\ - str(settings['HyperOptimization']['scoring_method']) - settings_dict['HyperOptimization']['test_size'] =\ - settings['HyperOptimization'].getfloat('test_size') - settings_dict['HyperOptimization']['N_iter'] =\ - settings['HyperOptimization'].getint('N_iterations') - settings_dict['HyperOptimization']['n_jobspercore'] =\ - int(settings['HyperOptimization']['n_jobspercore']) - - settings_dict['FeatureScaling']['scale_features'] =\ - settings['FeatureScaling'].getboolean('scale_features') - settings_dict['FeatureScaling']['scaling_method'] =\ - str(settings['FeatureScaling']['scaling_method']) - - settings_dict['SampleProcessing']['SMOTE'] =\ - [str(item).strip() for item in - settings['SampleProcessing']['SMOTE'].split(',')] - - settings_dict['SampleProcessing']['SMOTE_ratio'] =\ - [int(str(item).strip()) for item in - settings['SampleProcessing']['SMOTE_ratio'].split(',')] - - settings_dict['SampleProcessing']['SMOTE_neighbors'] =\ - [int(str(item).strip()) for item in - settings['SampleProcessing']['SMOTE_neighbors'].split(',')] - - settings_dict['SampleProcessing']['Oversampling'] =\ - [str(item).strip() for item in - settings['SampleProcessing']['Oversampling'].split(',')] - - settings_dict['Ensemble']['Use'] =\ - settings['Ensemble'].getboolean('Use') - - return settings_dict
                        -
                        - -
                        - -
                        -
                        - - -
                        - -
                        -

                        - © Copyright 2016 -- 2019, Biomedical Imaging Group Rotterdam, Departments of Medical Informatics and Radiology, Erasmus MC, Rotterdam, The Netherlands - -

                        -
                        - Built with Sphinx using a theme provided by Read the Docs. - -
                        - -
                        -
                        - -
                        - -
                        - - - - - - - - - - - - \ No newline at end of file diff --git a/build/lib/WORC/doc/_build/html/_modules/WORC/IOparser/config_preprocessing.html b/build/lib/WORC/doc/_build/html/_modules/WORC/IOparser/config_preprocessing.html deleted file mode 100644 index d939af43..00000000 --- a/build/lib/WORC/doc/_build/html/_modules/WORC/IOparser/config_preprocessing.html +++ /dev/null @@ -1,247 +0,0 @@ - - - - - - - - - - - WORC.IOparser.config_preprocessing — WORC 3.0.0 documentation - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
                        - - - -
                        - - - - - -
                        - -
                        - - - - - - - - - - - - - - - - - -
                        - -
                          - -
                        • Docs »
                        • - -
                        • Module code »
                        • - -
                        • WORC.IOparser.config_preprocessing
                        • - - -
                        • - -
                        • - -
                        - - -
                        -
                        -
                        -
                        - -

                        Source code for WORC.IOparser.config_preprocessing

                        -#!/usr/bin/env python
                        -
                        -# Copyright 2016-2019 Biomedical Imaging Group Rotterdam, Departments of
                        -# Medical Informatics and Radiology, Erasmus MC, Rotterdam, The Netherlands
                        -#
                        -# 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 configparser
                        -
                        -
                        -
                        [docs]def load_config(config_file_path): - """ Parse a WORC configuration file. - - Arguments: - config_file_path: path to the configuration file to be parsed. - - Returns: - settings_dict: dictionary containing all parsed settings. - """ - - settings = configparser.ConfigParser() - settings.read(config_file_path) - - settings_dict = {'Normalize': dict(), 'ImageFeatures': dict()} - - settings_dict['Normalize']['ROI'] =\ - str(settings['Normalize']['ROI']) - - settings_dict['Normalize']['Method'] =\ - str(settings['Normalize']['Method']) - - settings_dict['ImageFeatures']['image_type'] =\ - [str(item).strip() for item in - settings['ImageFeatures']['image_type'].split(',')] - - return settings_dict
                        -
                        - -
                        - -
                        -
                        - - -
                        - -
                        -

                        - © Copyright 2016 -- 2019, Biomedical Imaging Group Rotterdam, Departments of Medical Informatics and Radiology, Erasmus MC, Rotterdam, The Netherlands - -

                        -
                        - Built with Sphinx using a theme provided by Read the Docs. - -
                        - -
                        -
                        - -
                        - -
                        - - - - - - - - - - - - \ No newline at end of file diff --git a/build/lib/WORC/doc/_build/html/_modules/WORC/IOparser/config_segmentix.html b/build/lib/WORC/doc/_build/html/_modules/WORC/IOparser/config_segmentix.html deleted file mode 100644 index d0713f42..00000000 --- a/build/lib/WORC/doc/_build/html/_modules/WORC/IOparser/config_segmentix.html +++ /dev/null @@ -1,254 +0,0 @@ - - - - - - - - - - - WORC.IOparser.config_segmentix — WORC 3.0.0 documentation - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
                        - - - -
                        - - - - - -
                        - -
                        - - - - - - - - - - - - - - - - - -
                        - -
                          - -
                        • Docs »
                        • - -
                        • Module code »
                        • - -
                        • WORC.IOparser.config_segmentix
                        • - - -
                        • - -
                        • - -
                        - - -
                        -
                        -
                        -
                        - -

                        Source code for WORC.IOparser.config_segmentix

                        -#!/usr/bin/env python
                        -
                        -# Copyright 2016-2019 Biomedical Imaging Group Rotterdam, Departments of
                        -# Medical Informatics and Radiology, Erasmus MC, Rotterdam, The Netherlands
                        -#
                        -# 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 configparser
                        -
                        -
                        -
                        [docs]def load_config(config_file_path): - """ Parse a segmentix configuration file. - - Arguments: - config_file_path: path to the configuration file to be parsed. - - Returns: - settings_dict: dictionary containing all parsed settings. - """ - - settings = configparser.ConfigParser() - settings.read(config_file_path) - - settings_dict = {'Segmentix': dict()} - - # Segmentation settings - settings_dict['Sementix'] = dict() - settings_dict['Segmentix']['type'] =\ - str(settings['Segmentix']['segtype']) - - settings_dict['Segmentix']['mask'] =\ - str(settings['Segmentix']['mask']) - - settings_dict['Segmentix']['radius'] =\ - int(settings['Segmentix']['segradius']) - - settings_dict['Segmentix']['N_blobs'] =\ - int(settings['Segmentix']['N_blobs']) - - settings_dict['Segmentix']['fillholes'] =\ - settings['Segmentix'].getboolean('fillholes') - - return settings_dict
                        -
                        - -
                        - -
                        -
                        - - -
                        - -
                        -

                        - © Copyright 2016 -- 2019, Biomedical Imaging Group Rotterdam, Departments of Medical Informatics and Radiology, Erasmus MC, Rotterdam, The Netherlands - -

                        -
                        - Built with Sphinx using a theme provided by Read the Docs. - -
                        - -
                        -
                        - -
                        - -
                        - - - - - - - - - - - - \ No newline at end of file diff --git a/build/lib/WORC/doc/_build/html/_modules/WORC/IOparser/file_io.html b/build/lib/WORC/doc/_build/html/_modules/WORC/IOparser/file_io.html deleted file mode 100644 index ce04451e..00000000 --- a/build/lib/WORC/doc/_build/html/_modules/WORC/IOparser/file_io.html +++ /dev/null @@ -1,318 +0,0 @@ - - - - - - - - - - - WORC.IOparser.file_io — WORC 3.0.0 documentation - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
                        - - - -
                        - - - - - -
                        - -
                        - - - - - - - - - - - - - - - - - -
                        - - - - -
                        -
                        -
                        -
                        - -

                        Source code for WORC.IOparser.file_io

                        -#!/usr/bin/env python
                        -
                        -# Copyright 2016-2019 Biomedical Imaging Group Rotterdam, Departments of
                        -# Medical Informatics and Radiology, Erasmus MC, Rotterdam, The Netherlands
                        -#
                        -# 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 pandas as pd
                        -import WORC.processing.label_processing as lp
                        -import WORC.addexceptions as WORCexceptions
                        -import numpy as np
                        -
                        -
                        -
                        [docs]def load_data(featurefiles, patientinfo=None, label_names=None, modnames=[]): - ''' Read feature files and stack the features per patient in an array. - Additionally, if a patient label file is supplied, the features from - a patient will be matched to the labels. - - Parameters - ---------- - featurefiles: list, mandatory - List containing all paths to the .hdf5 feature files to be loaded. - The argument should contain a list per modelity, e.g. - [[features_mod1_patient1, features_mod1_patient2, ...], - [features_mod2_patient1, features_mod2_patient2, ...]]. - - patientinfo: string, optional - Path referring to the .txt file to be used to read patient - labels from. See the Github Wiki for the format. - - label_names: list, optional - List containing all the labels that should be extracted from - the patientinfo file. - - ''' - - # Read out all feature values and labels - image_features_temp = list() - feature_labels_all = list() - for i_patient in range(0, len(featurefiles[0])): - feature_values_temp = list() - feature_labels_temp = list() - for i_mod in range(0, len(featurefiles)): - feat_temp = pd.read_hdf(featurefiles[i_mod][i_patient]) - feature_values_temp += feat_temp.feature_values - if not modnames: - # Create artificial names - feature_labels_temp += [f + '_M' + str(i_mod) for f in feat_temp.feature_labels] - else: - # Use the provides modality names - feature_labels_temp += [f + '_' + str(modnames[i_mod]) for f in feat_temp.feature_labels] - - image_features_temp.append((feature_values_temp, feature_labels_temp)) - - # Also make a list of all unique label names - feature_labels_all = feature_labels_all + list(set(feature_labels_temp) - set(feature_labels_all)) - - # If some objects miss certain features, we will identify these with NaN values - feature_labels_all.sort() - image_features = list() - for patient in image_features_temp: - feat_temp = patient[0] - label_temp = patient[1] - - feat = list() - for f in feature_labels_all: - if f in label_temp: - index = label_temp.index(f) - fv = feat_temp[index] - else: - fv = np.NaN - feat.append(fv) - - image_features.append((feat, feature_labels_all)) - - # Get the labels and patient IDs - if patientinfo is not None: - # We use the feature files of the first modality to match to patient name - pfiles = featurefiles[0] - try: - label_data, image_features =\ - lp.findlabeldata(patientinfo, - label_names, - pfiles, - image_features) - except ValueError as e: - message = e.message + '. Please take a look at your labels' +\ - ' file and make sure it is formatted correctly. ' +\ - 'See also https://github.com/MStarmans91/WORC/wiki/The-WORC-configuration#genetics.' - raise WORCexceptions.WORCValueError(message) - - print("Labels:") - print(label_data['label']) - print('Total of ' + str(label_data['patient_IDs'].shape[0]) + - ' patients') - pos = np.sum(label_data['label']) - neg = label_data['patient_IDs'].shape[0] - pos - print(('{} positives, {} negatives').format(pos, neg)) - else: - # Use filenames as patient ID s - patient_IDs = list() - for i in featurefiles: - patient_IDs.append(os.path.basename(i)) - label_data = dict() - label_data['patient_IDs'] = patient_IDs - - return label_data, image_features
                        -
                        - -
                        - -
                        -
                        - - -
                        - -
                        -

                        - © Copyright 2016 -- 2019, Biomedical Imaging Group Rotterdam, Departments of Medical Informatics and Radiology, Erasmus MC, Rotterdam, The Netherlands - -

                        -
                        - Built with Sphinx using a theme provided by Read the Docs. - -
                        - -
                        -
                        - -
                        - -
                        - - - - - - - - - - - - \ No newline at end of file diff --git a/build/lib/WORC/doc/_build/html/_modules/WORC/WORC.html b/build/lib/WORC/doc/_build/html/_modules/WORC/WORC.html deleted file mode 100644 index b8539902..00000000 --- a/build/lib/WORC/doc/_build/html/_modules/WORC/WORC.html +++ /dev/null @@ -1,1182 +0,0 @@ - - - - - - - - - - - WORC.WORC — WORC 3.0.0 documentation - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
                        - - - -
                        - - - - - -
                        - -
                        - - - - - - - - - - - - - - - - - -
                        - - - - -
                        -
                        -
                        -
                        - -

                        Source code for WORC.WORC

                        -#!/usr/bin/env python
                        -
                        -# Copyright 2016-2019 Biomedical Imaging Group Rotterdam, Departments of
                        -# Medical Informatics and Radiology, Erasmus MC, Rotterdam, The Netherlands
                        -#
                        -# 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 configparser
                        -import fastr
                        -from fastr.api import ResourceLimit
                        -import os
                        -from random import randint
                        -import WORC.addexceptions as WORCexceptions
                        -import WORC.IOparser.config_WORC as config_io
                        -from WORC.tools.Elastix import Elastix
                        -from WORC.tools.Evaluate import Evaluate
                        -
                        -
                        -
                        [docs]class WORC(object): - """ - A Workflow for Optimal Radiomics Classification (WORC) object that - serves as a pipeline spawner and manager for optimizating radiomics - studies. Depending on the attributes set, the object will spawn an - appropriate pipeline and manage it. - - Note that many attributes are lists and can therefore contain multiple - instances. For example, when providing two sequences per patient, - the "images" list contains two items. The type of items in the lists - is described below. - - All objects that serve as source for your network, i.e. refer to - actual files to be used, should be formatted as fastr sources suited for - one of the fastr plugings, see also - http://fastr.readthedocs.io/en/stable/fastr.reference.html#ioplugin-reference - The objects should be lists of these fastr sources or dictionaries with the - sample ID's, e.g. - - images_train = [{'Patient001': vfs://input/CT001.nii.gz, - 'Patient002': vfs://input/CT002.nii.gz}, - {'Patient001': vfs://input/MR001.nii.gz, - 'Patient002': vfs://input/MR002.nii.gz}] - - Attributes - ------------------ - name: String, default 'WORC' - name of the network. - - configs: list, required - Configuration parameters, either ConfigParser objects - created through the defaultconfig function or paths of config .ini - files. (list, required) - - labels: list, required - Paths to files containing patient labels (.txt files). - - network: automatically generated - The FASTR network generated through the "build" function. - - images: list, optional - Paths refering to the images used for Radiomics computation. Images - should be of the ITK Image type. - - segmentations: list, optional - Paths refering to the segmentations used for Radiomics computation. - Segmentations should be of the ITK Image type. - - semantics: semantic features per image type (list, optional) - - masks: state which pixels of images are valid (list, optional) - - features: input Radiomics features for classification (list, optional) - - metadata: DICOM headers belonging to images (list, optional) - - Elastix_Para: parameter files for Elastix (list, optional) - - fastr_plugin: plugin to use for FASTR execution - - fastr_tempdir: temporary directory to use for FASTR execution - - additions: additional inputs for your network (dict, optional) - - source_data: data to use as sources for FASTR (dict) - - sink_data: data to use as sinks for FASTR (dict) - - CopyMetadata: Boolean, default True - when using elastix, copy metadata from image to segmentation or not - - - """ - -
                        [docs] def __init__(self, name='WORC'): - """Initialize WORC object. Set the initial variables all to None, - except for some defaults. - - Arguments: - name: name of the nework (string, optional) - - """ - self.name = name - - # Initialize several objects - self.configs = list() - self.fastrconfigs = list() - - self.images_train = list() - self.segmentations_train = list() - self.semantics_train = list() - self.labels_train = list() - self.masks_train = list() - self.features_train = list() - self.metadata_train = list() - - self.images_test = list() - self.segmentations_test = list() - self.semantics_test = list() - self.labels_test = list() - self.masks_test = list() - self.features_test = list() - self.metadata_test = list() - - self.Elastix_Para = list() - - # Set some defaults, name - self.fastr_plugin = 'ProcessPoolExecution' - if name == '': - name = [randint(0, 9) for p in range(0, 5)] - self.fastr_tmpdir = os.path.join(fastr.config.mounts['tmp'], 'WORC_' + str(name)) - - self.additions = dict() - self.CopyMetadata = True - self.segmode = []
                        - -
                        [docs] def defaultconfig(self): - """Generate a configparser object holding all default configuration values. - - Returns: - config: configparser configuration file - - """ - # TODO: cluster parallel execution parameters - config = configparser.ConfigParser() - config.optionxform = str - - # General configuration of WORC - config['General'] = dict() - config['General']['cross_validation'] = 'True' - config['General']['Segmentix'] = 'False' - config['General']['FeatureCalculator'] = 'predict/CalcFeatures:1.0' - config['General']['Preprocessing'] = 'worc/PreProcess:1.0' - config['General']['RegistrationNode'] = "'elastix4.8/Elastix:4.8'" - config['General']['TransformationNode'] = "'elastix4.8/Transformix:4.8'" - config['General']['Joblib_ncores'] = '4' - config['General']['Joblib_backend'] = 'multiprocessing' - config['General']['tempsave'] = 'False' - - # Segmentix - config['Segmentix'] = dict() - config['Segmentix']['mask'] = 'subtract' - config['Segmentix']['segtype'] = 'None' - config['Segmentix']['segradius'] = '5' - config['Segmentix']['N_blobs'] = '1' - config['Segmentix']['fillholes'] = 'False' - - # Preprocessing - config['Normalize'] = dict() - config['Normalize']['ROI'] = 'Full' - config['Normalize']['Method'] = 'z_score' - - # PREDICT - Feature calculation - # Determine which features are calculated - config['ImageFeatures'] = dict() - config['ImageFeatures']['shape'] = 'True' - config['ImageFeatures']['histogram'] = 'True' - config['ImageFeatures']['orientation'] = 'True' - config['ImageFeatures']['texture_Gabor'] = 'False' - config['ImageFeatures']['texture_LBP'] = 'True' - config['ImageFeatures']['texture_GLCM'] = 'True' - config['ImageFeatures']['texture_GLCMMS'] = 'True' - config['ImageFeatures']['texture_GLRLM'] = 'True' - config['ImageFeatures']['texture_GLSZM'] = 'True' - config['ImageFeatures']['texture_NGTDM'] = 'True' - config['ImageFeatures']['coliage'] = 'False' - config['ImageFeatures']['vessel'] = 'False' - config['ImageFeatures']['log'] = 'False' - config['ImageFeatures']['phase'] = 'False' - - # Parameter settings for PREDICT feature calculation - # Defines what should be done with the images - config['ImageFeatures']['image_type'] = 'CT' - - # Define frequencies for gabor filter in pixels - config['ImageFeatures']['gabor_frequencies'] = '0.05, 0.2, 0.5' - - # Gabor, GLCM angles in degrees and radians, respectively - config['ImageFeatures']['gabor_angles'] = '0, 45, 90, 135' - config['ImageFeatures']['GLCM_angles'] = '0, 0.79, 1.57, 2.36' - - # GLCM discretization levels, distances in pixels - config['ImageFeatures']['GLCM_levels'] = '16' - config['ImageFeatures']['GLCM_distances'] = '1, 3' - - # LBP radius, number of points in pixels - config['ImageFeatures']['LBP_radius'] = '3, 8, 15' - config['ImageFeatures']['LBP_npoints'] = '12, 24, 36' - - # Phase features minimal wavelength and number of scales - config['ImageFeatures']['phase_minwavelength'] = '3' - config['ImageFeatures']['phase_nscale'] = '5' - - # Log features sigma of Gaussian in pixels - config['ImageFeatures']['log_sigma'] = '1, 5, 10' - - # Vessel features scale range, steps for the range - config['ImageFeatures']['vessel_scale_range'] = '1, 10' - config['ImageFeatures']['vessel_scale_step'] = '2' - - # Vessel features radius for erosion to determine boudnary - config['ImageFeatures']['vessel_radius'] = '5' - - # Feature selection - config['Featsel'] = dict() - config['Featsel']['Variance'] = 'True, False' - config['Featsel']['GroupwiseSearch'] = 'True' - config['Featsel']['SelectFromModel'] = 'False' - config['Featsel']['UsePCA'] = 'False' - config['Featsel']['PCAType'] = '95variance' - config['Featsel']['StatisticalTestUse'] = 'False' - config['Featsel']['StatisticalTestMetric'] = 'ttest, Welch, Wilcoxon, MannWhitneyU' - config['Featsel']['StatisticalTestThreshold'] = '0.02, 0.2' - config['Featsel']['ReliefUse'] = 'False' - config['Featsel']['ReliefNN'] = '2, 4' - config['Featsel']['ReliefSampleSize'] = '1, 1' - config['Featsel']['ReliefDistanceP'] = '1, 3' - config['Featsel']['ReliefNumFeatures'] = '25, 200' - - # Groupwise Featureselection options - config['SelectFeatGroup'] = dict() - config['SelectFeatGroup']['shape_features'] = 'True, False' - config['SelectFeatGroup']['histogram_features'] = 'True, False' - config['SelectFeatGroup']['orientation_features'] = 'True, False' - config['SelectFeatGroup']['texture_Gabor_features'] = 'True, False' - config['SelectFeatGroup']['texture_GLCM_features'] = 'True, False' - config['SelectFeatGroup']['texture_GLCMMS_features'] = 'True, False' - config['SelectFeatGroup']['texture_GLRLM_features'] = 'True, False' - config['SelectFeatGroup']['texture_GLSZM_features'] = 'True, False' - config['SelectFeatGroup']['texture_NGTDM_features'] = 'True, False' - config['SelectFeatGroup']['texture_LBP_features'] = 'True, False' - config['SelectFeatGroup']['patient_features'] = 'False' - config['SelectFeatGroup']['semantic_features'] = 'False' - config['SelectFeatGroup']['coliage_features'] = 'False' - config['SelectFeatGroup']['log_features'] = 'False' - config['SelectFeatGroup']['vessel_features'] = 'False' - config['SelectFeatGroup']['phase_features'] = 'False' - - # Feature imputation - config['Imputation'] = dict() - config['Imputation']['use'] = 'False' - config['Imputation']['strategy'] = 'mean, median, most_frequent, constant, knn' - config['Imputation']['n_neighbors'] = '5, 5' - - # Classification - config['Classification'] = dict() - config['Classification']['fastr'] = 'True' - config['Classification']['fastr_plugin'] = self.fastr_plugin - config['Classification']['classifiers'] = 'SVM' - config['Classification']['max_iter'] = '100000' - config['Classification']['SVMKernel'] = 'poly' - config['Classification']['SVMC'] = '0, 6' - config['Classification']['SVMdegree'] = '1, 6' - config['Classification']['SVMcoef0'] = '0, 1' - config['Classification']['SVMgamma'] = '-5, 5' - config['Classification']['RFn_estimators'] = '10, 90' - config['Classification']['RFmin_samples_split'] = '2, 3' - config['Classification']['RFmax_depth'] = '5, 5' - config['Classification']['LRpenalty'] = 'l2, l1' - config['Classification']['LRC'] = '0.01, 1.0' - config['Classification']['LDA_solver'] = 'svd, lsqr, eigen' - config['Classification']['LDA_shrinkage'] = '-5, 5' - config['Classification']['QDA_reg_param'] = '-5, 5' - config['Classification']['ElasticNet_alpha'] = '-5, 5' - config['Classification']['ElasticNet_l1_ratio'] = '0, 1' - config['Classification']['SGD_alpha'] = '-5, 5' - config['Classification']['SGD_l1_ratio'] = '0, 1' - config['Classification']['SGD_loss'] = 'hinge, squared_hinge, modified_huber' - config['Classification']['SGD_penalty'] = 'none, l2, l1' - config['Classification']['CNB_alpha'] = '0, 1' - - # CrossValidation - config['CrossValidation'] = dict() - config['CrossValidation']['N_iterations'] = '100' - config['CrossValidation']['test_size'] = '0.2' - - # Options for the object/patient labels that are used - config['Labels'] = dict() - config['Labels']['label_names'] = 'Label1, Label2' - config['Labels']['modus'] = 'singlelabel' - config['Labels']['url'] = 'WIP' - config['Labels']['projectID'] = 'WIP' - - # Hyperparameter optimization options - config['HyperOptimization'] = dict() - config['HyperOptimization']['scoring_method'] = 'f1_weighted' - config['HyperOptimization']['test_size'] = '0.15' - config['HyperOptimization']['N_iterations'] = '10000' - config['HyperOptimization']['n_jobspercore'] = '2000' # only relevant when using fastr in classification - - # Feature scaling options - config['FeatureScaling'] = dict() - config['FeatureScaling']['scale_features'] = 'True' - config['FeatureScaling']['scaling_method'] = 'z_score' - - # Sample processing options - config['SampleProcessing'] = dict() - config['SampleProcessing']['SMOTE'] = 'True' - config['SampleProcessing']['SMOTE_ratio'] = '1, 0' - config['SampleProcessing']['SMOTE_neighbors'] = '5, 15' - config['SampleProcessing']['Oversampling'] = 'False' - - # Ensemble options - config['Ensemble'] = dict() - config['Ensemble']['Use'] = 'False' # Still WIP - - return config
                        - -
                        [docs] def add_tools(self): - self.Tools = Tools()
                        - -
                        [docs] def build(self, wtype='training'): - """Build the network based on the given attributes. - - Parameters - ---------- - wtype: string, default 'training' - Specify the WORC execution type. - - testing: use if you have a trained classifier and want to - train it on some new images. - - training: use if you want to train a classifier from a dataset. - - """ - - self.wtype = wtype - if wtype == 'training': - self.build_training() - elif wtype == 'testing': - self.build_testing()
                        - -
                        [docs] def build_training(self): - """Build the training network based on the given attributes.""" - # We either need images or features for Radiomics - if self.images_train or self.features_train: - # We currently require labels for supervised learning - if self.labels_train: - if not self.configs: - print("No configuration given, assuming default") - if self.images_train: - self.configs = [self.defaultconfig()] * len(self.images_train) - else: - self.configs = [self.defaultconfig()] * len(self.features_train) - self.network = fastr.create_network('WORC_' + self.name) - - # BUG: We currently use the first configuration as general config - image_types = list() - for c in range(len(self.configs)): - if type(self.configs[c]) == str: - # Probably, c is a configuration file - self.configs[c] = config_io.load_config(self.configs[c]) - image_types.append(self.configs[c]['ImageFeatures']['image_type']) - - # Create config source - self.source_class_config = self.network.create_source('ParameterFile', id='config_classification_source', node_group='conf') - - # Classification tool and label source - self.source_patientclass_train = self.network.create_source('PatientInfoFile', id='patientclass_train', node_group='pctrain') - if self.labels_test: - self.source_patientclass_test = self.network.create_source('PatientInfoFile', id='patientclass_test', node_group='pctest') - - self.classify = self.network.create_node('worc/TrainClassifier:1.0', tool_version='1.0', id='classify', resources=ResourceLimit(memory='12G')) - - # Outputs - self.sink_classification = self.network.create_sink('HDF5', id='classification') - self.sink_performance = self.network.create_sink('JsonFile', id='performance') - self.sink_class_config = self.network.create_sink('ParameterFile', id='config_classification_sink', node_group='conf') - - # Links - self.sink_class_config.input = self.source_class_config.output - self.link_class_1 = self.network.create_link(self.source_class_config.output, self.classify.inputs['config']) - self.link_class_2 = self.network.create_link(self.source_patientclass_train.output, self.classify.inputs['patientclass_train']) - self.link_class_1.collapse = 'conf' - self.link_class_2.collapse = 'pctrain' - - if self.images_test or self.features_test: - # FIXME: the naming here is ugly - self.link_class_3 = self.network.create_link(self.source_patientclass_test.output, self.classify.inputs['patientclass_test']) - self.link_class_3.collapse = 'pctest' - - self.sink_classification.input = self.classify.outputs['classification'] - self.sink_performance.input = self.classify.outputs['performance'] - - if not self.features_train: - # Create nodes to compute features - self.sources_parameters = dict() - - self.calcfeatures_train = dict() - self.preprocessing_train = dict() - self.sources_images_train = dict() - self.sinks_features_train = dict() - self.converters_im_train = dict() - self.converters_seg_train = dict() - self.links_C1_train = dict() - - if self.images_test or self.features_test: - # A test set is supplied, for which nodes also need to be created - self.preprocessing_test = dict() - self.calcfeatures_test = dict() - self.sources_images_test = dict() - self.sinks_features_test = dict() - self.converters_im_test = dict() - self.converters_seg_test = dict() - self.links_C1_test = dict() - - # Check which nodes are necessary - if not self.segmentations_train: - message = "No automatic segmentation method is yet implemented." - raise WORCexceptions.WORCNotImplementedError(message) - - elif len(self.segmentations_train) == len(image_types): - # Segmentations provided - self.sources_segmentations_train = dict() - self.sources_segmentations_test = dict() - self.segmode = 'Provided' - - elif len(self.segmentations_train) == 1: - # Assume segmentations need to be registered to other modalities - self.sources_segmentation = dict() - self.segmode = 'Register' - - self.source_Elastix_Parameters = dict() - self.elastix_nodes_train = dict() - self.transformix_seg_nodes_train = dict() - self.sources_segmentations_train = dict() - self.sinks_transformations_train = dict() - self.sinks_segmentations_elastix_train = dict() - self.sinks_images_elastix_train = dict() - self.converters_seg_train = dict() - self.edittransformfile_nodes_train = dict() - self.transformix_im_nodes_train = dict() - - self.elastix_nodes_test = dict() - self.transformix_seg_nodes_test = dict() - self.sources_segmentations_test = dict() - self.sinks_transformations_test = dict() - self.sinks_segmentations_elastix_test = dict() - self.sinks_images_elastix_test = dict() - self.converters_seg_test = dict() - self.edittransformfile_nodes_test = dict() - self.transformix_im_nodes_test = dict() - pass - - # BUG: We assume that first type defines if we use segmentix - if self.configs[0]['General']['Segmentix'] == 'True': - # Use the segmentix toolbox for segmentation processing - self.sinks_segmentations_segmentix_train = dict() - self.sources_masks_train = dict() - self.converters_masks_train = dict() - self.nodes_segmentix_train = dict() - - if self.images_test or self.features_test: - # Also use segmentix on the tes set - self.sinks_segmentations_segmentix_test = dict() - self.sources_masks_test = dict() - self.converters_masks_test = dict() - self.nodes_segmentix_test = dict() - - if self.semantics_train: - # Semantic features are supplied - self.sources_semantics_train = dict() - - if self.metadata_train: - # Metadata to extract patient features from is supplied - self.sources_metadata_train = dict() - - if self.semantics_test: - # Semantic features are supplied - self.sources_semantics_test = dict() - - if self.metadata_test: - # Metadata to extract patient features from is supplied - self.sources_metadata_test = dict() - - # Create a part of the pipeline for each modality - self.modlabels = list() - for nmod, mod in enumerate(image_types): - # Create label for each modality/image - num = 0 - label = mod + '_' + str(num) - while label in self.calcfeatures_train.keys(): - # if label already exists, add number to label - num += 1 - label = mod + '_' + str(num) - self.modlabels.append(label) - - # Create required sources and sinks - self.sources_parameters[label] = self.network.create_source('ParameterFile', id='parameters_' + label) - self.sources_images_train[label] = self.network.create_source('ITKImageFile', id='images_train_' + label, node_group='train') - self.sinks_features_train[label] = self.network.create_sink('HDF5', id='features_train_' + label) - if self.images_test or self.features_test: - self.sources_images_test[label] = self.network.create_source('ITKImageFile', id='images_test_' + label, node_group='test') - self.sinks_features_test[label] = self.network.create_sink('HDF5', id='features_test_' + label) - - if self.metadata_train and len(self.metadata_train) >= nmod + 1: - self.sources_metadata_train[label] = self.network.create_source('DicomImageFile', id='metadata_train_' + label, node_group='train') - - if self.metadata_test and len(self.metadata_test) >= nmod + 1: - self.sources_metadata_test[label] = self.network.create_source('DicomImageFile', id='metadata_test_' + label, node_group='test') - - if self.masks_train and len(self.masks_train) >= nmod + 1: - # Create mask source and convert - self.sources_masks_train[label] = self.network.create_source('ITKImageFile', id='mask_train_' + label, node_group='train') - self.converters_masks_train[label] = self.network.create_node('worc/WORCCastConvert:0.3.2', tool_version='0.1', id='convert_mask_train_' + label, node_group='train', resources=ResourceLimit(memory='4G')) - self.converters_masks_train[label].inputs['image'] = self.sources_masks_train[label].output - - if self.masks_test and len(self.masks_test) >= nmod + 1: - # Create mask source and convert - self.sources_masks_test[label] = self.network.create_source('ITKImageFile', id='mask_test_' + label, node_group='test') - self.converters_masks_test[label] = self.network.create_node('worc/WORCCastConvert:0.3.2', tool_version='0.1', id='convert_mask_test_' + label, node_group='test', resources=ResourceLimit(memory='4G')) - self.converters_masks_test[label].inputs['image'] = self.sources_masks_test[label].output - - # First convert the images - if any(modality in mod for modality in ['MR', 'CT', 'MG', 'PET']): - # Use ITKTools PXCastConvet for converting image formats - self.converters_im_train[label] = self.network.create_node('worc/WORCCastConvert:0.3.2', tool_version='0.1', id='convert_im_train_' + label, resources=ResourceLimit(memory='4G')) - if self.images_test or self.features_test: - self.converters_im_test[label] = self.network.create_node('worc/WORCCastConvert:0.3.2', tool_version='0.1', id='convert_im_test_' + label, resources=ResourceLimit(memory='4G')) - - else: - raise WORCexceptions.WORCTypeError(('No valid image type for modality {}: {} provided.').format(str(nmod), mod)) - - # Create required links - self.converters_im_train[label].inputs['image'] = self.sources_images_train[label].output - if self.images_test or self.features_test: - self.converters_im_test[label].inputs['image'] = self.sources_images_test[label].output - - # ----------------------------------------------------- - # Preprocessing - # Create nodes - preprocess_node = str(self.configs[nmod]['General']['Preprocessing']) - self.preprocessing_train[label] = self.network.create_node(preprocess_node, tool_version='1.0', id='preprocessing_train_' + label, resources=ResourceLimit(memory='4G')) - if self.images_test or self.features_test: - self.preprocessing_test[label] = self.network.create_node(preprocess_node, tool_version='1.0', id='preprocessing_test_' + label, resources=ResourceLimit(memory='4G')) - - # Create required links - self.preprocessing_train[label].inputs['parameters'] = self.sources_parameters[label].output - self.preprocessing_train[label].inputs['image'] = self.converters_im_train[label].outputs['image'] - - if self.images_test or self.features_test: - self.preprocessing_test[label].inputs['parameters'] = self.sources_parameters[label].output - self.preprocessing_test[label].inputs['image'] = self.converters_im_test[label].outputs['image'] - - if self.metadata_train and len(self.metadata_train) >= nmod + 1: - self.preprocessing_train[label].inputs['metadata'] = self.sources_metadata_train[label].output - - if self.metadata_test and len(self.metadata_test) >= nmod + 1: - self.preprocessing_test[label].inputs['metadata'] = self.sources_metadata_test[label].output - - # ----------------------------------------------------- - # Create a feature calculator node - calcfeat_node = str(self.configs[nmod]['General']['FeatureCalculator']) - self.calcfeatures_train[label] = self.network.create_node(calcfeat_node, tool_version='1.0', id='calcfeatures_train_' + label, resources=ResourceLimit(memory='14G')) - if self.images_test or self.features_test: - self.calcfeatures_test[label] = self.network.create_node(calcfeat_node, tool_version='1.0', id='calcfeatures_test_' + label, resources=ResourceLimit(memory='14G')) - - # Create required links - self.calcfeatures_train[label].inputs['parameters'] = self.sources_parameters[label].output - self.calcfeatures_train[label].inputs['image'] = self.preprocessing_train[label].outputs['image'] - - if self.images_test or self.features_test: - self.calcfeatures_test[label].inputs['parameters'] = self.sources_parameters[label].output - self.calcfeatures_test[label].inputs['image'] = self.preprocessing_test[label].outputs['image'] - - if self.metadata_train and len(self.metadata_train) >= nmod + 1: - self.calcfeatures_train[label].inputs['metadata'] = self.sources_metadata_train[label].output - - if self.metadata_train and len(self.metadata_test) >= nmod + 1: - self.calcfeatures_train[label].inputs['metadata'] = self.sources_metadata_train[label].output - - if self.semantics_train and len(self.semantics_train) >= nmod + 1: - self.sources_semantics_train[label] = self.network.create_source('CSVFile', id='semantics_train_' + label) - self.calcfeatures_train[label].inputs['semantics'] = self.sources_semantics_train[label].output - - if self.semantics_test and len(self.semantics_test) >= nmod + 1: - self.sources_semantics_test[label] = self.network.create_source('CSVFile', id='semantics_test_' + label) - self.calcfeatures_test[label].inputs['semantics'] = self.sources_semantics_test[label].output - - if self.segmode == 'Provided': - # Segmentation ----------------------------------------------------- - # Use the provided segmantions for each modality - self.sources_segmentations_train[label] = self.network.create_source('ITKImageFile', id='segmentations_train_' + label, node_group='train') - self.converters_seg_train[label] = self.network.create_node('worc/WORCCastConvert:0.3.2', tool_version='0.1', id='convert_seg_train_' + label, resources=ResourceLimit(memory='4G')) - self.converters_seg_train[label].inputs['image'] = self.sources_segmentations_train[label].output - - if self.images_test or self.features_test: - self.sources_segmentations_test[label] = self.network.create_source('ITKImageFile', id='segmentations_test_' + label, node_group='test') - self.converters_seg_test[label] = self.network.create_node('worc/WORCCastConvert:0.3.2', tool_version='0.1', id='convert_seg_test_' + label, resources=ResourceLimit(memory='4G')) - self.converters_seg_test[label].inputs['image'] = self.sources_segmentations_test[label].output - - elif self.segmode == 'Register': - # Registration nodes ----------------------------------------------------- - # Align segmentation of first modality to others using registration with Elastix - - # Create sources and converter for only for the given segmentation, which should be on the first modality - if nmod == 0: - self.sources_segmentations_train[label] = self.network.create_source('ITKImageFile', id='segmentations_train_' + label, node_group='input') - self.converters_seg_train[label] = self.network.create_node('worc/WORCCastConvert:0.3.2', tool_version='0.1', id='convert_seg_train_' + label, resources=ResourceLimit(memory='4G')) - self.converters_seg_train[label].inputs['image'] = self.sources_segmentations_train[label].output - - if self.images_test or self.features_test: - self.sources_segmentations_test[label] = self.network.create_source('ITKImageFile', id='segmentations_test_' + label, node_group='input') - self.converters_seg_test[label] = self.network.create_node('worc/WORCCastConvert:0.3.2', tool_version='0.1', id='convert_seg_test_' + label, resources=ResourceLimit(memory='4G')) - self.converters_seg_test[label].inputs['image'] = self.sources_segmentations_test[label].output - - # Assume provided segmentation is on first modality - if nmod > 0: - # Use elastix and transformix for registration - # NOTE: Assume elastix node type is on first configuration - elastix_node = str(self.configs[0]['General']['RegistrationNode']) - transformix_node = str(self.configs[0]['General']['TransformationNode']) - self.elastix_nodes_train[label] = self.network.create_node(elastix_node, tool_version='0.2', id='elastix_train_' + label, resources=ResourceLimit(memory='4G')) - self.transformix_seg_nodes_train[label] = self.network.create_node(transformix_node, tool_version= '0.2' , id='transformix_seg_train_' + label) - self.transformix_im_nodes_train[label] = self.network.create_node(transformix_node, tool_version= '0.2' , id='transformix_im_train_' + label) - - if self.images_test or self.features_test: - self.elastix_nodes_test[label] = self.network.create_node(elastix_node, tool_version='0.2', id='elastix_test_' + label, resources=ResourceLimit(memory='4G')) - self.transformix_seg_nodes_test[label] = self.network.create_node(transformix_node, tool_version= '0.2' , id='transformix_seg_test_' + label) - self.transformix_im_nodes_test[label] = self.network.create_node(transformix_node, tool_version= '0.2' , id='transformix_im_test_' + label) - - # Create sources_segmentation - # M1 = moving, others = fixed - self.elastix_nodes_train[label].inputs['fixed_image'] = self.converters_im_train[label].outputs['image'] - self.elastix_nodes_train[label].inputs['moving_image'] = self.converters_im_train[self.modlabels[0]].outputs['image'] - - # Add node that copies metadata from the image to the segmentation if required - if self.CopyMetadata: - # Copy metadata from the image which was registered to the segmentation, if it is not created yet - if not hasattr(self, "copymetadata_nodes_train"): - # NOTE: Do this for first modality, as we assume segmentation is on that one - self.copymetadata_nodes_train = dict() - self.copymetadata_nodes_train[self.modlabels[0]] = self.network.create_node('itktools/0.3.2/CopyMetadata:1.0', tool_version= '1.0' , id='CopyMetadata_train_' + self.modlabels[0]) - self.copymetadata_nodes_train[self.modlabels[0]].inputs["source"] = self.converters_im_train[self.modlabels[0]].outputs['image'] - self.copymetadata_nodes_train[self.modlabels[0]].inputs["destination"] = self.converters_seg_train[self.modlabels[0]].outputs['image'] - self.transformix_seg_nodes_train[label].inputs['image'] = self.copymetadata_nodes_train[self.modlabels[0]].outputs['output'] - else: - self.transformix_seg_nodes_train[label].inputs['image'] = self.converters_seg_train[self.modlabels[0]].outputs['image'] - - if self.images_test or self.features_test: - self.elastix_nodes_test[label].inputs['fixed_image'] = self.converters_im_test[label].outputs['image'] - self.elastix_nodes_test[label].inputs['moving_image'] = self.converters_im_test[self.modlabels[0]].outputs['image'] - - if self.CopyMetadata: - # Copy metadata from the image which was registered to the segmentation - if not hasattr(self, "copymetadata_nodes_test"): - # NOTE: Do this for first modality, as we assume segmentation is on that one - self.copymetadata_nodes_test = dict() - self.copymetadata_nodes_test[self.modlabels[0]] = self.network.create_node('itktools/0.3.2/CopyMetadata:1.0', tool_version= '1.0' , id='CopyMetadata_test_' + self.modlabels[0]) - self.copymetadata_nodes_test[self.modlabels[0]].inputs["source"] = self.converters_im_test[self.modlabels[0]].outputs['image'] - self.copymetadata_nodes_test[self.modlabels[0]].inputs["destination"] = self.converters_seg_test[self.modlabels[0]].outputs['image'] - self.transformix_seg_nodes_test[label].inputs['image'] = self.copymetadata_nodes_test[self.modlabels[0]].outputs['output'] - else: - self.transformix_seg_nodes_test[label].inputs['image'] = self.converters_seg_test[self.modlabels[0]].outputs['image'] - - # Apply registration to input modalities - self.source_Elastix_Parameters[label] = self.network.create_source('ElastixParameterFile', id='Elastix_Para_' + label, node_group='elpara') - self.link_elparam_train = self.network.create_link(self.source_Elastix_Parameters[label].output, - self.elastix_nodes_train[label].inputs['parameters']) - self.link_elparam_train.collapse = 'elpara' - - if self.images_test or self.features_test: - self.link_elparam_test = self.network.create_link(self.source_Elastix_Parameters[label].output, - self.elastix_nodes_test[label].inputs['parameters']) - self.link_elparam_test.collapse = 'elpara' - - if self.masks_train: - self.elastix_nodes_train[label].inputs['fixed_mask'] = self.converters_masks_train[label].outputs['image'] - self.elastix_nodes_train[label].inputs['moving_mask'] = self.converters_masks_train[self.modlabels[0]].outputs['image'] - - if self.images_test or self.features_test: - if self.masks_test: - self.elastix_nodes_test[label].inputs['fixed_mask'] = self.converters_masks_test[label].outputs['image'] - self.elastix_nodes_test[label].inputs['moving_mask'] = self.converters_masks_test[self.modlabels[0]].outputs['image'] - - # Change the FinalBSpline Interpolation order to 0 as required for binarie images: see https://github.com/SuperElastix/elastix/wiki/FAQ - self.edittransformfile_nodes_train[label] = self.network.create_node('elastixtools/EditElastixTransformFile:0.1', tool_version= '0.1' , id='EditElastixTransformFile' + label) - self.edittransformfile_nodes_train[label].inputs['set'] = ["FinalBSplineInterpolationOrder=0"] - self.edittransformfile_nodes_train[label].inputs['transform'] = self.elastix_nodes_train[label].outputs['transform'][-1] - - if self.images_test or self.features_test: - self.edittransformfile_nodes_test[label] = self.network.create_node('elastixtools/EditElastixTransformFile:0.1', tool_version= '0.1' , id='EditElastixTransformFile' + label) - self.edittransformfile_nodes_test[label].inputs['set'] = ["FinalBSplineInterpolationOrder=0"] - self.edittransformfile_nodes_test[label].inputs['transform'] = self.elastix_nodes_test[label].outputs['transform'][-1] - - # Link data and transformation to transformix and source - self.transformix_seg_nodes_train[label].inputs['transform'] = self.edittransformfile_nodes_train[label].outputs['transform'] - self.calcfeatures_train[label].inputs['segmentation'] = self.transformix_seg_nodes_train[label].outputs['image'] - - self.transformix_im_nodes_train[label].inputs['transform'] = self.elastix_nodes_train[label].outputs['transform'][-1] - self.transformix_im_nodes_train[label].inputs['image'] = self.converters_im_train[self.modlabels[0]].outputs['image'] - - if self.images_test or self.features_test: - self.transformix_seg_nodes_test[label].inputs['transform'] = self.edittransformfile_nodes_test[label].outputs['transform'] - self.calcfeatures_test[label].inputs['segmentation'] = self.transformix_seg_nodes_test[label] .outputs['image'] - - self.transformix_im_nodes_test[label].inputs['transform'] = self.elastix_nodes_test[label].outputs['transform'][-1] - self.transformix_im_nodes_test[label].inputs['image'] = self.converters_im_test[self.modlabels[0]].outputs['image'] - - # Save output - self.sinks_transformations_train[label] = self.network.create_sink('ElastixTransformFile', id='transformations_train_' + label) - self.sinks_segmentations_elastix_train[label] = self.network.create_sink('ITKImageFile', id='segmentations_out_elastix_train_' + label) - self.sinks_images_elastix_train[label] = self.network.create_sink('ITKImageFile', id='images_out_elastix_train_' + label) - self.sinks_transformations_train[label].input = self.elastix_nodes_train[label].outputs['transform'] - self.sinks_segmentations_elastix_train[label].input = self.transformix_seg_nodes_train[label].outputs['image'] - self.sinks_images_elastix_train[label].input = self.transformix_im_nodes_train[label].outputs['image'] - - if self.images_test or self.features_test: - self.sinks_transformations_test[label] = self.network.create_sink('ElastixTransformFile', id='transformations_test_' + label) - self.sinks_segmentations_elastix_test[label] = self.network.create_sink('ITKImageFile', id='segmentations_out_elastix_test_' + label) - self.sinks_images_elastix_test[label] = self.network.create_sink('ITKImageFile', id='images_out_elastix_test_' + label) - self.sinks_transformations_elastix_test[label].input = self.elastix_nodes_test[label].outputs['transform'] - self.sinks_segmentations_elastix_test[label].input = self.transformix_seg_nodes_test[label].outputs['image'] - self.sinks_images_elastix_test[label].input = self.transformix_im_nodes_test[label].outputs['image'] - - if self.configs[nmod]['General']['Segmentix'] == 'True': - # Segmentix nodes ----------------------------------------------------- - # Use segmentix node to convert input segmentation into correct contour - if label not in self.sinks_segmentations_segmentix_train: - self.sinks_segmentations_segmentix_train[label] = self.network.create_sink('ITKImageFile', id='segmentations_out_segmentix_train_' + label) - - self.nodes_segmentix_train[label] = self.network.create_node('segmentix/Segmentix:1.0', tool_version='1.0', id='segmentix_train_' + label, resources=ResourceLimit(memory='6G')) - if hasattr(self, 'transformix_seg_nodes_train'): - if label in self.transformix_seg_nodes_train.keys(): - # Use output of registration in segmentix - self.nodes_segmentix_train[label].inputs['segmentation_in'] = self.transformix_seg_nodes_train[label].outputs['image'] - else: - # Use original segmentation - self.nodes_segmentix_train[label].inputs['segmentation_in'] = self.converters_seg_train[label].outputs['image'] - else: - # Use original segmentation - self.nodes_segmentix_train[label].inputs['segmentation_in'] = self.converters_seg_train[label].outputs['image'] - - self.nodes_segmentix_train[label].inputs['parameters'] = self.sources_parameters[label].output - self.calcfeatures_train[label].inputs['segmentation'] = self.nodes_segmentix_train[label].outputs['segmentation_out'] - self.sinks_segmentations_segmentix_train[label].input = self.nodes_segmentix_train[label].outputs['segmentation_out'] - - if self.images_test or self.features_test: - self.sinks_segmentations_segmentix_test[label] = self.network.create_sink('ITKImageFile', id='segmentations_out_segmentix_test_' + label) - self.nodes_segmentix_test[label] = self.network.create_node('segmentix/Segmentix:1.0', tool_version='1.0', id='segmentix_test_' + label, resources=ResourceLimit(memory='6G')) - if hasattr(self, 'transformix_seg_nodes_test'): - if label in self.transformix_seg_nodes_test.keys(): - # Use output of registration in segmentix - self.nodes_segmentix_test[label].inputs['segmentation_in'] = self.transformix_seg_nodes_test[label].outputs['image'] - else: - # Use original segmentation - self.nodes_segmentix_test[label].inputs['segmentation_in'] = self.converters_seg_test[label].outputs['image'] - else: - # Use original segmentation - self.nodes_segmentix_test[label].inputs['segmentation_in'] = self.converters_seg_test[label].outputs['image'] - - self.nodes_segmentix_test[label].inputs['parameters'] = self.sources_parameters[label].output - self.calcfeatures_test[label].inputs['segmentation'] = self.nodes_segmentix_test[label].outputs['segmentation_out'] - self.sinks_segmentations_segmentix_test[label].input = self.nodes_segmentix_test[label].outputs['segmentation_out'] - - if self.masks_train and len(self.masks_train) >= nmod + 1: - # Use masks - self.nodes_segmentix_train[label].inputs['mask'] = self.converters_masks_train[label].outputs['image'] - - if self.masks_test and len(self.masks_test) >= nmod + 1: - # Use masks - self.nodes_segmentix_test[label].inputs['mask'] = self.converters_masks_test[label].outputs['image'] - - else: - if self.segmode == 'Provided': - self.calcfeatures_train[label].inputs['segmentation'] = self.converters_seg_train[label].outputs['image'] - elif self.segmode == 'Register': - if nmod > 0: - self.calcfeatures_train[label].inputs['segmentation'] = self.transformix_seg_nodes_train[label].outputs['image'] - else: - self.calcfeatures_train[label].inputs['segmentation'] = self.converters_seg_train[label].outputs['image'] - - if self.images_test or self.features_test: - if self.segmode == 'Provided': - self.calcfeatures_train[label].inputs['segmentation'] = self.converters_seg_train[label].outputs['image'] - elif self.segmode == 'Register': - if nmod > 0: - self.calcfeatures_test[label].inputs['segmentation'] = self.transformix_seg_nodes_test[label] .outputs['image'] - else: - self.calcfeatures_train[label].inputs['segmentation'] = self.converters_seg_train[label].outputs['image'] - - # Classification nodes ----------------------------------------------------- - # Add the features from this modality to the classifier node input - self.links_C1_train[label] = self.classify.inputs['features_train'][str(label)] << self.calcfeatures_train[label].outputs['features'] - self.links_C1_train[label].collapse = 'train' - - if self.images_test or self.features_test: - # Add the features from this modality to the classifier node input - self.links_C1_test[label] = self.classify.inputs['features_test'][str(label)] << self.calcfeatures_test[label].outputs['features'] - self.links_C1_test[label].collapse = 'test' - - # Save output - self.sinks_features_train[label].input = self.calcfeatures_train[label].outputs['features'] - if self.images_test or self.features_test: - self.sinks_features_test[label].input = self.calcfeatures_test[label].outputs['features'] - - else: - # Features already provided: hence we can skip numerous nodes - self.sources_features_train = dict() - self.links_C1_train = dict() - - if self.features_test: - self.sources_features_test = dict() - self.links_C1_test = dict() - - # Create label for each modality/image - self.modlabels = list() - for num, mod in enumerate(image_types): - num = 0 - label = mod + str(num) - while label in self.sources_features_train.keys(): - # if label exists, add number to label - num += 1 - label = mod + str(num) - self.modlabels.append(label) - - # Create a node for the feature computation - self.sources_features_train[label] = self.network.create_source('HDF5', id='features_train_' + label, node_group='train') - - # Add the features from this modality to the classifier node input - self.links_C1_train[label] = self.classify.inputs['features_train'][str(label)] << self.sources_features_train[label].output - self.links_C1_train[label].collapse = 'train' - - if self.features_test: - self.sources_features_test[label] = self.network.create_source('HDF5', id='features_test_' + label, node_group='test') - self.links_C1_test[label] = self.classify.inputs['features_test'][str(label)] << self.sources_features_test[label].output - self.links_C1_test[label].collapse = 'test' - - else: - raise WORCexceptions.WORCIOError("Please provide labels.") - else: - raise WORCexceptions.WORCIOError("Please provide either images or features.")
                        - -
                        [docs] def build_testing(self): - ''' todo '''
                        - -
                        [docs] def set(self): - """ Set the FASTR source and sink data based on the given attributes.""" - self.fastrconfigs = list() - self.source_data = dict() - self.sink_data = dict() - - # If the configuration files are confiparse objects, write to file - for num, c in enumerate(self.configs): - if type(c) != configparser.ConfigParser: - # A filepath (not a fastr source) is provided. Hence we read - # the config file and convert it to a configparser object - config = configparser.ConfigParser() - config.read(c) - c = config - cfile = os.path.join(fastr.config.mounts['tmp'], 'WORC_' + self.name, ("config_{}_{}.ini").format(self.name, num)) - if not os.path.exists(os.path.dirname(cfile)): - os.makedirs(os.path.dirname(cfile)) - with open(cfile, 'w') as configfile: - c.write(configfile) - self.fastrconfigs.append(("vfs://tmp/{}/config_{}_{}.ini").format('WORC_' + self.name, self.name, num)) - - # Generate gridsearch parameter files if required - # TODO: We now use the first configuration for the classifier, but his needs to be separated from the rest per modality - self.source_data['config_classification_source'] = self.fastrconfigs[0] - - # Set source and sink data - self.source_data['patientclass_train'] = self.labels_train - self.source_data['patientclass_test'] = self.labels_test - - self.sink_data['classification'] = ("vfs://output/{}/svm_{{sample_id}}_{{cardinality}}{{ext}}").format(self.name) - self.sink_data['performance'] = ("vfs://output/{}/performance_{{sample_id}}_{{cardinality}}{{ext}}").format(self.name) - self.sink_data['config_classification_sink'] = ("vfs://output/{}/config_{{sample_id}}_{{cardinality}}{{ext}}").format(self.name) - - # Set the source data from the WORC objects you created - for num, label in enumerate(self.modlabels): - self.source_data['parameters_' + label] = self.fastrconfigs[num] - - # Add train data sources - if self.images_train and len(self.images_train) - 1 >= num: - self.source_data['images_train_' + label] = self.images_train[num] - - if self.masks_train and len(self.masks_train) - 1 >= num: - self.source_data['mask_train_' + label] = self.masks_train[num] - - if self.metadata_train and len(self.metadata_train) - 1 >= num: - self.source_data['metadata_train_' + label] = self.metadata_train[num] - - if self.segmentations_train and len(self.segmentations_train) - 1 >= num: - self.source_data['segmentations_train_' + label] = self.segmentations_train[num] - - if self.semantics_train and len(self.semantics_train) - 1 >= num: - self.source_data['semantics_train_' + label] = self.semantics_train[num] - - if self.features_train and len(self.features_train) - 1 >= num: - self.source_data['features_train_' + label] = self.features_train[num] - - if self.Elastix_Para: - # First modality does not need to be registered - if num > 0: - if len(self.Elastix_Para) > 1: - # Each modality has its own registration parameters - self.source_data['Elastix_Para_' + label] = self.Elastix_Para[num] - else: - # Use one fileset for all modalities - self.source_data['Elastix_Para_' + label] = self.Elastix_Para[0] - - # Add test data sources - if self.images_test and len(self.images_test) - 1 >= num: - self.source_data['images_test_' + label] = self.images_test[num] - - if self.masks_test and len(self.masks_test) - 1 >= num: - self.source_data['mask_test_' + label] = self.masks_test[num] - - if self.metadata_test and len(self.metadata_test) - 1 >= num: - self.source_data['metadata_test_' + label] = self.metadata_test[num] - - if self.segmentations_test and len(self.segmentations_test) - 1 >= num: - self.source_data['segmentations_test_' + label] = self.segmentations_test[num] - - if self.semantics_test and len(self.semantics_test) - 1 >= num: - self.source_data['semantics_test_' + label] = self.semantics_test[num] - - if self.features_test and len(self.features_test) - 1 >= num: - self.source_data['features_test_' + label] = self.features_test[num] - - self.sink_data['segmentations_out_segmentix_train_' + label] = ("vfs://output/{}/Segmentations/seg_{}_segmentix_{{sample_id}}_{{cardinality}}{{ext}}").format(self.name, label) - self.sink_data['segmentations_out_elastix_train_' + label] = ("vfs://output/{}/Elastix/seg_{}_elastix_{{sample_id}}_{{cardinality}}{{ext}}").format(self.name, label) - self.sink_data['images_out_elastix_train_' + label] = ("vfs://output/{}/Elastix/im_{}_elastix_{{sample_id}}_{{cardinality}}{{ext}}").format(self.name, label) - self.sink_data['features_train_' + label] = ("vfs://output/{}/Features/features_{}_{{sample_id}}_{{cardinality}}{{ext}}").format(self.name, label) - - if self.labels_test: - self.sink_data['segmentations_out_segmentix_test_' + label] = ("vfs://output/Segmentations/{}/seg_{}_segmentix_{{sample_id}}_{{cardinality}}{{ext}}").format(self.name, label) - self.sink_data['segmentations_out_elastix_test_' + label] = ("vfs://output/{}/Elastix/seg_{}_elastix_{{sample_id}}_{{cardinality}}{{ext}}").format(self.name, label) - self.sink_data['images_out_elastix_test_' + label] = ("vfs://output/{}/Images/im_{}_elastix_{{sample_id}}_{{cardinality}}{{ext}}").format(self.name, label) - self.sink_data['features_test_' + label] = ("vfs://output/{}/Features/features_{}_{{sample_id}}_{{cardinality}}{{ext}}").format(self.name, label) - - # Add elastix sinks if used - if self.segmode: - # Segmode is only non-empty if segmentations are provided - if self.segmode == 'Register': - self.sink_data['transformations_train_' + label] = ("vfs://output/{}/Elastix/transformation_{}_{{sample_id}}_{{cardinality}}{{ext}}").format(self.name, label) - if self.images_test or self.features_test: - self.sink_data['transformations_test_' + label] = ("vfs://output/{}/Elastix/transformation_{}_{{sample_id}}_{{cardinality}}{{ext}}").format(self.name, label)
                        - -
                        [docs] def execute(self): - """ Execute the network through the fastr.network.execute command. """ - # Draw and execute nwtwork - self.network.draw(file_path=self.network.id + '.svg', draw_dimensions=True) - self.network.execute(self.source_data, self.sink_data, execution_plugin=self.fastr_plugin, tmpdir=self.fastr_tmpdir)
                        - # self.network.execute(self.source_data, self.sink_data) - - -
                        [docs]class Tools(object): - ''' - This object can be used to create other pipelines besides the default - Radiomics executions. Currently only includes a registratio pipeline. - ''' -
                        [docs] def __init__(self): - self.Elastix = Elastix() - self.Evaluate = Evaluate()
                        -
                        - -
                        - -
                        -
                        - - -
                        - -
                        -

                        - © Copyright 2016 -- 2019, Biomedical Imaging Group Rotterdam, Departments of Medical Informatics and Radiology, Erasmus MC, Rotterdam, The Netherlands - -

                        -
                        - Built with Sphinx using a theme provided by Read the Docs. - -
                        - -
                        -
                        - -
                        - -
                        - - - - - - - - - - - - \ No newline at end of file diff --git a/build/lib/WORC/doc/_build/html/_modules/WORC/WORCpy27.html b/build/lib/WORC/doc/_build/html/_modules/WORC/WORCpy27.html deleted file mode 100644 index ce3e3d07..00000000 --- a/build/lib/WORC/doc/_build/html/_modules/WORC/WORCpy27.html +++ /dev/null @@ -1,1220 +0,0 @@ - - - - - - - - - - - WORC.WORCpy27 — WORC 2.1.3 documentation - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
                        - - - -
                        - - - - - -
                        - -
                        - - - - - - - - - - - - - - - - - -
                        - - - - -
                        -
                        -
                        -
                        - -

                        Source code for WORC.WORCpy27

                        -#!/usr/bin/env python
                        -
                        -# Copyright 2017-2018 Biomedical Imaging Group Rotterdam, Departments of
                        -# Medical Informatics and Radiology, Erasmus MC, Rotterdam, The Netherlands
                        -#
                        -# 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 configparser
                        -import fastr
                        -import os
                        -from random import randint
                        -import WORC.addexceptions as WORCexceptions
                        -import WORC.IOparser.config_WORC as config_io
                        -from WORC.tools.Elastix import Elastix
                        -from WORC.tools.Evaluate import Evaluate
                        -
                        -
                        -
                        [docs]class WORC(object): - """ - A Workflow for Optimal Radiomics Classification (WORC) object that - serves as a pipeline spawner and manager for optimizating radiomics - studies. Depending on the attributes set, the object will spawn an - appropriate pipeline and manage it. - - Note that many attributes are lists and can therefore contain multiple - instances. For example, when providing two sequences per patient, - the "images" list contains two items. The type of items in the lists - is described below. - - All objects that serve as source for your network, i.e. refer to - actual files to be used, should be formatted as fastr sources suited for - one of the fastr plugings, see also - http://fastr.readthedocs.io/en/stable/fastr.reference.html#ioplugin-reference - The objects should be lists of these fastr sources or dictionaries with the - sample ID's, e.g. - - images_train = [{'Patient001': vfs://input/CT001.nii.gz, - 'Patient002': vfs://input/CT002.nii.gz}, - {'Patient001': vfs://input/MR001.nii.gz, - 'Patient002': vfs://input/MR002.nii.gz}] - - Attributes - ------------------ - name: String, default 'WORC' - name of the network. - - configs: list, required - Configuration parameters, either ConfigParser objects - created through the defaultconfig function or paths of config .ini - files. (list, required) - - labels: list, required - Paths to files containing patient labels (.txt files). - - network: automatically generated - The FASTR network generated through the "build" function. - - images: list, optional - Paths refering to the images used for Radiomics computation. Images - should be of the ITK Image type. - - segmentations: list, optional - Paths refering to the segmentations used for Radiomics computation. - Segmentations should be of the ITK Image type. - - semantics: semantic features per image type (list, optional) - - masks: state which pixels of images are valid (list, optional) - - features: input Radiomics features for classification (list, optional) - - metadata: DICOM headers belonging to images (list, optional) - - Elastix_Para: parameter files for Elastix (list, optional) - - fastr_plugin: plugin to use for FASTR execution - - fastr_tempdir: temporary directory to use for FASTR execution - - additions: additional inputs for your network (dict, optional) - - source_data: data to use as sources for FASTR (dict) - - sink_data: data to use as sinks for FASTR (dict) - - CopyMetadata: Boolean, default True - when using elastix, copy metadata from image to segmentation or not - - """ - -
                        [docs] def __init__(self, name='WORC'): - """Initialize WORC object. Set the initial variables all to None, - except for some defaults. - - Arguments: - name: name of the nework (string, optional) - - """ - self.name = name - - # Initialize several objects - self.configs = list() - self.fastrconfigs = list() - - self.images_train = list() - self.segmentations_train = list() - self.semantics_train = list() - self.labels_train = list() - self.masks_train = list() - self.features_train = list() - self.metadata_train = list() - - self.images_test = list() - self.segmentations_test = list() - self.semantics_test = list() - self.labels_test = list() - self.masks_test = list() - self.features_test = list() - self.metadata_test = list() - - self.Elastix_Para = list() - - # Set some defaults, name - self.fastr_plugin = 'ProcessPoolExecution' - if name == '': - name = [randint(0, 9) for p in range(0, 5)] - self.fastr_tmpdir = os.path.join(fastr.config.mounts['tmp'], 'fastr' + str(name)) - else: - self.fastr_tmpdir = os.path.join(fastr.config.mounts['tmp'], name) - self.additions = dict() - self.CopyMetadata = True - self.segmode = []
                        - -
                        [docs] def defaultconfig(self): - """Generate a configparser object holding all default configuration values. - - Returns: - config: configparser configuration file - - """ - # TODO: cluster parallel execution parameters - config = configparser.ConfigParser() - config.optionxform = str - - # General configuration of WORC - config['General'] = dict() - config['General']['cross_validation'] = 'True' - config['General']['Segmentix'] = 'False' - config['General']['PCE'] = 'False' # We do not yet provide this module - config['General']['FeatureCalculator'] = 'CalcFeatures' - config['General']['Preprocessing'] = 'PreProcess' - config['General']['RegistrationNode'] = "Elastix" - config['General']['TransformationNode'] = "Transformix" - config['General']['Joblib_ncores'] = '4' - config['General']['Joblib_backend'] = 'multiprocessing' - config['General']['tempsave'] = 'False' - - # Segmentix - config['Segmentix'] = dict() - config['Segmentix']['mask'] = 'subtract' - config['Segmentix']['segtype'] = 'None' - config['Segmentix']['segradius'] = '5' - config['Segmentix']['N_blobs'] = '1' - config['Segmentix']['fillholes'] = 'False' - - # Preprocessing - config['Normalize'] = dict() - config['Normalize']['ROI'] = 'Full' - config['Normalize']['Method'] = 'z_score' - - # PREDICT - Feature calculation - config['ImageFeatures'] = dict() - config['ImageFeatures']['orientation'] = 'True' - config['ImageFeatures']['texture'] = 'all' - config['ImageFeatures']['coliage'] = 'False' - config['ImageFeatures']['vessel'] = 'False' - config['ImageFeatures']['log'] = 'False' - config['ImageFeatures']['phase'] = 'False' - - ## Parameter settings for PREDICT feature calculation - # Defines what should be done with the images - config['ImageFeatures']['image_type'] = 'CT' - - # Define frequencies for gabor filter in pixels - config['ImageFeatures']['gabor_frequencies'] = '0.05, 0.2, 0.5' - - # Gabor, GLCM angles in degrees and radians, respectively - config['ImageFeatures']['gabor_angles'] = '0, 45, 90, 135' - config['ImageFeatures']['GLCM_angles'] = '0, 0.79, 1.57, 2.36' - - # GLCM discretization levels, distances in pixels - config['ImageFeatures']['GLCM_levels'] = '16' - config['ImageFeatures']['GLCM_distances'] = '1, 3' - - # LBP radius, number of points in pixels - config['ImageFeatures']['LBP_radius'] = '3, 8, 15' - config['ImageFeatures']['LBP_npoints'] = '12, 24, 36' - - # Phase features minimal wavelength and number of scales - config['ImageFeatures']['phase_minwavelength'] = '3' - config['ImageFeatures']['phase_nscale'] = '5' - - # Log features sigma of Gaussian in pixels - config['ImageFeatures']['log_sigma'] = '1, 5, 10' - - # Vessel features scale range, steps for the range - config['ImageFeatures']['vessel_scale_range'] = '1, 10' - config['ImageFeatures']['vessel_scale_step'] = '2' - - # Vessel features radius for erosion to determine boudnary - config['ImageFeatures']['vessel_radius'] = '5' - - # Feature selection - config['Featsel'] = dict() - config['Featsel']['Variance'] = 'True, False' - config['Featsel']['GroupwiseSearch'] = 'True' - config['Featsel']['SelectFromModel'] = 'False' - config['Featsel']['UsePCA'] = 'False' - config['Featsel']['PCAType'] = '95variance' - config['Featsel']['StatisticalTestUse'] = 'False' - config['Featsel']['StatisticalTestMetric'] = 'ttest, Welch, Wilcoxon, MannWhitneyU' - config['Featsel']['StatisticalTestThreshold'] = '0.02, 0.2' - config['Featsel']['ReliefUse'] = 'False' - config['Featsel']['ReliefNN'] = '2, 4' - config['Featsel']['ReliefSampleSize'] = '1, 1' - config['Featsel']['ReliefDistanceP'] = '1, 3' - config['Featsel']['ReliefNumFeatures'] = '25, 200' - - # Groupwie Featureselection options - config['SelectFeatGroup'] = dict() - config['SelectFeatGroup']['shape_features'] = 'True, False' - config['SelectFeatGroup']['histogram_features'] = 'True, False' - config['SelectFeatGroup']['orientation_features'] = 'True, False' - config['SelectFeatGroup']['texture_Gabor_features'] = 'True, False' - config['SelectFeatGroup']['texture_GLCM_features'] = 'True, False' - config['SelectFeatGroup']['texture_GLCMMS_features'] = 'True, False' - config['SelectFeatGroup']['texture_GLRLM_features'] = 'True, False' - config['SelectFeatGroup']['texture_GLSZM_features'] = 'True, False' - config['SelectFeatGroup']['texture_NGTDM_features'] = 'True, False' - config['SelectFeatGroup']['texture_LBP_features'] = 'True, False' - config['SelectFeatGroup']['patient_features'] = 'False' - config['SelectFeatGroup']['semantic_features'] = 'False' - config['SelectFeatGroup']['coliage_features'] = 'False' - config['SelectFeatGroup']['log_features'] = 'False' - config['SelectFeatGroup']['vessel_features'] = 'False' - config['SelectFeatGroup']['phase_features'] = 'False' - - # Feature imputation - config['Imputation'] = dict() - config['Imputation']['use'] = 'False' - config['Imputation']['strategy'] = 'mean, median, most_frequent, constant, knn' - config['Imputation']['n_neighbors'] = '5, 5' - - # Classification - config['Classification'] = dict() - config['Classification']['fastr'] = 'False' - config['Classification']['fastr_plugin'] = self.fastr_plugin - config['Classification']['classifiers'] = 'SVM' - config['Classification']['max_iter'] = '100000' - config['Classification']['SVMKernel'] = 'poly' - config['Classification']['SVMC'] = '0, 6' - config['Classification']['SVMdegree'] = '1, 6' - config['Classification']['SVMcoef0'] = '0, 1' - config['Classification']['SVMgamma'] = '-5, 5' - config['Classification']['RFn_estimators'] = '10, 90' - config['Classification']['RFmin_samples_split'] = '2, 3' - config['Classification']['RFmax_depth'] = '5, 5' - config['Classification']['LRpenalty'] = 'l2, l1' - config['Classification']['LRC'] = '0.01, 1.0' - config['Classification']['LDA_solver'] = 'svd, lsqr, eigen' - config['Classification']['LDA_shrinkage'] = '-5, 5' - config['Classification']['QDA_reg_param'] = '-5, 5' - config['Classification']['ElasticNet_alpha'] = '-5, 5' - config['Classification']['ElasticNet_l1_ratio'] = '0, 1' - config['Classification']['SGD_alpha'] = '-5, 5' - config['Classification']['SGD_l1_ratio'] = '0, 1' - config['Classification']['SGD_loss'] = 'hinge, squared_hinge, modified_huber' - config['Classification']['SGD_penalty'] = 'none, l2, l1' - config['Classification']['CNB_alpha'] = '0, 1' - - # CrossValidation - config['CrossValidation'] = dict() - config['CrossValidation']['N_iterations'] = '100' - config['CrossValidation']['test_size'] = '0.2' - - # Options for the labels that are used (not only genetics) - config['Genetics'] = dict() - config['Genetics']['label_names'] = 'Label1, Label2' - config['Genetics']['modus'] = 'singlelabel' - config['Genetics']['url'] = 'WIP' - config['Genetics']['projectID'] = 'WIP' - - # Hyperparameter optimization options - config['HyperOptimization'] = dict() - config['HyperOptimization']['scoring_method'] = 'f1_weighted' - config['HyperOptimization']['test_size'] = '0.15' - config['HyperOptimization']['N_iterations'] = '10000' - config['HyperOptimization']['n_jobspercore'] = '2000' # only relevant when using fastr in classification - - # Feature scaling options - config['FeatureScaling'] = dict() - config['FeatureScaling']['scale_features'] = 'True' - config['FeatureScaling']['scaling_method'] = 'z_score' - - # Sample processing options - config['SampleProcessing'] = dict() - config['SampleProcessing']['SMOTE'] = 'True, False' - config['SampleProcessing']['SMOTE_ratio'] = '1, 0' - config['SampleProcessing']['SMOTE_neighbors'] = '5, 15' - config['SampleProcessing']['Oversampling'] = 'False' - - # Ensemble options - config['Ensemble'] = dict() - config['Ensemble']['Use'] = 'False' # Still WIP - - # BUG: the FASTR XNAT plugin can only retreive folders. We therefore need to add the filenames of the resources manually - # This should be fixed from fastr > 2.0.0: need to update. - config['FASTR_bugs'] = dict() - config['FASTR_bugs']['images'] = 'image.nii.gz' - config['FASTR_bugs']['segmentations'] = 'mask.nii.gz' - - return config
                        - -
                        [docs] def add_tools(self): - self.Tools = Tools()
                        - -
                        [docs] def build(self, wtype='training'): - """Build the network based on the given attributes. - - Parameters - ---------- - wtype: string, default 'training' - Specify the WORC execution type. - - testing: use if you have a trained classifier and want to - train it on some new images. - - training: use if you want to train a classifier from a dataset. - - """ - - if wtype == 'training': - self.build_training() - self.wtype = wtype - elif wtype == 'testing': - self.build_testing() - self.wtype = wtype
                        - -
                        [docs] def build_training(self): - """Build the training network based on the given attributes.""" - # We either need images or features for Radiomics - if self.images_train or self.features_train: - # We currently require labels for supervised learning - if self.labels_train: - if not self.configs: - print("No configuration given, assuming default") - if self.images_train: - self.configs = [self.defaultconfig()] * len(self.images_train) - else: - self.configs = [self.defaultconfig()] * len(self.features_train) - self.network = fastr.Network('WORC_' + self.name) - - # BUG: We currently use the first configuration as general config - image_types = list() - for c in range(len(self.configs)): - if type(self.configs[c]) == str: - # Probably, c is a configuration file - self.configs[c] = config_io.load_config(self.configs[c]) - image_types.append(self.configs[c]['ImageFeatures']['image_type']) - - # Classification tool and label source - self.network.source_patientclass_train = self.network.create_source('PatientInfoFile', id_='patientclass_train', nodegroup='pctrain') - if self.labels_test: - self.network.source_patientclass_test = self.network.create_source('PatientInfoFile', id_='patientclass_test', nodegroup='pctest') - - self.network.classify = self.network.create_node('TrainClassifier', memory='12G', id_='classify') - - # Outputs - self.network.sink_classification = self.network.create_sink('HDF5', id_='classification') - self.network.sink_performance = self.network.create_sink('JsonFile', id_='performance') - - # Links - self.network.source_class_config = self.network.create_source('ParameterFile', id_='config_classification', nodegroup='conf') - # self.network.source_class_parameters = self.network.create_source('JsonFile', id_='parameters_classification') - # self.network.classify.inputs['parameters'] = self.network.source_class_parameters.output - self.network.link_class_1 = self.network.create_link(self.network.source_class_config.output, self.network.classify.inputs['config'][0]) - self.network.link_class_2 = self.network.create_link(self.network.source_patientclass_train.output, self.network.classify.inputs['patientclass_train']) - self.network.link_class_1.collapse = 'conf' - self.network.link_class_2.collapse = 'pctrain' - - if self.images_test or self.features_test: - # FIXME: the naming here is ugly - self.network.link_class_3 = self.network.create_link(self.network.source_patientclass_test.output, self.network.classify.inputs['patientclass_test']) - self.network.link_class_3.collapse = 'pctest' - - self.network.sink_classification.input = self.network.classify.outputs['classification'] - self.network.sink_performance.input = self.network.classify.outputs['performance'] - - if not self.features_train: - # Create nodes to compute features - self.network.sources_parameters = dict() - - self.network.calcfeatures_train = dict() - self.network.preprocessing_train = dict() - self.network.sources_images_train = dict() - self.network.sinks_features_train = dict() - self.network.converters_im_train = dict() - self.network.converters_seg_train = dict() - self.network.links_C1_train = dict() - - if self.images_test or self.features_test: - # A test set is supplied, for which nodes also need to be created - self.network.preprocessing_test = dict() - self.network.calcfeatures_test = dict() - self.network.sources_images_test = dict() - self.network.sinks_features_test = dict() - self.network.converters_im_test = dict() - self.network.converters_seg_test = dict() - self.network.links_C1_test = dict() - - # Check which nodes are necessary - if not self.segmentations_train: - message = "No automatic segmentation method is yet implemented." - raise WORCexceptions.WORCNotImplementedError(message) - - elif len(self.segmentations_train) == len(image_types): - # Segmentations provided - self.network.sources_segmentations_train = dict() - self.network.sources_segmentations_test = dict() - self.segmode = 'Provided' - - elif len(self.segmentations_train) == 1: - # Assume segmentations need to be registered to other modalities - self.network.sources_segmentation = dict() - self.segmode = 'Register' - - self.network.source_Elastix_Parameters = dict() - self.network.elastix_nodes_train = dict() - self.network.transformix_seg_nodes_train = dict() - self.network.sources_segmentations_train = dict() - self.network.sinks_transformations_train = dict() - self.network.sinks_segmentations_elastix_train = dict() - self.network.sinks_images_elastix_train = dict() - self.network.converters_seg_train = dict() - self.network.edittransformfile_nodes_train = dict() - self.network.transformix_im_nodes_train = dict() - - self.network.elastix_nodes_test = dict() - self.network.transformix_seg_nodes_test = dict() - self.network.sources_segmentations_test = dict() - self.network.sinks_transformations_test = dict() - self.network.sinks_segmentations_elastix_test = dict() - self.network.sinks_images_elastix_test = dict() - self.network.converters_seg_test = dict() - self.network.edittransformfile_nodes_test = dict() - self.network.transformix_im_nodes_test = dict() - pass - - # BUG: We assume that first type defines if we use segmentix - if self.configs[0]['General']['Segmentix'] == 'True': - # Use the segmentix toolbox for segmentation processing - self.network.sinks_segmentations_segmentix_train = dict() - self.network.sources_masks_train = dict() - self.network.converters_masks_train = dict() - self.network.nodes_segmentix_train = dict() - - if self.images_test or self.features_test: - # Also use segmentix on the tes set - self.network.sinks_segmentations_segmentix_test = dict() - self.network.sources_masks_test = dict() - self.network.converters_masks_test = dict() - self.network.nodes_segmentix_test = dict() - - if self.semantics_train: - # Semantic features are supplied - self.network.sources_semantics_train = dict() - - if self.metadata_train: - # Metadata to extract patient features from is supplied - self.network.sources_metadata_train = dict() - - if self.semantics_test: - # Semantic features are supplied - self.network.sources_semantics_test = dict() - - if self.metadata_test: - # Metadata to extract patient features from is supplied - self.network.sources_metadata_test = dict() - - # Create a part of the pipeline for each modality - self.modlabels = list() - for nmod, mod in enumerate(image_types): - # Create label for each modality/image - num = 0 - label = mod + '_' + str(num) - while label in self.network.calcfeatures_train.keys(): - # if label already exists, add number to label - num += 1 - label = mod + '_' + str(num) - self.modlabels.append(label) - - # Create required sources and sinks - self.network.sources_parameters[label] = self.network.create_source('ParameterFile', id_='parameters_' + label) - self.network.sources_images_train[label] = self.network.create_source('ITKImageFile', id_='images_train_' + label, nodegroup='train') - self.network.sinks_features_train[label] = self.network.create_sink('HDF5', id_='features_train_' + label) - if self.images_test or self.features_test: - self.network.sources_images_test[label] = self.network.create_source('ITKImageFile', id_='images_test_' + label, nodegroup='test') - self.network.sinks_features_test[label] = self.network.create_sink('HDF5', id_='features_test_' + label) - - if self.metadata_train and len(self.metadata_train) >= nmod + 1: - self.network.sources_metadata_train[label] = self.network.create_source('DicomImageFile', id_='metadata_train_' + label, nodegroup='train') - - if self.metadata_test and len(self.metadata_test) >= nmod + 1: - self.network.sources_metadata_test[label] = self.network.create_source('DicomImageFile', id_='metadata_test_' + label, nodegroup='test') - - if self.masks_train and len(self.masks_train) >= nmod + 1: - # Create mask source and convert - self.network.sources_masks_train[label] = self.network.create_source('ITKImageFile', id_='mask_train_' + label, nodegroup='train') - self.network.converters_masks_train[label] = self.network.create_node('WORCCastConvert', memory='4G', id_='convert_mask_train_' + label, nodegroup='train') - self.network.converters_masks_train[label].inputs['image'] = self.network.sources_masks_train[label].output - - if self.masks_test and len(self.masks_test) >= nmod + 1: - # Create mask source and convert - self.network.sources_masks_test[label] = self.network.create_source('ITKImageFile', id_='mask_test_' + label, nodegroup='test') - self.network.converters_masks_test[label] = self.network.create_node('WORCCastConvert', memory='4G', id_='convert_mask_test_' + label, nodegroup='test') - self.network.converters_masks_test[label].inputs['image'] = self.network.sources_masks_test[label].output - - # First convert the images - if any(modality in mod for modality in ['MR', 'CT', 'MG', 'PET']): - # Use ITKTools PXCastConvet for converting image formats - self.network.converters_im_train[label] = self.network.create_node('WORCCastConvert', memory='4G', id_='convert_im_train_' + label) - if self.images_test or self.features_test: - self.network.converters_im_test[label] = self.network.create_node('WORCCastConvert', memory='4G', id_='convert_im_test_' + label) - - elif 'DTI' in mod: - # TODO: This reader is currently missing - self.network.converters_im_train[label] = self.network.create_node('DTIreader', memory='4G', id_='convert_im_train_' + label) - if self.images_test or self.features_test: - self.network.converters_im_test[label] = self.network.create_node('DTIreader', memory='4G', id_='convert_im_test_' + label) - - else: - raise WORCexceptions.WORCTypeError(('No valid image type for modality {}: {} provided.').format(str(nmod), mod)) - - # Create required links - self.network.converters_im_train[label].inputs['image'] = self.network.sources_images_train[label].output - if self.images_test or self.features_test: - self.network.converters_im_test[label].inputs['image'] = self.network.sources_images_test[label].output - - # ----------------------------------------------------- - # Preprocessing - # Create nodes - preprocess_node = str(self.configs[nmod]['General']['Preprocessing']) - self.network.preprocessing_train[label] = self.network.create_node(preprocess_node, memory='4G', id_='preprocessing_train_' + label) - if self.images_test or self.features_test: - self.network.preprocessing_test[label] = self.network.create_node(preprocess_node, memory='4G', id_='preprocessing_test_' + label) - - # Create required links - self.network.preprocessing_train[label].inputs['parameters'] = self.network.sources_parameters[label].output - self.network.preprocessing_train[label].inputs['image'] = self.network.converters_im_train[label].outputs['image'] - - if self.images_test or self.features_test: - self.network.preprocessing_test[label].inputs['parameters'] = self.network.sources_parameters[label].output - self.network.preprocessing_test[label].inputs['image'] = self.network.converters_im_test[label].outputs['image'] - - if self.metadata_train and len(self.metadata_train) >= nmod + 1: - self.network.preprocessing_train[label].inputs['metadata'] = self.network.sources_metadata_train[label].output - - if self.metadata_test and len(self.metadata_test) >= nmod + 1: - self.network.preprocessing_test[label].inputs['metadata'] = self.network.sources_metadata_test[label].output - - # ----------------------------------------------------- - # Create a feature calculator node - calcfeat_node = str(self.configs[nmod]['General']['FeatureCalculator']) - self.network.calcfeatures_train[label] = self.network.create_node(calcfeat_node, memory='14G', id_='calcfeatures_train_' + label) - if self.images_test or self.features_test: - self.network.calcfeatures_test[label] = self.network.create_node(calcfeat_node, memory='14G', id_='calcfeatures_test_' + label) - - # Create required links - self.network.calcfeatures_train[label].inputs['parameters'] = self.network.sources_parameters[label].output - self.network.calcfeatures_train[label].inputs['image'] = self.network.preprocessing_train[label].outputs['image'] - - if self.images_test or self.features_test: - self.network.calcfeatures_test[label].inputs['parameters'] = self.network.sources_parameters[label].output - self.network.calcfeatures_test[label].inputs['image'] = self.network.preprocessing_test[label].outputs['image'] - - if self.metadata_train and len(self.metadata_train) >= nmod + 1: - self.network.calcfeatures_train[label].inputs['metadata'] = self.network.sources_metadata_train[label].output - - if self.metadata_train and len(self.metadata_test) >= nmod + 1: - self.network.calcfeatures_train[label].inputs['metadata'] = self.network.sources_metadata_train[label].output - - if self.semantics_train and len(self.semantics_train) >= nmod + 1: - self.network.sources_semantics_train[label] = self.network.create_source('CSVFile', id_='semantics_train_' + label) - self.network.calcfeatures_train[label].inputs['semantics'] = self.network.sources_semantics_train[label].output - - if self.semantics_test and len(self.semantics_test) >= nmod + 1: - self.network.sources_semantics_test[label] = self.network.create_source('CSVFile', id_='semantics_test_' + label) - self.network.calcfeatures_test[label].inputs['semantics'] = self.network.sources_semantics_test[label].output - - if self.segmode == 'Provided': - # Segmentation ----------------------------------------------------- - # Use the provided segmantions for each modality - self.network.sources_segmentations_train[label] = self.network.create_source('ITKImageFile', id_='segmentations_train_' + label, nodegroup='train') - self.network.converters_seg_train[label] = self.network.create_node('WORCCastConvert', memory='4G', id_='convert_seg_train_' + label) - self.network.converters_seg_train[label].inputs['image'] = self.network.sources_segmentations_train[label].output - - if self.images_test or self.features_test: - self.network.sources_segmentations_test[label] = self.network.create_source('ITKImageFile', id_='segmentations_test_' + label, nodegroup='test') - self.network.converters_seg_test[label] = self.network.create_node('WORCCastConvert', memory='4G', id_='convert_seg_test_' + label) - self.network.converters_seg_test[label].inputs['image'] = self.network.sources_segmentations_test[label].output - - elif self.segmode == 'Register': - # Registration nodes ----------------------------------------------------- - # Align segmentation of first modality to others using registration with Elastix - - # Create sources and converter for only for the given segmentation, which should be on the first modality - if nmod == 0: - self.network.sources_segmentations_train[label] = self.network.create_source('ITKImageFile', id_='segmentations_train_' + label, nodegroup='input') - self.network.converters_seg_train[label] = self.network.create_node('WORCCastConvert', memory='4G', id_='convert_seg_train_' + label) - self.network.converters_seg_train[label].inputs['image'] = self.network.sources_segmentations_train[label].output - - if self.images_test or self.features_test: - self.network.sources_segmentations_test[label] = self.network.create_source('ITKImageFile', id_='segmentations_test_' + label, nodegroup='input') - self.network.converters_seg_test[label] = self.network.create_node('WORCCastConvert', memory='4G', id_='convert_seg_test_' + label) - self.network.converters_seg_test[label].inputs['image'] = self.network.sources_segmentations_test[label].output - - # Assume provided segmentation is on first modality - if nmod > 0: - # Use elastix and transformix for registration - # NOTE: Assume elastix node type is on first configuration - elastix_node = str(self.configs[0]['General']['RegistrationNode']) - transformix_node = str(self.configs[0]['General']['TransformationNode']) - self.network.elastix_nodes_train[label] = self.network.create_node(elastix_node, memory='4G', id_='elastix_train_' + label) - self.network.transformix_seg_nodes_train[label] = self.network.create_node(transformix_node, id_='transformix_seg_train_' + label) - self.network.transformix_im_nodes_train[label] = self.network.create_node(transformix_node, id_='transformix_im_train_' + label) - - if self.images_test or self.features_test: - self.network.elastix_nodes_test[label] = self.network.create_node(elastix_node, memory='4G', id_='elastix_test_' + label) - self.network.transformix_seg_nodes_test[label] = self.network.create_node(transformix_node, id_='transformix_seg_test_' + label) - self.network.transformix_im_nodes_test[label] = self.network.create_node(transformix_node, id_='transformix_im_test_' + label) - - # Create sources_segmentation - # M1 = moving, others = fixed - self.network.elastix_nodes_train[label].inputs['fixed_image'] = self.network.converters_im_train[label].outputs['image'] - self.network.elastix_nodes_train[label].inputs['moving_image'] = self.network.converters_im_train[self.modlabels[0]].outputs['image'] - - # Add node that copies metadata from the image to the segmentation if required - if self.CopyMetadata: - # Copy metadata from the image which was registered to the segmentation, if it is not created yet - if not hasattr(self.network, "copymetadata_nodes_train"): - # NOTE: Do this for first modality, as we assume segmentation is on that one - self.network.copymetadata_nodes_train = dict() - self.network.copymetadata_nodes_train[self.modlabels[0]] = self.network.create_node("CopyMetadata", id_='CopyMetadata_train_' + self.modlabels[0]) - self.network.copymetadata_nodes_train[self.modlabels[0]].inputs["source"] = self.network.converters_im_train[self.modlabels[0]].outputs['image'] - self.network.copymetadata_nodes_train[self.modlabels[0]].inputs["destination"] = self.network.converters_seg_train[self.modlabels[0]].outputs['image'] - self.network.transformix_seg_nodes_train[label].inputs['image'] = self.network.copymetadata_nodes_train[self.modlabels[0]].outputs['output'] - else: - self.network.transformix_seg_nodes_train[label].inputs['image'] = self.network.converters_seg_train[self.modlabels[0]].outputs['image'] - - if self.images_test or self.features_test: - self.network.elastix_nodes_test[label].inputs['fixed_image'] = self.network.converters_im_test[label].outputs['image'] - self.network.elastix_nodes_test[label].inputs['moving_image'] = self.network.converters_im_test[self.modlabels[0]].outputs['image'] - - if self.CopyMetadata: - # Copy metadata from the image which was registered to the segmentation - if not hasattr(self.network, "copymetadata_nodes_test"): - # NOTE: Do this for first modality, as we assume segmentation is on that one - self.network.copymetadata_nodes_test = dict() - self.network.copymetadata_nodes_test[self.modlabels[0]] = self.network.create_node("CopyMetadata", id_='CopyMetadata_test_' + self.modlabels[0]) - self.network.copymetadata_nodes_test[self.modlabels[0]].inputs["source"] = self.network.converters_im_test[self.modlabels[0]].outputs['image'] - self.network.copymetadata_nodes_test[self.modlabels[0]].inputs["destination"] = self.network.converters_seg_test[self.modlabels[0]].outputs['image'] - self.network.transformix_seg_nodes_test[label].inputs['image'] = self.network.copymetadata_nodes_test[self.modlabels[0]].outputs['output'] - else: - self.network.transformix_seg_nodes_test[label].inputs['image'] = self.network.converters_seg_test[self.modlabels[0]].outputs['image'] - - # Apply registration to input modalities - self.network.source_Elastix_Parameters[label] = self.network.create_source('ElastixParameterFile', id_='Elastix_Para_' + label, nodegroup='elpara') - self.link_elparam_train = self.network.create_link(self.network.source_Elastix_Parameters[label].output, - self.network.elastix_nodes_train[label].inputs['parameters']) - self.link_elparam_train.collapse = 'elpara' - - if self.images_test or self.features_test: - self.link_elparam_test = self.network.create_link(self.network.source_Elastix_Parameters[label].output, - self.network.elastix_nodes_test[label].inputs['parameters']) - self.link_elparam_test.collapse = 'elpara' - - if self.masks_train: - self.network.elastix_nodes_train[label].inputs['fixed_mask'] = self.network.converters_masks_train[label].outputs['image'] - self.network.elastix_nodes_train[label].inputs['moving_mask'] = self.network.converters_masks_train[self.modlabels[0]].outputs['image'] - - if self.images_test or self.features_test: - if self.masks_test: - self.network.elastix_nodes_test[label].inputs['fixed_mask'] = self.network.converters_masks_test[label].outputs['image'] - self.network.elastix_nodes_test[label].inputs['moving_mask'] = self.network.converters_masks_test[self.modlabels[0]].outputs['image'] - - # Change the FinalBSpline Interpolation order to 0 as required for binarie images: see https://github.com/SuperElastix/elastix/wiki/FAQ - self.network.edittransformfile_nodes_train[label] = self.network.create_node('EditElastixTransformFile', id_='EditElastixTransformFile' + label) - self.network.edittransformfile_nodes_train[label].inputs['set'] = ["FinalBSplineInterpolationOrder=0"] - self.network.edittransformfile_nodes_train[label].inputs['transform'] = self.network.elastix_nodes_train[label].outputs['transform'][-1] - - if self.images_test or self.features_test: - self.network.edittransformfile_nodes_test[label] = self.network.create_node('EditElastixTransformFile', id_='EditElastixTransformFile' + label) - self.network.edittransformfile_nodes_test[label].inputs['set'] = ["FinalBSplineInterpolationOrder=0"] - self.network.edittransformfile_nodes_test[label].inputs['transform'] = self.network.elastix_nodes_test[label].outputs['transform'][-1] - - # Link data and transformation to transformix and source - self.network.transformix_seg_nodes_train[label].inputs['transform'] = self.network.edittransformfile_nodes_train[label].outputs['transform'] - self.network.calcfeatures_train[label].inputs['segmentation'] = self.network.transformix_seg_nodes_train[label].outputs['image'] - - self.network.transformix_im_nodes_train[label].inputs['transform'] = self.network.elastix_nodes_train[label].outputs['transform'][-1] - self.network.transformix_im_nodes_train[label].inputs['image'] = self.network.converters_im_train[self.modlabels[0]].outputs['image'] - - if self.images_test or self.features_test: - self.network.transformix_seg_nodes_test[label].inputs['transform'] = self.network.edittransformfile_nodes_test[label].outputs['transform'] - self.network.calcfeatures_test[label].inputs['segmentation'] = self.network.transformix_seg_nodes_test[label] .outputs['image'] - - self.network.transformix_im_nodes_test[label].inputs['transform'] = self.network.elastix_nodes_test[label].outputs['transform'][-1] - self.network.transformix_im_nodes_test[label].inputs['image'] = self.network.converters_im_test[self.modlabels[0]].outputs['image'] - - # Save output - self.network.sinks_transformations_train[label] = self.network.create_sink('ElastixTransformFile', id_='transformations_train_' + label) - self.network.sinks_segmentations_elastix_train[label] = self.network.create_sink('ITKImageFile', id_='segmentations_out_elastix_train_' + label) - self.network.sinks_images_elastix_train[label] = self.network.create_sink('ITKImageFile', id_='images_out_elastix_train_' + label) - self.network.sinks_transformations_train[label].input = self.network.elastix_nodes_train[label].outputs['transform'] - self.network.sinks_segmentations_elastix_train[label].input = self.network.transformix_seg_nodes_train[label].outputs['image'] - self.network.sinks_images_elastix_train[label].input = self.network.transformix_im_nodes_train[label].outputs['image'] - - if self.images_test or self.features_test: - self.network.sinks_transformations_test[label] = self.network.create_sink('ElastixTransformFile', id_='transformations_test_' + label) - self.network.sinks_segmentations_elastix_test[label] = self.network.create_sink('ITKImageFile', id_='segmentations_out_elastix_test_' + label) - self.network.sinks_images_elastix_test[label] = self.network.create_sink('ITKImageFile', id_='images_out_elastix_test_' + label) - self.network.sinks_transformations_elastix_test[label].input = self.network.elastix_nodes_test[label].outputs['transform'] - self.network.sinks_segmentations_elastix_test[label].input = self.network.transformix_seg_nodes_test[label].outputs['image'] - self.network.sinks_images_elastix_test[label].input = self.network.transformix_im_nodes_test[label].outputs['image'] - - if self.configs[nmod]['General']['Segmentix'] == 'True': - # Segmentix nodes ----------------------------------------------------- - # Use segmentix node to convert input segmentation into correct contour - if label not in self.network.sinks_segmentations_segmentix_train: - self.network.sinks_segmentations_segmentix_train[label] = self.network.create_sink('ITKImageFile', id_='segmentations_out_segmentix_train_' + label) - - self.network.nodes_segmentix_train[label] = self.network.create_node('Segmentix', memory='6G', id_='segmentix_train_' + label) - if hasattr(self.network, 'transformix_seg_nodes_train'): - if label in self.network.transformix_seg_nodes_train.keys(): - # Use output of registration in segmentix - self.network.nodes_segmentix_train[label].inputs['segmentation_in'] = self.network.transformix_seg_nodes_train[label].outputs['image'] - else: - # Use original segmentation - self.network.nodes_segmentix_train[label].inputs['segmentation_in'] = self.network.converters_seg_train[label].outputs['image'] - else: - # Use original segmentation - self.network.nodes_segmentix_train[label].inputs['segmentation_in'] = self.network.converters_seg_train[label].outputs['image'] - - self.network.nodes_segmentix_train[label].inputs['parameters'] = self.network.sources_parameters[label].output - self.network.calcfeatures_train[label].inputs['segmentation'] = self.network.nodes_segmentix_train[label].outputs['segmentation_out'] - self.network.sinks_segmentations_segmentix_train[label].input = self.network.nodes_segmentix_train[label].outputs['segmentation_out'] - - if self.images_test or self.features_test: - self.network.sinks_segmentations_segmentix_test[label] = self.network.create_sink('ITKImageFile', id_='segmentations_out_segmentix_test_' + label) - self.network.nodes_segmentix_test[label] = self.network.create_node('Segmentix', memory='6G', id_='segmentix_test_' + label) - if hasattr(self.network, 'transformix_seg_nodes_test'): - if label in self.network.transformix_seg_nodes_test.keys(): - # Use output of registration in segmentix - self.network.nodes_segmentix_test[label].inputs['segmentation_in'] = self.network.transformix_seg_nodes_test[label].outputs['image'] - else: - # Use original segmentation - self.network.nodes_segmentix_test[label].inputs['segmentation_in'] = self.network.converters_seg_test[label].outputs['image'] - else: - # Use original segmentation - self.network.nodes_segmentix_test[label].inputs['segmentation_in'] = self.network.converters_seg_test[label].outputs['image'] - - self.network.nodes_segmentix_test[label].inputs['parameters'] = self.network.sources_parameters[label].output - self.network.calcfeatures_test[label].inputs['segmentation'] = self.network.nodes_segmentix_test[label].outputs['segmentation_out'] - self.network.sinks_segmentations_segmentix_test[label].input = self.network.nodes_segmentix_test[label].outputs['segmentation_out'] - - if self.masks_train: - # Use masks - self.network.nodes_segmentix_train[label].inputs['mask'] = self.network.converters_masks_train[label].outputs['image'] - - if self.masks_test: - # Use masks - self.network.nodes_segmentix_test[label].inputs['mask'] = self.network.converters_masks_test[label].outputs['image'] - - else: - if self.segmode == 'Provided': - self.network.calcfeatures_train[label].inputs['segmentation'] = self.network.converters_seg_train[label].outputs['image'] - elif self.segmode == 'Register': - if nmod > 0: - self.network.calcfeatures_train[label].inputs['segmentation'] = self.network.transformix_seg_nodes_train[label].outputs['image'] - else: - self.network.calcfeatures_train[label].inputs['segmentation'] = self.network.converters_seg_train[label].outputs['image'] - - if self.images_test or self.features_test: - if self.segmode == 'Provided': - self.network.calcfeatures_train[label].inputs['segmentation'] = self.network.converters_seg_train[label].outputs['image'] - elif self.segmode == 'Register': - if nmod > 0: - self.network.calcfeatures_test[label].inputs['segmentation'] = self.network.transformix_seg_nodes_test[label] .outputs['image'] - else: - self.network.calcfeatures_train[label].inputs['segmentation'] = self.network.converters_seg_train[label].outputs['image'] - - # Classification nodes ----------------------------------------------------- - # Add the features from this modality to the classifier node input - self.network.links_C1_train[label] = self.network.classify.inputs['features_train'][str(label)] << self.network.calcfeatures_train[label].outputs['features'] - self.network.links_C1_train[label].collapse = 'train' - - if self.images_test or self.features_test: - # Add the features from this modality to the classifier node input - self.network.links_C1_test[label] = self.network.classify.inputs['features_test'][str(label)] << self.network.calcfeatures_test[label].outputs['features'] - self.network.links_C1_test[label].collapse = 'test' - - # Save output - self.network.sinks_features_train[label].input = self.network.calcfeatures_train[label].outputs['features'] - if self.images_test or self.features_test: - self.network.sinks_features_test[label].input = self.network.calcfeatures_test[label].outputs['features'] - - else: - # Features already provided: hence we can skip numerous nodes - self.network.sources_features_train = dict() - self.network.links_C1_train = dict() - - if self.features_test: - self.network.sources_features_test = dict() - self.network.links_C1_test = dict() - - # Create label for each modality/image - self.modlabels = list() - for num, mod in enumerate(image_types): - num = 0 - label = mod + str(num) - while label in self.network.sources_features_train.keys(): - # if label exists, add number to label - num += 1 - label = mod + str(num) - self.modlabels.append(label) - - # Create a node for the feature computation - self.network.sources_features_train[label] = self.network.create_source('HDF5', id_='features_train_' + label, nodegroup='train') - - # Add the features from this modality to the classifier node input - self.network.links_C1_train[label] = self.network.classify.inputs['features_train'][str(label)] << self.network.sources_features_train[label].output - self.network.links_C1_train[label].collapse = 'train' - - if self.features_test: - self.network.sources_features_test[label] = self.network.create_source('HDF5', id_='features_test_' + label, nodegroup='test') - self.network.links_C1_test[label] = self.network.classify.inputs['features_test'][str(label)] << self.network.sources_features_test[label].output - self.network.links_C1_test[label].collapse = 'test' - - if self.configs[num]['General']['PCE'] == 'True': - # NOTE: PCE feature is currently not open-source. - self.network.PCEnode = self.network.create_node('PCE', memory='64G', id_='PCE') - self.network.PCEnode.inputs['svm'] = self.network.classify.outputs['classification'] - - self.network.sink_PCE = self.network.create_sink('MatlabFile', id_='PCE_mat') - self.network.sink_SI = self.network.create_sink('MatlabFile', id_='SI_mat') - self.network.sink_TS = self.network.create_sink('CSVFile', id_='TS_csv') - - self.network.sink_PCE.input = self.network.PCEnode.outputs['PCE'] - self.network.sink_SI.input = self.network.PCEnode.outputs['SI'] - self.network.sink_TS.input = self.network.PCEnode.outputs['TS'] - - else: - raise WORCexceptions.WORCIOError("Please provide labels.") - else: - raise WORCexceptions.WORCIOError("Please provide either images or features.")
                        - -
                        [docs] def build_testing(self): - ''' todo '''
                        - -
                        [docs] def set(self): - """ Set the FASTR source and sink data based on the given attributes.""" - self.fastrconfigs = list() - self.source_data = dict() - self.sink_data = dict() - - # If the configuration files are confiparse objects, write to file - for num, c in enumerate(self.configs): - if type(c) != configparser.ConfigParser: - # A filepath (not a fastr source) is provided. Hence we read - # the config file and convert it to a configparser object - config = configparser.ConfigParser() - config.read(c) - c = config - cfile = os.path.join(fastr.config.mounts['tmp'], self.name, ("config_{}_{}.ini").format(self.name, num)) - if not os.path.exists(os.path.dirname(cfile)): - os.makedirs(os.path.dirname(cfile)) - with open(cfile, 'w') as configfile: - c.write(configfile) - self.fastrconfigs.append(os.path.join("vfs://tmp", self.name, ("config_{}_{}.ini").format(self.name, num))) - - # Generate gridsearch parameter files if required - # TODO: We now use the first configuration for the classifier, but his needs to be separated from the rest per modality - self.source_data['config_classification'] = self.fastrconfigs[0] - - # Set source and sink data - self.source_data['patientclass_train'] = self.labels_train - self.source_data['patientclass_test'] = self.labels_test - - self.sink_data['classification'] = ("vfs://output/{}/svm_{{sample_id}}_{{cardinality}}{{ext}}").format(self.name) - self.sink_data['performance'] = ("vfs://output/{}/performance_{{sample_id}}_{{cardinality}}{{ext}}").format(self.name) - if self.configs[0]['General']['PCE']: - self.sink_data['PCE_mat'] = ("vfs://output/{}/PCE_{{sample_id}}_{{cardinality}}{{ext}}").format(self.name) - self.sink_data['SI_mat'] = ("vfs://output/{}/SI_{{sample_id}}_{{cardinality}}{{ext}}").format(self.name) - self.sink_data['TS_csv'] = ("vfs://output/{}/TS_{{sample_id}}_{{cardinality}}{{ext}}").format(self.name) - - # NOTE: Below bug should be fixed, need to check - # BUG: this is a bug in the FASTR package. Workaround for nifti XNAT links using expansion of FASTR XNAT plugin. - for num, im in enumerate(self.images_train): - if im is not None and 'xnat' in im: - if 'DICOM' not in im: - fastr.ioplugins['xnat'] - # metalink = im_m1.replace('NIFTI','DICOM') - im = fastr.ioplugins['xnat'].expand_url(im) - imagename = self.configs[num]['FASTR_bugs']['images'] - self.images_train[num] = {v[(v.find('subjects') + 9):v.find('/experiments')]: v + imagename + '?insecure=true' for k, v in im} - - for num, seg in enumerate(self.segmentations_train): - if seg is not None and 'xnat' in seg: - fastr.ioplugins['xnat'] - seg = fastr.ioplugins['xnat'].expand_url(seg) - segname = self.configs[num]['FASTR_bugs']['segmentations'] - self.segmentations_train[num] = {v[(v.find('subjects') + 9):v.find('/experiments')]: v + segname + '?insecure=true' for k, v in seg} - - # Set the source data from the WORC objects you created - for num, label in enumerate(self.modlabels): - self.source_data['parameters_' + label] = self.fastrconfigs[num] - - # Add train data sources - if self.images_train and len(self.images_train) - 1 >= num: - self.source_data['images_train_' + label] = self.images_train[num] - - if self.masks_train and len(self.masks_train) - 1 >= num: - self.source_data['mask_train_' + label] = self.masks_train[num] - - if self.metadata_train and len(self.metadata_train) - 1 >= num: - self.source_data['metadata_train_' + label] = self.metadata_train[num] - - if self.segmentations_train and len(self.segmentations_train) - 1 >= num: - self.source_data['segmentations_train_' + label] = self.segmentations_train[num] - - if self.semantics_train and len(self.semantics_train) - 1 >= num: - self.source_data['semantics_train_' + label] = self.semantics_train[num] - - if self.features_train and len(self.features_train) - 1 >= num: - self.source_data['features_train_' + label] = self.features_train[num] - - if self.Elastix_Para: - # First modality does not need to be registered - if num > 0: - if len(self.Elastix_Para) > 1: - # Each modality has its own registration parameters - self.source_data['Elastix_Para_' + label] = self.Elastix_Para[num] - else: - # Use one fileset for all modalities - self.source_data['Elastix_Para_' + label] = self.Elastix_Para[0] - - # Add test data sources - if self.images_test and len(self.images_test) - 1 >= num: - self.source_data['images_test_' + label] = self.images_test[num] - - if self.masks_test and len(self.masks_test) - 1 >= num: - self.source_data['mask_test_' + label] = self.masks_test[num] - - if self.metadata_test and len(self.metadata_test) - 1 >= num: - self.source_data['metadata_test_' + label] = self.metadata_test[num] - - if self.segmentations_test and len(self.segmentations_test) - 1 >= num: - self.source_data['segmentations_test_' + label] = self.segmentations_test[num] - - if self.semantics_test and len(self.semantics_test) - 1 >= num: - self.source_data['semantics_test_' + label] = self.semantics_test[num] - - if self.features_test and len(self.features_test) - 1 >= num: - self.source_data['features_test_' + label] = self.features_test[num] - - self.sink_data['segmentations_out_segmentix_train_' + label] = ("vfs://output/{}/Segmentations/seg_{}_segmentix_{{sample_id}}_{{cardinality}}{{ext}}").format(self.name, label) - self.sink_data['segmentations_out_elastix_train_' + label] = ("vfs://output/{}/Elastix/seg_{}_elastix_{{sample_id}}_{{cardinality}}{{ext}}").format(self.name, label) - self.sink_data['images_out_elastix_train_' + label] = ("vfs://output/{}/Elastix/im_{}_elastix_{{sample_id}}_{{cardinality}}{{ext}}").format(self.name, label) - self.sink_data['features_train_' + label] = ("vfs://output/{}/Features/features_{}_{{sample_id}}_{{cardinality}}{{ext}}").format(self.name, label) - - if self.labels_test: - self.sink_data['segmentations_out_segmentix_test_' + label] = ("vfs://output/Segmentations/{}/seg_{}_segmentix_{{sample_id}}_{{cardinality}}{{ext}}").format(self.name, label) - self.sink_data['segmentations_out_elastix_test_' + label] = ("vfs://output/{}/Elastix/seg_{}_elastix_{{sample_id}}_{{cardinality}}{{ext}}").format(self.name, label) - self.sink_data['images_out_elastix_test_' + label] = ("vfs://output/{}/Images/im_{}_elastix_{{sample_id}}_{{cardinality}}{{ext}}").format(self.name, label) - self.sink_data['features_test_' + label] = ("vfs://output/{}/Features/features_{}_{{sample_id}}_{{cardinality}}{{ext}}").format(self.name, label) - - # Add elastix sinks if used - if self.segmode: - # Segmode is only non-empty if segmentations are provided - if self.segmode == 'Register': - self.sink_data['transformations_train_' + label] = ("vfs://output/{}/Elastix/transformation_{}_{{sample_id}}_{{cardinality}}{{ext}}").format(self.name, label) - if self.images_test or self.features_test: - self.sink_data['transformations_test_' + label] = ("vfs://output/{}/Elastix/transformation_{}_{{sample_id}}_{{cardinality}}{{ext}}").format(self.name, label)
                        - -
                        [docs] def execute(self): - """ Execute the network through the fastr.network.execute command. """ - # Draw and execute nwtwork - self.network.draw_network(self.network.id, draw_dimension=True) - self.network.execute(self.source_data, self.sink_data, execution_plugin=self.fastr_plugin, tmpdir=self.fastr_tmpdir)
                        - - -
                        [docs]class Tools(object): - ''' - This object can be used to create other pipelines besides the default - Radiomics executions. Currently only includes a registratio pipeline. - ''' -
                        [docs] def __init__(self): - self.Elastix = Elastix() - self.Evaluate = Evaluate()
                        -
                        - -
                        - -
                        -
                        - - -
                        - -
                        -

                        - © Copyright 2016 -- 2019, Biomedical Imaging Group Rotterdam, Departments of Medical Informatics and Radiology, Erasmus MC, Rotterdam, The Netherlands - -

                        -
                        - Built with Sphinx using a theme provided by Read the Docs. - -
                        - -
                        -
                        - -
                        - -
                        - - - - - - - - - - - - \ No newline at end of file diff --git a/build/lib/WORC/doc/_build/html/_modules/WORC/addexceptions.html b/build/lib/WORC/doc/_build/html/_modules/WORC/addexceptions.html deleted file mode 100644 index 1bde6d65..00000000 --- a/build/lib/WORC/doc/_build/html/_modules/WORC/addexceptions.html +++ /dev/null @@ -1,322 +0,0 @@ - - - - - - - - - - - WORC.addexceptions — WORC 3.0.0 documentation - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
                        - - - -
                        - - - - - -
                        - -
                        - - - - - - - - - - - - - - - - - -
                        - - - - -
                        -
                        -
                        -
                        - -

                        Source code for WORC.addexceptions

                        -#!/usr/bin/env python
                        -
                        -# Copyright 2016-2019 Biomedical Imaging Group Rotterdam, Departments of
                        -# Medical Informatics and Radiology, Erasmus MC, Rotterdam, The Netherlands
                        -#
                        -# 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.
                        -
                        -"""
                        -This module contains all WORC-related Exceptions
                        -"""
                        -
                        -# import inspect
                        -# import os
                        -# import textwrap
                        -
                        -# pylint: disable=too-many-ancestors
                        -# Because fo inheriting from FastrError and a common exception causes this
                        -# exception, even though this behaviour is desired
                        -
                        -
                        -
                        [docs]class WORCError(Exception): - """ - This is the base class for all WORC related exceptions. Catching this - class of exceptions should ensure a proper execution of WORC. - """ - # def __init__(self, *args, **kwargs): - # """ - # Constructor for all exceptions. Saves the caller object fullid (if - # found) and the file, function and line number where the object was - # created. - # """ - # super(WORCError, self).__init__(*args, **kwargs) - # - # frame = inspect.stack()[1][0] - # call_object = frame.f_locals.get('self', None) - # if call_object is not None and hasattr(call_object, 'fullid'): - # self.WORC_object = call_object.fullid - # else: - # self.WORC_object = None - # - # info = inspect.getframeinfo(frame) - # self.filename = info.filename - # self.function = info.function - # self.linenumber = info.lineno - # - # def __str__(self): - # """ - # String representation of the error - # - # :return: error string - # :rtype: str - # """ - # if self.WORC_object is not None: - # return '[{}] {}'.format(self.WORC_object, super(WORCError, self).__str__()) - # else: - # return super(WORCError, self).__str__() - # - # def excerpt(self): - # """ - # Return a excerpt of the Error as a tuple. - # """ - # return type(self).__name__, self.message, self.filename, self.linenumber - pass
                        - - -
                        [docs]class WORCNotImplementedError(WORCError, NotImplementedError): - """ - This function/method has not been implemented on purpose (e.g. should be - overwritten in a sub-class) - """ - pass
                        - - -
                        [docs]class WORCIOError(WORCError, IOError): - """ - IOError in WORC - """ - pass
                        - - -
                        [docs]class WORCTypeError(WORCError, TypeError): - """ - TypeError in the WORC system - """ - pass
                        - - -
                        [docs]class WORCValueError(WORCError, ValueError): - """ - ValueError in the WORC system - """ - pass
                        - - -
                        [docs]class WORCKeyError(WORCError, KeyError): - """ - KeyError in the WORC system - """ - pass
                        - - -
                        [docs]class WORCAssertionError(WORCError, AssertionError): - """ - AssertionError in the WORC system - """ - pass
                        - -
                        [docs]class WORCIndexError(WORCError, IndexError): - """ - IndexError in the WORC system - """ - pass
                        -
                        - -
                        - -
                        -
                        - - -
                        - -
                        -

                        - © Copyright 2016 -- 2019, Biomedical Imaging Group Rotterdam, Departments of Medical Informatics and Radiology, Erasmus MC, Rotterdam, The Netherlands - -

                        -
                        - Built with Sphinx using a theme provided by Read the Docs. - -
                        - -
                        -
                        - -
                        - -
                        - - - - - - - - - - - - \ No newline at end of file diff --git a/build/lib/WORC/doc/_build/html/_modules/WORC/classification/AdvancedSampler.html b/build/lib/WORC/doc/_build/html/_modules/WORC/classification/AdvancedSampler.html deleted file mode 100644 index 9d2babaf..00000000 --- a/build/lib/WORC/doc/_build/html/_modules/WORC/classification/AdvancedSampler.html +++ /dev/null @@ -1,395 +0,0 @@ - - - - - - - - - - - WORC.classification.AdvancedSampler — WORC 3.0.0 documentation - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
                        - - - -
                        - - - - - -
                        - -
                        - - - - - - - - - - - - - - - - - -
                        - -
                          - -
                        • Docs »
                        • - -
                        • Module code »
                        • - -
                        • WORC.classification.AdvancedSampler
                        • - - -
                        • - -
                        • - -
                        - - -
                        -
                        -
                        -
                        - -

                        Source code for WORC.classification.AdvancedSampler

                        -#!/usr/bin/env python
                        -
                        -# Copyright 2016-2019 Biomedical Imaging Group Rotterdam, Departments of
                        -# Medical Informatics and Radiology, Erasmus MC, Rotterdam, The Netherlands
                        -#
                        -# 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.
                        -
                        -from sklearn.utils import check_random_state
                        -import numpy as np
                        -from sklearn.externals import six
                        -from ghalton import Halton
                        -# from sobol_seq import i4_sobol_generate as Sobol
                        -import scipy
                        -from scipy.stats import uniform
                        -import math
                        -
                        -
                        -
                        [docs]class log_uniform(): -
                        [docs] def __init__(self, loc=-1, scale=0, base=10): - self.loc = loc - self.scale = scale - self.base = base - self.uniform_dist = uniform(loc=self.loc, scale=self.scale)
                        - -
                        [docs] def rvs(self, size=None, random_state=None): - if size is None: - return np.power(self.base, self.uniform_dist.rvs(random_state=random_state)) - else: - return np.power(self.base, self.uniform_dist.rvs(size=size, random_state=random_state))
                        - - -
                        [docs]class discrete_uniform(): -
                        [docs] def __init__(self, loc=-1, scale=0): - self.loc = loc - self.scale = scale - self.uniform_dist = uniform(loc=self.loc, scale=self.scale)
                        - -
                        [docs] def rvs(self, size=None, random_state=None): - if size is None: - return int(self.uniform_dist.rvs(random_state=random_state)) - else: - return int(self.uniform_dist.rvs(size=size, random_state=random_state))
                        - - -
                        [docs]class exp_uniform(): -
                        [docs] def __init__(self, loc=-1, scale=0, base=math.e): - self.loc = loc - self.scale = scale - self.base = base
                        - -
                        [docs] def rvs(self, size=None, random_state=None): - uniform_dist = uniform(loc=self.loc, scale=self.scale) - if size is None: - return np.power(self.base, uniform_dist .rvs(random_state=random_state)) - else: - return np.power(self.base, uniform_dist .rvs(size=size, random_state=random_state))
                        - - -
                        [docs]class AdvancedSampler(object): - """Generator on parameters sampled from given distributions using - numerical sequences. Based on the sklearn ParameterSampler. - - Non-deterministic iterable over random candidate combinations for hyper- - parameter search. If all parameters are presented as a list, - sampling without replacement is performed. If at least one parameter - is given as a distribution, sampling with replacement is used. - It is highly recommended to use continuous distributions for continuous - parameters. - - Note that before SciPy 0.16, the ``scipy.stats.distributions`` do not - accept a custom RNG instance and always use the singleton RNG from - ``numpy.random``. Hence setting ``random_state`` will not guarantee a - deterministic iteration whenever ``scipy.stats`` distributions are used to - define the parameter search space. Deterministic behavior is however - guaranteed from SciPy 0.16 onwards. - - Read more in the :ref:`User Guide <search>`. - - Parameters - ---------- - param_distributions : dict - Dictionary where the keys are parameters and values - are distributions from which a parameter is to be sampled. - Distributions either have to provide a ``rvs`` function - to sample from them, or can be given as a list of values, - where a uniform distribution is assumed. - - n_iter : integer - Number of parameter settings that are produced. - - random_state : int or RandomState - Pseudo random number generator state used for random uniform sampling - from lists of possible values instead of scipy.stats distributions. - - Returns - ------- - params : dict of string to any - **Yields** dictionaries mapping each estimator parameter to - as sampled value. - - Examples - -------- - >>> from WORC.classification.AdvancedSampler import HaltonSampler - >>> from scipy.stats.distributions import expon - >>> import numpy as np - >>> np.random.seed(0) - >>> param_grid = {'a':[1, 2], 'b': expon()} - >>> param_list = list(HaltonSampler(param_grid, n_iter=4)) - >>> rounded_list = [dict((k, round(v, 6)) for (k, v) in d.items()) - ... for d in param_list] - >>> rounded_list == [{'b': 0.89856, 'a': 1}, - ... {'b': 0.923223, 'a': 1}, - ... {'b': 1.878964, 'a': 2}, - ... {'b': 1.038159, 'a': 2}] - True - """ -
                        [docs] def __init__(self, param_distributions, n_iter, random_state=None, - method='Halton'): - self.param_distributions = param_distributions - self.n_iter = n_iter - self.random_state = random_state - self.method = method - - if method == 'Halton': - self.Halton = Halton(len(self.param_distributions.keys()))
                        - -
                        [docs] def __iter__(self): - # Create a random state to be used - rnd = check_random_state(self.random_state) - - # Generate the sequence generator - if self.method == 'Halton': - sequence = self.Halton.get(self.n_iter) - elif self.method == 'Sobol': - sequence = Sobol(len(self.param_distributions.keys()), self.n_iter) - - # Always sort the keys of a dictionary, for reproducibility - items = sorted(self.param_distributions.items()) - for i in six.moves.range(self.n_iter): - sample = sequence[i] - params = dict() - for ind, (k, v) in enumerate(items): - point = sample[ind] - # Check if the parameter space is a distribution or a list - if hasattr(v, "rvs"): - print(point) - # Parameter space is a distribution, hence sample - params[k] = v.ppf(point) - else: - # Parameter space is a list, so select an index - point = int(round(point*float(len(v) - 1))) - print(point) - params[k] = v[point] - yield params - - # For reproducibility, reset sampler if needed - if self.method == 'Halton': - self.Halton.reset()
                        - -
                        [docs] def __len__(self): - """Number of points that will be sampled.""" - return self.n_iter
                        - - -if __name__ == '__main__': - random_seed = np.random.randint(1, 5000) - random_state = check_random_state(random_seed) - - param_distributions = {'kernel': ['poly', 'RGB'], - 'C': scipy.stats.uniform(loc=0, scale=1E6), - 'degree': scipy.stats.uniform(loc=1, scale=6), - 'coef0': scipy.stats.uniform(loc=0, scale=1), - 'gamma': scipy.stats.uniform(loc=1E-5, scale=1), - 'histogram_features': ['True', 'False']} - - n_iter = 6 - - method = 'Sobol' - sampled_params = AdvancedSampler(param_distributions, - n_iter, - random_state) - - - for s in sampled_params: - print(s) -
                        - -
                        - -
                        -
                        - - -
                        - -
                        -

                        - © Copyright 2016 -- 2019, Biomedical Imaging Group Rotterdam, Departments of Medical Informatics and Radiology, Erasmus MC, Rotterdam, The Netherlands - -

                        -
                        - Built with Sphinx using a theme provided by Read the Docs. - -
                        - -
                        -
                        - -
                        - -
                        - - - - - - - - - - - - \ No newline at end of file diff --git a/build/lib/WORC/doc/_build/html/_modules/WORC/classification/RankedSVM.html b/build/lib/WORC/doc/_build/html/_modules/WORC/classification/RankedSVM.html deleted file mode 100644 index 23d1f36b..00000000 --- a/build/lib/WORC/doc/_build/html/_modules/WORC/classification/RankedSVM.html +++ /dev/null @@ -1,953 +0,0 @@ - - - - - - - - - - - WORC.classification.RankedSVM — WORC 3.0.0 documentation - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
                        - - - -
                        - - - - - -
                        - -
                        - - - - - - - - - - - - - - - - - -
                        - -
                          - -
                        • Docs »
                        • - -
                        • Module code »
                        • - -
                        • WORC.classification.RankedSVM
                        • - - -
                        • - -
                        • - -
                        - - -
                        -
                        -
                        -
                        - -

                        Source code for WORC.classification.RankedSVM

                        -#!/usr/bin/env python
                        -
                        -# Copyright 2016-2019 Biomedical Imaging Group Rotterdam, Departments of
                        -# Medical Informatics and Radiology, Erasmus MC, Rotterdam, The Netherlands
                        -#
                        -# 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.
                        -
                        -
                        -from __future__ import division
                        -import numpy as np
                        -from scipy.optimize import linprog
                        -from scipy.optimize import fminbound
                        -from scipy import linalg
                        -import operator
                        -import WORC.addexceptions as WORCexceptions
                        -
                        -
                        -'''
                        -This code is based on the original RankSVM Matlab Code from [1] and [2].
                        -Only the multi-classification variant has been ported.
                        -
                        -
                        -RanKSVM_train trains a multi-label ranking svm using the method described in
                        -[1] and [2] and originally implemented in MATLAB.
                        -
                        -[1] Elisseeff A, Weston J. Kernel methods for multi-labelled classfication
                        -      and categorical regression problems. Technical Report,
                        -      BIOwulf Technologies, 2001.
                        -[2] Elisseeff A,Weston J. A kernel method for multi-labelled classification.
                        -      In: Dietterich T G, Becker S, Ghahramani Z, eds. Advances in
                        -      Neural Information Processing Systems 14, Cambridge,
                        -      MA: MIT Press, 2002, 681-687.
                        -
                        -Translated by Mumtaz Hussain Soomro (mumtazhussain.soomro@uniroma3.tk) in August 2018
                        -'''
                        -
                        -
                        -
                        [docs]def neg_dual_func(Lambda, Alpha_old, Alpha_new, c_value, kernel, - num_training, num_class, Label, not_Label, - Label_size, size_alpha): - - # Local Variables: kernel, num_class, Alpha_new, index, i, num_training, k, size_alpha, m, c_value, Label, Alpha, Beta, n, not_Label, output, Lambda, Label_size, Alpha_old - # Function calls: sum, zeros, neg_dual_func - - Alpha = Alpha_old+np.dot(Lambda, Alpha_new-Alpha_old) - Beta = np.zeros(shape =(num_class, num_training)) - for k in range(num_class): - for i in range(num_training): - for m in range(Label_size[:,int(i)]): - for n in range(num_class-Label_size[:,int(i)]): - index = np.sum(size_alpha[:,0:i])+n - - ak = np.array(c_value[k], dtype=int) - r1 = Label[int(i)] ####this supports for only for multiclass - ### if you want to work on multilabel then try this: r1 = Label[i] - #################################################### r1 = r1[m] - c1 = not_Label[int(i)] - c1 = c1[n] - Beta[k,i] = Beta[k,i]+ak[int(r1),int(c1)]*Alpha[:,int(index)] - - - output = 0 - for k in range(num_class): - fg = np.dot(Beta[int(k),:], kernel.conj().T) - fg = fg.conj().T - gf = np.dot(Beta[int(k),:], fg) - output = output + gf - - output = np.dot(0.5, output) - output = output-np.sum(Alpha) - return np.array([output])
                        - - -
                        [docs]def is_empty(any_structure): - if any_structure: - return False - - else: - return True
                        - - -
                        [docs]def RankSVM_train_old(train_data, train_target, cost=1, lambda_tol=1e-6, - norm_tol=1e-4, max_iter=500, svm='Poly', gamma=0.05, - coefficient=0.05, degree=3): - # NOTE: Only multilabel classification, not multiclass! Make a check. - ''' - Weights,Bias,SVs = RankSVM_train(train_data,train_target,cost,lambda_tol,norm_tol,max_iter,svm,gamma,coefficient,degree) - - Description - - RankSVM_train takes, - train_data - An MxN array, the ith instance of training instance is stored in train_data[i,:] - train_target - A QxM array, if the ith training instance belongs to the jth class, then train_target[j,i] equals +1, otherwise train_target(j,i) equals -1 - svm - svm gives the type of svm used in training, which can take the value of 'RBF', 'Poly' or 'Linear'; svm.para gives the corresponding parameters used for the svm: - 1) if svm is 'RBF', then gamma gives the value of gamma, where the kernel is exp(-Gamma*|x[i]-x[j]|^2) - 2) if svm is 'Poly', then three values are used gamma, coefficient, and degree respectively, where the kernel is (gamma*<x[i],x[j]>+coefficient)^degree. - 3) if svm is 'Linear', then svm is []. - cost - The value of 'C' used in the SVM, default=1 - lambda_tol - The tolerance value for lambda described in the appendix of [1]; default value is 1e-6 - norm_tol - The tolerance value for difference between alpha(p+1) and alpha(p) described in the appendix of [1]; default value is 1e-4 - max_iter - The maximum number of iterations for RankSVM, default=500 - - and returns, - Weights - The value for beta[ki] as described in the appendix of [1] is stored in Weights[k,i] - Bias - The value for b[i] as described in the appendix of [1] is stored in Bias[1,i] - SVs - The ith support vector is stored in SVs[:,i] - - - For more details,please refer to [1] and [2]. - ''' - - # RankedSVM only works for multilabel problems, not multiclass, so check - # Whether patients have no class or multiple classes - n_class = train_target.shape[0] - n_object = train_target.shape[1] - for i in range(0, n_object): - if np.sum(train_target[:, i]) != -n_class + 2: - raise WORCexceptions.WORCIOError('RankedSVM only works ' + - 'for multilabel problems,' + - ' not multiclass. One or ' + - 'more objects belong ' + - 'either to no class or' + - ' multiple classes. ' + - 'Please check your data' + - ' again.') - - num_training, tempvalue = np.shape(train_data) - - SVs = np.zeros(shape=(tempvalue,num_training)) - - num_class, tempvalue = np.shape(train_target) - lc = np.ones(shape=(1,num_class)) - - target = np.zeros(shape=(num_class, tempvalue)) - for i in range(num_training): - temp = train_target[:,int(i)] - if np.logical_and(np.sum(temp) != num_class, np.sum(temp) != -num_class): - #SVs = (SVs, train_data[int(i),:].conj().T) - SVs [:,i] = train_data[int(i),:].conj().T - target[:,i] = temp - - - Dim, num_training = np.shape(SVs) - Label = np.array(np.zeros(shape=(num_training,1)), dtype=float) - not_Label = [] - Label_size = np.zeros(shape=(1,num_training)) - size_alpha = np.zeros(shape=(1,num_training), dtype=float) - - for i in range(num_training): - temp1 = train_target[:,int(i)] - Label_size[0,int(i)] = np.sum(temp1 == lc) - lds = num_class-Label_size[0,int(i)] - size_alpha[0,int(i)] = np.dot(lds, Label_size[0,int(i)]) - for j in range(num_class): - if temp1[int(j)] == 1: - Label[int(i),0] = np.array([j]) - else: - not_Label.append((j)) - - not_Label = np.reshape(not_Label, (num_training,num_class-1)) - - kernel = np.zeros(shape =(num_training, num_training), dtype=float) - - if svm == 'RBF': - for i in range(num_training): - for j in range(num_training): - kernel[int(i),int(j)] = np.exp(-gamma*(np.sum((SVs[:,i]-SVs[:,j])**2))) - - - else: - if svm == 'Poly': - for i in range(num_training): - for j in range(num_training): - ab= np.dot((np.array([SVs[:,int(j)]])),((np.array([SVs[:,int(i)]])).conj().T)) - ab=gamma*ab - ab=ab+coefficient - ab=ab**degree - #kernel[int(i),int(j)] = (gamma*(SVs[:,int(i)].conj().T)*SVs[:,int(j)]+coefficient)**degree - kernel[int(i),int(j)] = np.array([ab]) - else: - for i in range(num_training): - for j in range(num_training): - kernel[int(i),int(j)] = np.dot((np.array([SVs[:,int(j)]])),((np.array([SVs[:,int(i)]])).conj().T)) - - svm_used=svm; - - #Begin training phase - - #data initializing - - ak = np.sum(size_alpha, dtype=int) - Alpha = np.zeros(shape=(1, ak)) - - ####creating a cell c_value - - c_value = np.zeros((num_class,), dtype=np.object) - - for i in range(num_class): - c_value[i] = np.zeros(shape=(num_class,num_class)) - - for i in range(num_class): - ak = c_value[i] - ak[i,:]= np.ones(shape=(1,num_class)) - ak[:,i]= -np.ones(shape=(num_class,)) - c_value[i] = ak - - #print Label_size - ### Find the Alpha value using Franke and Wolfe method [1] - - continuing = True - iteration = 0 - - while(continuing): - - #computing Beta - #iteration=iteration+1; - - #disp(strcat('current iteration: ',num2str(iteration))) - Beta = np.zeros(shape=(num_class,num_training)) - for k in range(num_class): - for i in range(num_training): - for m in range(Label_size[:,int(i)]): - for n in range(num_class-Label_size[:,int(i)]): - #index = np.sum(size_alpha[:,0:i])+(m-1)*(num_class-Label_size[i])+n - index = np.sum(size_alpha[:,0:i])+n - - ak = np.array(c_value[k], dtype=int) - r1 = Label[int(i)] ####this supports for only for multiclass - ### if you want to work on multilabel then try this: r1 = Label[i] - #################################################### r1 = r1[m] - c1 = not_Label[int(i)] - c1 = c1[n] - Beta[k,i] = Beta[k,i]+ak[int(r1),int(c1)]*Alpha[:,int(index)] - - ####computing gradient(ikl) - - inner = np.zeros(shape=(num_class,num_training)) - for k in range(num_class): - for j in range(num_training): - inner[k,j] = np.dot(Beta[k,:], kernel[:,j]) - - gradient=[] - - for i in range(num_training): - for m in range(Label_size[:,int(i)]): - for n in range(num_class-Label_size[:,int(i)]): - r1 = Label[int(i)] ####this supports only for multiclass - ### if you want to work on multilabel then try this: r1 = Label[i] - #################################################### r1 = r1[m] - c1 = not_Label[int(i)] - c1 = c1[n] - temp = inner[int(r1), int(i)]-inner[int(c1),int(i)]-1 - #gradient=np.array([gradient,temp]) - gradient.append(float(temp)) - - gradient = np.array(gradient, dtype=float) - gradient = gradient.conj().T - - - ###Find Alpha_new - Aeq = np.zeros(shape=(num_class,np.sum(size_alpha, dtype=int))) - for k in range(num_class): - counter=0 - for i in range(num_training): - for m in range (Label_size[:,int(i)]): - for n in range(num_class-Label_size[:,int(i)]): - #counter+=1 - r1 = Label[i] ####this supports only for multiclass - ### if you want to work on multilabel then try this: r1 = Label[i] - #################################################### r1 = r1[m] - c1 = not_Label[int(i)] - c1 = c1[n] - ak = c_value[k] - Aeq[k,counter] = ak[int(r1),int(c1)] - counter+=1 - #print Aeq - beq=np.zeros(shape=(num_class,)) - LB=np.zeros(shape=(np.sum(size_alpha, dtype=int),1)) - UB=np.zeros(shape=(np.sum(size_alpha, dtype=int),1)) - counter=0 - for i in range(num_training): - for m in range(Label_size[:,int(i)]): - for n in range(num_class-Label_size[:,int(i)]): - #counter+=1 - UB[counter,:]=cost/(size_alpha[:,i]) - counter+=1 - #print UB - cc = [LB.T, UB.T] - cc =np.ravel(cc) - bounds = np.reshape(cc, (2,np.sum(size_alpha, dtype=int))) - bounds = bounds.T - Alpha_new=linprog(gradient.conj().T,A_ub=None, b_ub=None, A_eq=Aeq, b_eq=beq.T,bounds=bounds) - Alpha_new = Alpha_new.x - Alpha_new = (np.array(Alpha_new)).conj().T - - Lambda =fminbound(neg_dual_func, 0.0, 1.0,args= (Alpha,Alpha_new,c_value,kernel,num_training,num_class,Label,not_Label,Label_size,size_alpha)) - - - #print Lambda - #Test convergence - - if np.logical_or(np.abs(Lambda)<=lambda_tol, np.dot(Lambda, np.sqrt(np.sum(((Alpha_new-Alpha)**2.))))<=norm_tol): - continuing = False - # np.disp('program terminated normally') - else: - if iteration >= max_iter: - continuing = False - - else: - Alpha = Alpha+np.dot(Lambda, Alpha_new-Alpha) - - iteration+=1 - - - Weights = Beta - - #Computing Bias - - Left = [] - Right = [] - for i in range(num_training): - for m in range(Label_size[:,int(i)]): - for n in range(num_class-Label_size[:,int(i)]): - index = np.sum(size_alpha[:,0:i])+n - if np.logical_and(np.abs(Alpha[:,int(index)]) >= lambda_tol, np.abs(Alpha[:,int(index)]-cost/(size_alpha[:,i])) >= lambda_tol): - vector = np.zeros(shape=(1, num_class)) - vector[0,int(Label[i])] = 1 - c1 = not_Label[int(i)] - c1 = c1[n] - vector[0,int(c1)] = -1. - Left.append(vector) - Right.append(-gradient[int(index)]) - - - if is_empty(Left): - Bias = np.sum(train_target.conj().T) - else: - bb = np.array([Right]) - ss1,ss2 = bb.shape - aa = np.ravel(Left) - aa = np.reshape(aa,(ss2,num_class)) - - ##### Proper way to solve linear equation with non-square matrix - Bias = np.linalg.lstsq(aa,bb.T,rcond = -1)[0] - #Bias = Bias.T - - return Weights, Bias, SVs
                        - - -
                        [docs]def RankSVM_train(train_data, train_target, cost=1, lambda_tol=1e-6, - norm_tol=1e-4, max_iter=500, svm='Poly', gamma=0.05, - coefficient=0.05, degree=3): - print('Training Ranked SVM ...') - num_training, tempvalue = np.shape(train_data) - - SVs = np.zeros(shape=(tempvalue,num_training)) - num_class, tempvalue = np.shape(train_target) - lc = np.ones(shape=(1,num_class)) - #print SVs.shape - target = np.zeros(shape=(num_class, tempvalue)) - for i in range(num_training): - temp = train_target[:,int(i)] - if np.logical_and(np.sum(temp) != num_class, np.sum(temp) != -num_class): - #SVs = (SVs, train_data[int(i),:].conj().T) - #print (train_data[int(i),:]).conj().T - SVs [:,i] = train_data[int(i),:].conj().T - #SVs [i,:] = train_data[int(i),:].T - - target[:,i] = temp - - #SVs = SVs.T - Dim, num_training = np.shape(SVs) - Label = np.array(np.zeros(shape=(num_training,1)), dtype=float) - not_Label = [] - Label_size = np.zeros(shape=(1,num_training)) - size_alpha = np.zeros(shape=(1,num_training), dtype=float) - - for i in range(num_training): - temp1 = train_target[:,int(i)] - Label_size[0,int(i)] = np.sum(temp1 == lc) - lds = num_class-Label_size[0,int(i)] - size_alpha[0,int(i)] = np.dot(lds, Label_size[0,int(i)]) - for j in range(num_class): - if temp1[int(j)] == 1: - Label[int(i),0] = np.array([j]) - else: - not_Label.append((j)) - not_Label = np.reshape(not_Label, (num_training,num_class-1)) - - kernel = np.zeros(shape =(num_training, num_training), dtype=float) - - if svm == 'RBF': - for i in range(num_training): - for j in range(num_training): - kernel[int(i),int(j)] = np.exp(-gamma*(np.sum((SVs[:,i]-SVs[:,j])**2))) - - - else: - if svm == 'Poly': - for i in range(num_training): - for j in range(num_training): - ab= np.dot((np.array([SVs[:,int(j)]])),((np.array([SVs[:,int(i)]])).conj().T)) - ab=gamma*ab - ab=ab+coefficient - ab=ab**degree - #kernel[int(i),int(j)] = (gamma*(SVs[:,int(i)].conj().T)*SVs[:,int(j)]+coefficient)**degree - kernel[int(i),int(j)] = np.array([ab]) - else: - for i in range(num_training): - for j in range(num_training): - kernel[int(i),int(j)] = np.dot((np.array([SVs[:,int(j)]])),((np.array([SVs[:,int(i)]])).conj().T)) - - svm_used=svm; - - #Begin training phase - - #data initializing - - ak = np.sum(size_alpha, dtype=int) - Alpha = np.zeros(shape=(1, ak)) - - ####creating a cell c_value - - c_value = np.zeros((num_class,), dtype=np.object) - - for i in range(num_class): - c_value[i] = np.zeros(shape=(num_class,num_class)) - - for i in range(num_class): - ak = c_value[i] - ak[i,:]= np.ones(shape=(1,num_class)) - ak[:,i]= -np.ones(shape=(num_class,)) - c_value[i] = ak - - #print Label_size - ### Find the Alpha value using Franke and Wolfe method [1] - - continuing = True - iteration = 0 - - while(continuing): - print('Iteration {}.').format(iteration) - #computing Beta - #iteration=iteration+1; - - #disp(strcat('current iteration: ',num2str(iteration))) - Beta = np.zeros(shape=(num_class,num_training)) - for k in range(num_class): - for i in range(num_training): - for m in range(Label_size[:,int(i)]): - for n in range(num_class-Label_size[:,int(i)]): - #index = np.sum(size_alpha[:,0:i])+(m-1)*(num_class-Label_size[i])+n - index = np.sum(size_alpha[:,0:i])+n - - ak = np.array(c_value[k], dtype=int) - r1 = Label[int(i)] ####this supports for only for multiclass - ### if you want to work on multilabel then try this: r1 = Label[i] - #################################################### r1 = r1[m] - c1 = not_Label[int(i)] - c1 = c1[n] - Beta[k,i] = Beta[k,i]+ak[int(r1),int(c1)]*Alpha[:,int(index)] - - ####computing gradient(ikl) - - inner = np.zeros(shape=(num_class,num_training)) - for k in range(num_class): - for j in range(num_training): - inner[k,j] = np.dot(Beta[k,:], kernel[:,j]) - - gradient=[] - - for i in range(num_training): - for m in range(Label_size[:,int(i)]): - for n in range(num_class-Label_size[:,int(i)]): - r1 = Label[int(i)] ####this supports only for multiclass - ### if you want to work on multilabel then try this: r1 = Label[i] - #################################################### r1 = r1[m] - c1 = not_Label[int(i)] - c1 = c1[n] - temp = inner[int(r1), int(i)]-inner[int(c1),int(i)]-1 - #gradient=np.array([gradient,temp]) - gradient.append(float(temp)) - - gradient = np.array(gradient, dtype=float) - gradient = gradient.conj().T - - - ###Find Alpha_new - - Aeq = np.zeros(shape=(num_class,np.sum(size_alpha, dtype=int))) - for k in range(num_class): - counter=0 - for i in range(num_training): - for m in range (Label_size[:,int(i)]): - for n in range(num_class-Label_size[:,int(i)]): - #counter+=1 - r1 = Label[i] ####this supports only for multiclass - ### if you want to work on multilabel then try this: r1 = Label[i] - #################################################### r1 = r1[m] - c1 = not_Label[int(i)] - c1 = c1[n] - ak = c_value[k] - Aeq[k,counter] = ak[int(r1),int(c1)] - counter+=1 - #print Aeq - beq=np.zeros(shape=(num_class,)) - LB=np.zeros(shape=(np.sum(size_alpha, dtype=int),1)) - UB=np.zeros(shape=(np.sum(size_alpha, dtype=int),1)) - counter=0 - for i in range(num_training): - for m in range(Label_size[:,int(i)]): - for n in range(num_class-Label_size[:,int(i)]): - #counter+=1 - UB[counter,:]=cost/(size_alpha[:,i]) - counter+=1 - #print UB - cc = [LB.T, UB.T] - cc =np.ravel(cc) - bounds = np.reshape(cc, (2,np.sum(size_alpha, dtype=int))) - bounds = bounds.T - try: - Alpha_new = linprog(gradient.conj().T,A_ub=None, b_ub=None, A_eq=Aeq, b_eq=beq.T,bounds=bounds) - Alpha_new = Alpha_new.x - Alpha_new = (np.array(Alpha_new)).conj().T - except IndexError: - print('[WORC Warning] RankedSVM could not be fit to data. Returning zero classifier.') - Alpha_new = Alpha - - Lambda =fminbound(neg_dual_func, 0.0, 1.0,args= (Alpha,Alpha_new,c_value,kernel,num_training,num_class,Label,not_Label,Label_size,size_alpha)) - - - #print Lambda - #Test convergence - - if np.logical_or(np.abs(Lambda)<=lambda_tol, np.dot(Lambda, np.sqrt(np.sum(((Alpha_new-Alpha)**2.))))<=norm_tol): - continuing = False - # np.disp('program terminated normally') - else: - if iteration >= max_iter: - continuing = False - - else: - Alpha = Alpha+np.dot(Lambda, Alpha_new-Alpha) - - iteration+=1 - - Weights = Beta - - #Computing Bias - Left = [] - Right = [] - for i in range(num_training): - for m in range(Label_size[:,int(i)]): - for n in range(num_class-Label_size[:,int(i)]): - index = np.sum(size_alpha[:,0:i])+n - if np.logical_and(np.abs(Alpha[:,int(index)]) >= lambda_tol, np.abs(Alpha[:,int(index)]-cost/(size_alpha[:,i])) >= lambda_tol): - vector = np.zeros(shape=(1, num_class)) - vector[0,int(Label[i])] = 1 - c1 = not_Label[int(i)] - c1 = c1[n] - vector[0,int(c1)] = -1. - Left.append(vector) - Right.append(-gradient[int(index)]) - - if is_empty(Left): - Bias = np.sum(train_target.conj().T) - else: - bb = np.array([Right]) - ss1,ss2 = bb.shape - aa = np.ravel(Left) - aa = np.reshape(aa,(ss2,num_class)) - - ##### Proper way to solve linear equation with non-square matrix - Bias = np.linalg.lstsq(aa,bb.T,rcond = -1)[0] - #Bias = Bias.T - - if Bias.shape == (): - # Error in Alpha, create empty bias - print('[WORC Warning] Error in Alpha, create empty bias.') - Bias = np.zeros(shape=(num_class,1)) - - return Weights,Bias,SVs
                        - -
                        [docs]def RankSVM_test_original(test_data, test_target, Weights, Bias, SVs, - svm='Poly', gamma=0.05, - coefficient=0.05, degree=3): - num_testing, tempvalue = np.shape(test_data) - num_class, tempvalue = np.shape(test_target) - tempvalue,num_training= np.shape(SVs) - Label = np.array(np.zeros(shape=(num_testing,1)), dtype=float) - not_Label = [] - Label_size = np.zeros(shape=(1,num_testing)) - size_alpha = np.zeros(shape=(1,num_training), dtype=float) - lc = np.ones(shape=(1,num_class)) - for i in range(num_testing): - temp = test_target[:,int(i)] - Label_size[0,int(i)] = np.sum(temp == lc) - lds = num_class-Label_size[0,int(i)] - size_alpha[0,int(i)] = np.dot(lds, Label_size[0,int(i)]) - for j in range(num_class): - if temp[int(j)] == 1: - Label[int(i),0] = np.array([j]) - else: - not_Label.append((j)) - - not_Label = np.reshape(not_Label, (num_testing,num_class-1)) - - kernel = np.zeros(shape =(num_testing, num_training), dtype=float) - if svm == 'RBF': - for i in range(num_testing): - for j in range(num_training): - kernel[int(i),int(j)] = np.exp(-gamma*(np.sum(((test_data[i,:].conj.T)-SVs[:,j])**2))) - - - else: - if svm == 'Poly': - for i in range(num_testing): - for j in range(num_training): - ab= np.dot((np.array([SVs[:,int(j)]])),(np.array([test_data[int(i),:]]).T)) - ab=gamma*ab - ab=ab+coefficient - ab=ab**degree - #kernel[int(i),int(j)] = (gamma*(SVs[:,int(i)].conj().T)*SVs[:,int(j)]+coefficient)**degree - kernel[int(i),int(j)] = np.array([ab]) - else: - for i in range(num_testing): - for j in range(num_training): - kernel[int(i),int(j)] = np.dot((np.array([SVs[:,int(j)]])),(np.array([test_data[int(i),:]]))) - - Outputs =np.zeros(shape=(num_class,num_testing)) - - for i in range(num_testing): - for k in range(num_class): - temp = 0 - for j in range(num_training): - - temp=temp + np.dot(Weights[k,j],kernel[i,j]) - #temp = np.array([temp], dtype=int) - #temp.append(int(temp)) - temp=temp+Bias[k] - Outputs[k,i]=temp - #hh = Outputs - #mm, nn = np.shape(Outputs) - - for i in range(num_testing): ########### this logic is only for 3 classes and can be modified for further classes - - idx,val = max(enumerate(Outputs[:,i]), key=operator.itemgetter(1)) - - if idx == 0: - Outputs[idx+1,i]=0 - Outputs[idx+2,i]=0 - if idx == 1: - Outputs[idx+1,i]=0 - Outputs[idx-1,i]=0 - if idx == 2: - Outputs[idx-1,i]=0 - Outputs[idx-2,i]=0 - - Pre_Labels = np.zeros(shape = (num_class,num_testing)) - for i in range(num_testing): - for k in range(num_class): - - if (abs(Outputs[k,i]) > 0): - Pre_Labels[k,i]=1 - else: - Pre_Labels[k,i]=-1 - - return Outputs, Pre_Labels
                        - - -
                        [docs]def RankSVM_test(test_data, num_class, Weights, Bias, SVs, - svm='Poly', gamma=0.05, - coefficient=0.05, degree=3): - num_testing, tempvalue = np.shape(test_data) - # num_class, tempvalue = np.shape(test_target) - tempvalue, num_training = np.shape(SVs) - # Label = np.array(np.zeros(shape=(num_testing,1)), dtype=float) - # not_Label = [] - # Label_size = np.zeros(shape=(1,num_testing)) - # size_alpha = np.zeros(shape=(1,num_training), dtype=float) - # lc = np.ones(shape=(1,num_class)) - # for i in range(num_testing): - # temp = test_target[:,int(i)] - # Label_size[0,int(i)] = np.sum(temp == lc) - # lds = num_class-Label_size[0,int(i)] - # size_alpha[0,int(i)] = np.dot(lds, Label_size[0,int(i)]) - # for j in range(num_class): - # if temp[int(j)] == 1: - # Label[int(i),0] = np.array([j]) - # else: - # not_Label.append((j)) - # - # not_Label = np.reshape(not_Label, (num_testing,num_class-1)) - - kernel = np.zeros(shape =(num_testing, num_training), dtype=float) - if svm == 'RBF': - for i in range(num_testing): - for j in range(num_training): - kernel[int(i),int(j)] = np.exp(-gamma*(np.sum(((test_data[i,:].conj.T)-SVs[:,j])**2))) - - - else: - if svm == 'Poly': - for i in range(num_testing): - for j in range(num_training): - ab= np.dot((np.array([SVs[:,int(j)]])),(np.array([test_data[int(i),:]]).T)) - ab=gamma*ab - ab=ab+coefficient - ab=ab**degree - #kernel[int(i),int(j)] = (gamma*(SVs[:,int(i)].conj().T)*SVs[:,int(j)]+coefficient)**degree - kernel[int(i),int(j)] = np.array([ab]) - else: - for i in range(num_testing): - for j in range(num_training): - kernel[int(i),int(j)] = np.dot((np.array([SVs[:,int(j)]])),(np.array([test_data[int(i),:]]))) - - Probabilities = np.zeros(shape=(num_class,num_testing)) - - for i in range(num_testing): - for k in range(num_class): - temp = 0 - for j in range(num_training): - - temp=temp + np.dot(Weights[k,j],kernel[i,j]) - #temp = np.array([temp], dtype=int) - #temp.append(int(temp)) - temp=temp+Bias[k] - Probabilities[k,i]=temp - #hh = Outputs - #mm, nn = np.shape(Outputs) - - # Class with maximum probability is predicted as label - Predicted_Labels = np.zeros(Probabilities.shape) - # Probabilities = np.asarray([np.argmax(Probabilities[:, i]) for i in range(num_testing)]) - for i in range(num_testing): - idx = np.argmax(Probabilities[:, i]) - Predicted_Labels[idx, i] = 1 - - # Transpose in order to be compatible with sklearn - Probabilities = np.transpose(Probabilities) - Predicted_Labels = np.transpose(Predicted_Labels) - - return Probabilities, Predicted_Labels
                        -
                        - -
                        - -
                        -
                        - - -
                        - -
                        -

                        - © Copyright 2016 -- 2019, Biomedical Imaging Group Rotterdam, Departments of Medical Informatics and Radiology, Erasmus MC, Rotterdam, The Netherlands - -

                        -
                        - Built with Sphinx using a theme provided by Read the Docs. - -
                        - -
                        -
                        - -
                        - -
                        - - - - - - - - - - - - \ No newline at end of file diff --git a/build/lib/WORC/doc/_build/html/_modules/WORC/classification/SearchCV.html b/build/lib/WORC/doc/_build/html/_modules/WORC/classification/SearchCV.html deleted file mode 100644 index fc183c9d..00000000 --- a/build/lib/WORC/doc/_build/html/_modules/WORC/classification/SearchCV.html +++ /dev/null @@ -1,2669 +0,0 @@ - - - - - - - - - - - WORC.classification.SearchCV — WORC 3.0.0 documentation - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
                        - - - -
                        - - - - - -
                        - -
                        - - - - - - - - - - - - - - - - - -
                        - -
                          - -
                        • Docs »
                        • - -
                        • Module code »
                        • - -
                        • WORC.classification.SearchCV
                        • - - -
                        • - -
                        • - -
                        - - -
                        -
                        -
                        -
                        - -

                        Source code for WORC.classification.SearchCV

                        -#!/usr/bin/env python
                        -
                        -# Copyright 2016-2019 Biomedical Imaging Group Rotterdam, Departments of
                        -# Medical Informatics and Radiology, Erasmus MC, Rotterdam, The Netherlands
                        -#
                        -# 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.
                        -
                        -
                        -from sklearn.base import BaseEstimator, is_classifier, clone
                        -from sklearn.base import MetaEstimatorMixin
                        -from sklearn.exceptions import NotFittedError
                        -from sklearn.utils.metaestimators import if_delegate_has_method
                        -from sklearn.utils.validation import indexable, check_is_fitted
                        -from WORC.classification.metrics import check_scoring
                        -from sklearn.model_selection._split import check_cv
                        -from scipy.stats import rankdata
                        -from sklearn.externals import six
                        -from sklearn.utils.fixes import MaskedArray
                        -
                        -from sklearn.model_selection._search import _CVScoreTuple, ParameterSampler
                        -from sklearn.model_selection._search import ParameterGrid, _check_param_grid
                        -
                        -from abc import ABCMeta, abstractmethod
                        -from collections import Sized, defaultdict
                        -import numpy as np
                        -from functools import partial
                        -import warnings
                        -
                        -import os
                        -import random
                        -import string
                        -import fastr
                        -from fastr.api import ResourceLimit
                        -from joblib import Parallel, delayed
                        -from WORC.classification.fitandscore import fit_and_score
                        -from WORC.classification.fitandscore import delete_nonestimator_parameters
                        -import WORC.addexceptions as WORCexceptions
                        -import pandas as pd
                        -import json
                        -import glob
                        -from itertools import islice
                        -import shutil
                        -from sklearn.metrics import f1_score, roc_auc_score, mean_squared_error
                        -from sklearn.metrics import accuracy_score
                        -from sklearn.multiclass import OneVsRestClassifier
                        -from WORC.classification.estimators import RankedSVM
                        -from WORC.classification import construct_classifier as cc
                        -
                        -
                        -
                        [docs]def rms_score(truth, prediction): - ''' Root-mean-square-error metric''' - return np.sqrt(mean_squared_error(truth, prediction))
                        - - -
                        [docs]def sar_score(truth, prediction): - ''' SAR metric from Caruana et al. 2004''' - - ROC = roc_auc_score(truth, prediction) - # Convert score to binaries first - for num in range(0, len(prediction)): - if prediction[num] >= 0.5: - prediction[num] = 1 - else: - prediction[num] = 0 - - ACC = accuracy_score(truth, prediction) - RMS = rms_score(truth, prediction) - SAR = (ACC + ROC + (1 - RMS))/3 - return SAR
                        - - -
                        [docs]def chunksdict(data, SIZE): - '''Split a dictionary in equal parts of certain slice''' - it = iter(data) - for i in xrange(0, len(data), SIZE): - yield {k: data[k] for k in islice(it, SIZE)}
                        - - -
                        [docs]def chunks(l, n): - """Yield successive n-sized chunks from l.""" - for i in range(0, len(l), n): - yield l[i:i + n]
                        - - -
                        [docs]class Ensemble(six.with_metaclass(ABCMeta, BaseEstimator, - MetaEstimatorMixin)): - """Ensemble of BaseSearchCV Estimators.""" - # @abstractmethod -
                        [docs] def __init__(self, estimators): - self.estimators = estimators - self.n_estimators = len(estimators)
                        - -
                        [docs] def predict(self, X): - """Call predict on the estimator with the best found parameters. - - Only available if ``refit=True`` and the underlying estimator supports - ``predict``. - - Parameters - ----------- - X : indexable, length n_samples - Must fulfill the input assumptions of the - underlying estimator. - - """ - self.estimators[0]._check_is_fitted('predict') - - # NOTE: Check if we are dealing with multilabel - if type(self.estimators[0].best_estimator_) == OneVsRestClassifier: - # Multilabel - nlabels = self.estimators[0].predict(X).shape[1] - outcome = np.zeros((self.n_estimators, len(X), nlabels)) - for num, est in enumerate(self.estimators): - if hasattr(est, 'predict_proba'): - # BUG: SVM kernel can be wrong type - if hasattr(est.best_estimator_, 'kernel'): - est.best_estimator_.kernel = str(est.best_estimator_.kernel) - outcome[num, :, :] = est.predict_proba(X)[:, 1] - else: - outcome[num, :, :] = est.predict(X) - - outcome = np.squeeze(np.mean(outcome, axis=0)) - - # NOTE: Binarize specifically for multiclass - for i in range(0, outcome.shape[0]): - label = np.argmax(outcome[i, :]) - outcome[i, :] = np.zeros(outcome.shape[1]) - outcome[i, label] = 1 - - else: - # Singlelabel - outcome = np.zeros((self.n_estimators, len(X))) - for num, est in enumerate(self.estimators): - if hasattr(est, 'predict_proba'): - # BUG: SVM kernel can be wrong type - if hasattr(est.best_estimator_, 'kernel'): - est.best_estimator_.kernel = str(est.best_estimator_.kernel) - outcome[num, :] = est.predict_proba(X)[:, 1] - else: - outcome[num, :] = est.predict(X) - - outcome = np.squeeze(np.mean(outcome, axis=0)) - - # Binarize - isclassifier = is_classifier(est.best_estimator_) - - if isclassifier: - outcome[outcome >= 0.5] = 1 - outcome[outcome < 0.5] = 0 - - return outcome
                        - -
                        [docs] def predict_proba(self, X): - """Call predict_proba on the estimator with the best found parameters. - - Only available if ``refit=True`` and the underlying estimator supports - ``predict_proba``. - - Parameters - ----------- - X : indexable, length n_samples - Must fulfill the input assumptions of the - underlying estimator. - - """ - self.estimators[0]._check_is_fitted('predict_proba') - - # For probabilities, we get both a class0 and a class1 score - outcome = np.zeros((len(X), 2)) - outcome_class1 = np.zeros((self.n_estimators, len(X))) - outcome_class2 = np.zeros((self.n_estimators, len(X))) - for num, est in enumerate(self.estimators): - # BUG: SVM kernel can be wrong type - if hasattr(est.best_estimator_, 'kernel'): - est.best_estimator_.kernel = str(est.best_estimator_.kernel) - outcome_class1[num, :] = est.predict_proba(X)[:, 0] - outcome_class2[num, :] = est.predict_proba(X)[:, 1] - - outcome[:, 0] = np.squeeze(np.mean(outcome_class1, axis=0)) - outcome[:, 1] = np.squeeze(np.mean(outcome_class2, axis=0)) - return outcome
                        - -
                        [docs] def predict_log_proba(self, X): - """Call predict_log_proba on the estimator with the best found parameters. - - Only available if ``refit=True`` and the underlying estimator supports - ``predict_log_proba``. - - Parameters - ----------- - X : indexable, length n_samples - Must fulfill the input assumptions of the - underlying estimator. - - """ - self.estimators[0]._check_is_fitted('predict_log_proba') - - outcome = np.zeros((self.n_estimators, len(X))) - for num, est in enumerate(self.estimators): - outcome[num, :] = est.predict_log_proba(X) - - outcome = np.squeeze(np.mean(outcome, axis=0)) - return outcome
                        - -
                        [docs] def decision_function(self, X): - """Call decision_function on the estimator with the best found parameters. - - Only available if ``refit=True`` and the underlying estimator supports - ``decision_function``. - - Parameters - ----------- - X : indexable, length n_samples - Must fulfill the input assumptions of the - underlying estimator. - - """ - self.estimators[0]._check_is_fitted('decision_function') - - # NOTE: Check if we are dealing with multilabel - if type(self.estimators[0].best_estimator_) == OneVsRestClassifier: - # Multilabel - nlabels = self.estimators[0].decision_function(X).shape[1] - outcome = np.zeros((self.n_estimators, len(X), nlabels)) - for num, est in enumerate(self.estimators): - outcome[num, :, :] = est.decision_function(X) - - outcome = np.squeeze(np.mean(outcome, axis=0)) - - else: - # Singlelabel - outcome = np.zeros((self.n_estimators, len(X))) - for num, est in enumerate(self.estimators): - outcome[num, :] = est.decision_function(X) - - outcome = np.squeeze(np.mean(outcome, axis=0)) - - return outcome
                        - -
                        [docs] def transform(self, X): - """Call transform on the estimator with the best found parameters. - - Only available if the underlying estimator supports ``transform`` and - ``refit=True``. - - Parameters - ----------- - X : indexable, length n_samples - Must fulfill the input assumptions of the - underlying estimator. - - """ - self.estimators[0]._check_is_fitted('transform') - - outcome = np.zeros((self.n_estimators, len(X))) - for num, est in enumerate(self.estimators): - outcome[num, :] = est.transform(X) - - outcome = np.squeeze(np.mean(outcome, axis=0)) - return outcome
                        - -
                        [docs] def inverse_transform(self, Xt): - """Call inverse_transform on the estimator with the best found params. - - Only available if the underlying estimator implements - ``inverse_transform`` and ``refit=True``. - - Parameters - ----------- - Xt : indexable, length n_samples - Must fulfill the input assumptions of the - underlying estimator. - - """ - self.estimators[0]._check_is_fitted('inverse_transform') - - outcome = np.zeros((self.n_estimators, len(Xt))) - for num, est in enumerate(self.estimators): - outcome[num, :] = est.transform(Xt) - - outcome = np.squeeze(np.mean(outcome, axis=0)) - return outcome
                        - - -
                        [docs]class BaseSearchCV(six.with_metaclass(ABCMeta, BaseEstimator, - MetaEstimatorMixin)): - """Base class for hyper parameter search with cross-validation.""" -
                        [docs] @abstractmethod - def __init__(self, param_distributions={}, n_iter=10, scoring=None, - fit_params=None, n_jobs=1, iid=True, - refit=True, cv=None, verbose=0, pre_dispatch='2*n_jobs', - random_state=None, error_score='raise', return_train_score=True, - n_jobspercore=100, maxlen=100, fastr_plugin=None): - - # Added for fastr and joblib executions - self.param_distributions = param_distributions - self.n_iter = n_iter - self.n_jobspercore = n_jobspercore - self.random_state = random_state - self.ensemble = list() - self.fastr_plugin = fastr_plugin - - # Below are the defaults from sklearn - self.scoring = scoring - self.n_jobs = n_jobs - self.fit_params = fit_params if fit_params is not None else {} - self.iid = iid - self.refit = refit - self.cv = cv - self.verbose = verbose - self.pre_dispatch = pre_dispatch - self.error_score = error_score - self.return_train_score = return_train_score - self.maxlen = maxlen
                        - - @property - def _estimator_type(self): - return self.estimator._estimator_type - -
                        [docs] def score(self, X, y=None): - """Returns the score on the given data, if the estimator has been refit. - - This uses the score defined by ``scoring`` where provided, and the - ``best_estimator_.score`` method otherwise. - - Parameters - ---------- - X : array-like, shape = [n_samples, n_features] - Input data, where n_samples is the number of samples and - n_features is the number of features. - - y : array-like, shape = [n_samples] or [n_samples, n_output], optional - Target relative to X for classification or regression; - None for unsupervised learning. - - Returns - ------- - score : float - """ - if self.scorer_ is None: - raise ValueError("No score function explicitly defined, " - "and the estimator doesn't provide one %s" - % self.best_estimator_) - - X, y = self.preprocess(X, y) - - return self.scorer_(self.best_estimator_, X, y)
                        - - def _check_is_fitted(self, method_name): - if not self.refit: - raise NotFittedError(('This GridSearchCV instance was initialized ' - 'with refit=False. %s is ' - 'available only after refitting on the best ' - 'parameters. ') % method_name) - else: - check_is_fitted(self, 'best_estimator_') - -
                        [docs] @if_delegate_has_method(delegate=('best_estimator_', 'estimator')) - def predict(self, X): - """Call predict on the estimator with the best found parameters. - - Only available if ``refit=True`` and the underlying estimator supports - ``predict``. - - Parameters - ----------- - X : indexable, length n_samples - Must fulfill the input assumptions of the - underlying estimator. - - """ - self._check_is_fitted('predict') - - if self.ensemble: - return self.ensemble.predict(X) - else: - X, _ = self.preprocess(X) - return self.best_estimator_.predict(X)
                        - -
                        [docs] @if_delegate_has_method(delegate=('best_estimator_', 'estimator')) - def predict_proba(self, X): - """Call predict_proba on the estimator with the best found parameters. - - Only available if ``refit=True`` and the underlying estimator supports - ``predict_proba``. - - Parameters - ----------- - X : indexable, length n_samples - Must fulfill the input assumptions of the - underlying estimator. - - """ - self._check_is_fitted('predict_proba') - - # BUG: kernel sometimes saved as unicode - # BUG: SVM kernel can be wrong type - if hasattr(self.best_estimator_, 'kernel'): - self.best_estimator_.kernel = str(self.best_estimator_.kernel) - if self.ensemble: - return self.ensemble.predict_proba(X) - else: - X, _ = self.preprocess(X) - return self.best_estimator_.predict_proba(X)
                        - -
                        [docs] @if_delegate_has_method(delegate=('best_estimator_', 'estimator')) - def predict_log_proba(self, X): - """Call predict_log_proba on the estimator with the best found parameters. - - Only available if ``refit=True`` and the underlying estimator supports - ``predict_log_proba``. - - Parameters - ----------- - X : indexable, length n_samples - Must fulfill the input assumptions of the - underlying estimator. - - """ - self._check_is_fitted('predict_log_proba') - - # BUG: SVM kernel can be wrong type - if hasattr(self.est.best_estimator_, 'kernel'): - self.best_estimator_.kernel = str(self.best_estimator_.kernel) - - if self.ensemble: - return self.ensemble.predict_log_proba(X) - else: - X, _ = self.preprocess(X) - return self.best_estimator_.predict_log_proba(X)
                        - -
                        [docs] @if_delegate_has_method(delegate=('best_estimator_', 'estimator')) - def decision_function(self, X): - """Call decision_function on the estimator with the best found parameters. - - Only available if ``refit=True`` and the underlying estimator supports - ``decision_function``. - - Parameters - ----------- - X : indexable, length n_samples - Must fulfill the input assumptions of the - underlying estimator. - - """ - self._check_is_fitted('decision_function') - - if self.ensemble: - return self.ensemble.decision_function(X) - else: - X, _ = self.preprocess(X) - return self.best_estimator_.decision_function(X)
                        - -
                        [docs] @if_delegate_has_method(delegate=('best_estimator_', 'estimator')) - def transform(self, X): - """Call transform on the estimator with the best found parameters. - - Only available if the underlying estimator supports ``transform`` and - ``refit=True``. - - Parameters - ----------- - X : indexable, length n_samples - Must fulfill the input assumptions of the - underlying estimator. - - """ - self._check_is_fitted('transform') - - if self.ensemble: - return self.ensemble.transform(X) - else: - X = self.preprocess(X) - return self.best_estimator_.transform(X)
                        - -
                        [docs] @if_delegate_has_method(delegate=('best_estimator_', 'estimator')) - def inverse_transform(self, Xt): - """Call inverse_transform on the estimator with the best found params. - - Only available if the underlying estimator implements - ``inverse_transform`` and ``refit=True``. - - Parameters - ----------- - Xt : indexable, length n_samples - Must fulfill the input assumptions of the - underlying estimator. - - """ - self._check_is_fitted('inverse_transform') - - if self.ensemble: - return self.ensemble.transform(Xt) - else: - Xt, _ = self.preprocess(Xt) - return self.best_estimator_.transform(Xt)
                        - -
                        [docs] def preprocess(self, X, y=None): - '''Apply the available preprocssing methods to the features''' - if self.best_imputer is not None: - X = self.best_imputer.transform(X) - - # Only oversample in training phase, i.e. if we have the labels - if y is not None: - if self.best_SMOTE is not None: - X, y = self.best_SMOTE.fit_sample(X, y) - - if self.best_RandomOverSampler is not None: - X, y = self.best_RandomOverSampler.fit_sample(X, y) - - if self.best_groupsel is not None: - X = self.best_groupsel.transform(X) - - if self.best_varsel is not None: - X = self.best_varsel.transform(X) - - if self.best_statisticalsel is not None: - X = self.best_statisticalsel.transform(X) - - if self.best_scaler is not None: - X = self.best_scaler.transform(X) - - if self.best_reliefsel is not None: - X = self.best_reliefsel.transform(X) - - if self.best_pca is not None: - X = self.best_pca.transform(X) - - if self.best_modelsel is not None: - X = self.best_modelsel.transform(X) - - return X, y
                        - - @property - def best_params_(self): - check_is_fitted(self, 'cv_results_') - return self.cv_results_['params_all'][self.best_index_] - - @property - def best_score_(self): - check_is_fitted(self, 'cv_results_') - return self.cv_results_['mean_test_score'][self.best_index_] - - @property - def grid_scores_(self): - warnings.warn( - "The grid_scores_ attribute was deprecated in version 0.18" - " in favor of the more elaborate cv_results_ attribute." - " The grid_scores_ attribute will not be available from 0.20", - DeprecationWarning) - - check_is_fitted(self, 'cv_results_') - grid_scores = list() - - for i, (params, mean, std) in enumerate(zip( - self.cv_results_['params'], - self.cv_results_['mean_test_score'], - self.cv_results_['std_test_score'])): - scores = np.array(list(self.cv_results_['split%d_test_score' - % s][i] - for s in range(self.n_splits_)), - dtype=np.float64) - grid_scores.append(_CVScoreTuple(params, mean, scores)) - - return grid_scores - -
                        [docs] def process_fit(self, n_splits, parameters_est, parameters_all, - test_sample_counts, test_scores, - train_scores, fit_time, score_time, cv_iter, - X, y): - - """ - Process the outcomes of a SearchCV fit and find the best settings - over all cross validations from all hyperparameters tested - - """ - # We take only one result per split, default by sklearn - candidate_params_est = list(parameters_est[::n_splits]) - candidate_params_all = list(parameters_all[::n_splits]) - n_candidates = len(candidate_params_est) - - # Computed the (weighted) mean and std for test scores alone - # NOTE test_sample counts (weights) remain the same for all candidates - test_sample_counts = np.array(test_sample_counts[:n_splits], - dtype=np.int) - - # Store some of the resulting scores - results = dict() - - def _store(key_name, array, weights=None, splits=False, rank=False): - """A small helper to store the scores/times to the cv_results_""" - array = np.array(array, dtype=np.float64).reshape(n_candidates, - n_splits) - if splits: - for split_i in range(n_splits): - results["split%d_%s" - % (split_i, key_name)] = array[:, split_i] - - try: - array_means = np.average(array, axis=1, weights=weights) - except ZeroDivisionError as e: - e = ('[PREDICT Warning] {}. Setting {} to unweighted.').format(e, key_name) - print(e) - array_means = np.average(array, axis=1) - - results['mean_%s' % key_name] = array_means - # Weighted std is not directly available in numpy - try: - array_stds = np.sqrt(np.average((array - - array_means[:, np.newaxis]) ** 2, - axis=1, weights=weights)) - except ZeroDivisionError as e: - e = ('[PREDICT Warning] {}. Setting {} to unweighted.').format(e, key_name) - print(e) - array_stds = np.sqrt(np.average((array - - array_means[:, np.newaxis]) ** 2, - axis=1)) - - results['std_%s' % key_name] = array_stds - - if rank: - results["rank_%s" % key_name] = np.asarray( - rankdata(-array_means, method='min'), dtype=np.int32) - - _store('test_score', test_scores, splits=True, rank=True, - weights=test_sample_counts if self.iid else None) - if self.return_train_score: - _store('train_score', train_scores, splits=True) - _store('fit_time', fit_time) - _store('score_time', score_time) - - # Rank the indices of scores from all parameter settings - ranked_test_scores = results["rank_test_score"] - indices = range(0, len(ranked_test_scores)) - sortedindices = [x for _, x in sorted(zip(ranked_test_scores, indices))] - - # In order to reduce the memory used, we will only save - # a maximum of results - maxlen = min(self.maxlen, n_candidates) - bestindices = sortedindices[0:maxlen] - - candidate_params_est = np.asarray(candidate_params_est)[bestindices].tolist() - candidate_params_all = np.asarray(candidate_params_all)[bestindices].tolist() - for k in results.keys(): - results[k] = results[k][bestindices] - n_candidates = len(candidate_params_est) - - # Store the atributes of the best performing estimator - best_index = np.flatnonzero(results["rank_test_score"] == 1)[0] - best_parameters_est = candidate_params_est[best_index] - best_parameters_all = candidate_params_all[best_index] - - # Use one MaskedArray and mask all the places where the param is not - # applicable for that candidate. Use defaultdict as each candidate may - # not contain all the params - param_results = defaultdict(partial(MaskedArray, - np.empty(n_candidates,), - mask=True, - dtype=object)) - for cand_i, params in enumerate(candidate_params_all): - for name, value in params.items(): - # An all masked empty array gets created for the key - # `"param_%s" % name` at the first occurence of `name`. - # Setting the value at an index also unmasks that index - param_results["param_%s" % name][cand_i] = value - - # Store a list of param dicts at the key 'params' - results['params'] = candidate_params_est - results['params_all'] = candidate_params_all - - self.cv_results_ = results - self.best_index_ = best_index - self.n_splits_ = n_splits - self.cv_iter = cv_iter - - # Refit all objects with best settings on the full dataset - indices = range(0, len(y)) - self.refit_and_score(X, y, best_parameters_all, best_parameters_est, - train=indices, test=indices) - - return self
                        - -
                        [docs] def refit_and_score(self, X, y, parameters_all, parameters_est, - train, test, verbose=None): - """Refit the base estimator and attributes such as GroupSel - - Parameters - ---------- - X: array, mandatory - Array containingfor each object (rows) the feature values - (1st Column) and the associated feature label (2nd Column). - - y: list(?), mandatory - List containing the labels of the objects. - - parameters_all: dictionary, mandatory - Contains the settings used for the all preprocessing functions - and the fitting. TODO: Create a default object and show the - fields. - - parameters_est: dictionary, mandatory - Contains the settings used for the base estimator - - train: list, mandatory - Indices of the objects to be used as training set. - - test: list, mandatory - Indices of the objects to be used as testing set. - - - """ - - if verbose is None: - verbose = self.verbose - - # Refit all preprocessing functions - out = fit_and_score(X, y, self.scoring, - train, test, parameters_all, - fit_params=self.fit_params, - return_train_score=self.return_train_score, - return_n_test_samples=True, - return_times=True, return_parameters=True, - error_score=self.error_score, - verbose=verbose, - return_all=True) - - # Associate best options with new fits - (save_data, GroupSel, VarSel, SelectModel, feature_labels, scalers,\ - Imputers, PCAs, StatisticalSel, ReliefSel, sm, ros) = out - self.best_groupsel = GroupSel - self.best_scaler = scalers - self.best_varsel = VarSel - self.best_modelsel = SelectModel - self.best_imputer = Imputers - self.best_pca = PCAs - self.best_featlab = feature_labels - self.best_statisticalsel = StatisticalSel - self.best_reliefsel = ReliefSel - self.best_SMOTE = sm - self.best_RandomOverSampler = ros - - # Fit the estimator using the preprocessed features - X = [x[0] for x in X] - X, y = self.preprocess(X, y) - - parameters_est = delete_nonestimator_parameters(parameters_est) - best_estimator = cc.construct_classifier(parameters_all) - - # NOTE: This just has to go to the construct classifier function, - # although it is more convenient here due to the hyperparameter search - if type(y) is list: - labellength = 1 - else: - try: - labellength = y.shape[1] - except IndexError: - labellength = 1 - - if labellength > 1 and type(best_estimator) != RankedSVM: - # Multiclass, hence employ a multiclass classifier for e.g. SVM, RF - best_estimator = OneVsRestClassifier(best_estimator) - - if y is not None: - best_estimator.fit(X, y, **self.fit_params) - else: - best_estimator.fit(X, **self.fit_params) - self.best_estimator_ = best_estimator - - return self
                        - -
                        [docs] def create_ensemble(self, X_train, Y_train, verbose=None, initialize=True, - scoring=None, method=50): - # NOTE: Function is still WIP, do not actually use this. - ''' - - Create an (optimal) ensemble of a combination of hyperparameter settings - and the associated groupsels, PCAs, estimators etc. - - Based on Caruana et al. 2004, but a little different: - - 1. Recreate the training/validation splits for a n-fold cross validation. - 2. For each fold: - a. Start with an empty ensemble - b. Create starting ensemble by adding N individually best performing - models on the validation set. N is tuned on the validation set. - c. Add model that improves ensemble performance on validation set the most, with replacement. - d. Repeat (c) untill performance does not increase - - The performance metric is the same as for the original hyperparameter - search, i.e. probably the F1-score for classification and r2-score - for regression. However, we recommend using the SAR score, as this is - more universal. - - Method: top50 or Caruana - - ''' - - # Define a function for scoring the performance of a classifier - def compute_performance(scoring, Y_valid_truth, Y_valid_score): - if scoring == 'f1_weighted': - # Convert score to binaries first - for num in range(0, len(Y_valid_score)): - if Y_valid_score[num] >= 0.5: - Y_valid_score[num] = 1 - else: - Y_valid_score[num] = 0 - - perf = f1_score(Y_valid_truth, Y_valid_score, average='weighted') - elif scoring == 'auc': - perf = roc_auc_score(Y_valid_truth, Y_valid_score) - elif scoring == 'sar': - perf = sar_score(Y_valid_truth, Y_valid_score) - else: - raise KeyError('[PREDICT Warning] No valid score method given in ensembling: ' + str(scoring)) - - return perf - - if verbose is None: - verbose = self.verbose - - if scoring is None: - scoring = self.scoring - - # Get settings for best 100 estimators - parameters_est = self.cv_results_['params'] - parameters_all = self.cv_results_['params_all'] - n_classifiers = len(parameters_est) - n_iter = len(self.cv_iter) - - # Create a new base object for the ensemble components - if type(self) == RandomizedSearchCVfastr: - base_estimator = RandomizedSearchCVfastr() - elif type(self) == RandomizedSearchCVJoblib: - base_estimator = RandomizedSearchCVJoblib() - - if type(method) is int: - # Simply take the top50 best hyperparameters - if verbose: - print(f'Creating ensemble using top {str(method)} individual classifiers.') - ensemble = range(0, method) - - elif method == 'FitNumber': - # Use optimum number of models - - # In order to speed up the process, we precompute all scores of the possible - # classifiers in all cross validation estimatons - - # Create the training and validation set scores - if verbose: - print('Precomputing scores on training and validation set.') - Y_valid_score = list() - Y_valid_truth = list() - performances = np.zeros((n_iter, n_classifiers)) - for it, (train, valid) in enumerate(self.cv_iter): - if verbose: - print(f' - iteration {it + 1} / {n_iter}.') - Y_valid_score_it = np.zeros((n_classifiers, len(valid))) - - # Loop over the 100 best estimators - for num, (p_est, p_all) in enumerate(zip(parameters_est, parameters_all)): - # NOTE: Explicitly exclude validation set, elso refit and score - # somehow still seems to use it. - X_train_temp = [X_train[i] for i in train] - Y_train_temp = [Y_train[i] for i in train] - train_temp = range(0, len(train)) - - # Refit a SearchCV object with the provided parameters - base_estimator.refit_and_score(X_train_temp, Y_train_temp, p_all, - p_est, train_temp, train_temp, - verbose=False) - - # Predict and save scores - X_train_values = [x[0] for x in X_train] # Throw away labels - X_train_values_valid = [X_train_values[i] for i in valid] - Y_valid_score_temp = base_estimator.predict_proba(X_train_values_valid) - - # Only take the probabilities for the second class - Y_valid_score_temp = Y_valid_score_temp[:, 1] - - # Append to array for all classifiers on this validation set - Y_valid_score_it[num, :] = Y_valid_score_temp - - if num == 0: - # Also store the validation ground truths - Y_valid_truth.append(Y_train[valid]) - - performances[it, num] = compute_performance(scoring, - Y_train[valid], - Y_valid_score_temp) - - Y_valid_score.append(Y_valid_score_it) - - # Sorted Ensemble Initialization ------------------------------------- - # Go on adding to the ensemble untill we find the optimal performance - # Initialize variables - - # Note: doing this in a greedy way doesnt work. We compute the - # performances for the ensembles of lengt [1, n_classifiers] and - # select the optimum - best_performance = 0 - new_performance = 0.001 - iteration = 0 - ensemble = list() - y_score = [None]*n_iter - best_index = 0 - single_estimator_performance = new_performance - - if initialize: - # Rank the models based on scoring on the validation set - performances = np.mean(performances, axis=0) - sortedindices = np.argsort(performances)[::-1] - performances_n_class = list() - - if verbose: - print("\n") - print('Sorted Ensemble Initialization.') - # while new_performance > best_performance: - for dummy in range(0, n_classifiers): - # Score is better, so expand ensemble and replace new best score - best_performance = new_performance - - if iteration > 1: - # Stack scores: not needed for first iteration - ensemble.append(best_index) - # N_models += 1 - for num in range(0, n_iter): - y_score[num] = np.vstack((y_score[num], Y_valid_score[num][ensemble[-1], :])) - - elif iteration == 1: - # Create y_score object for second iteration - single_estimator_performance = new_performance - ensemble.append(best_index) - # N_models += 1 - for num in range(0, n_iter): - y_score[num] = Y_valid_score[num][ensemble[-1], :] - - # Perform n-fold cross validation to estimate performance of next best classifier - performances_temp = np.zeros((n_iter)) - for n_crossval in range(0, n_iter): - # For each estimator, add the score to the ensemble and new ensemble performance - if iteration == 0: - # No y_score yet, so we need to build it instead of stacking - y_valid_score_new = Y_valid_score[n_crossval][sortedindices[iteration], :] - else: - # Stack scores of added model on top of previous scores and average - y_valid_score_new = np.mean(np.vstack((y_score[n_crossval], Y_valid_score[n_crossval][sortedindices[iteration], :])), axis=0) - - perf = compute_performance(scoring, Y_valid_truth[n_crossval], y_valid_score_new) - performances_temp[n_crossval] = perf - - # Check which ensemble should be in the ensemble to maximally improve - new_performance = np.mean(performances_temp) - performances_n_class.append(new_performance) - best_index = sortedindices[iteration] - iteration += 1 - - # Select N_models for initialization - new_performance = max(performances_n_class) - N_models = performances_n_class.index(new_performance) + 1 # +1 due to python indexing - ensemble = ensemble[0:N_models] - best_performance = new_performance - - # Print the performance gain - print(f"Ensembling best {scoring}: {best_performance}.") - print(f"Single estimator best {scoring}: {single_estimator_performance}.") - print(f'Ensemble consists of {len(ensemble)} estimators {ensemble}.') - - elif method == 'Caruana': - # Use the method from Caruana - if verbose: - print('Creating ensemble with Caruana method.') - - # BUG: kernel parameter is sometimes saved in unicode - for i in range(0, len(parameters_est)): - kernel = str(parameters_est[i][u'kernel']) - del parameters_est[i][u'kernel'] - del parameters_all[i][u'kernel'] - parameters_est[i]['kernel'] = kernel - parameters_all[i]['kernel'] = kernel - - # In order to speed up the process, we precompute all scores of the possible - # classifiers in all cross validation estimatons - - # Create the training and validation set scores - if verbose: - print('Precomputing scores on training and validation set.') - Y_valid_score = list() - Y_valid_truth = list() - performances = np.zeros((n_iter, n_classifiers)) - for it, (train, valid) in enumerate(self.cv_iter): - if verbose: - print(f' - iteration {it + 1} / {n_iter}.') - Y_valid_score_it = np.zeros((n_classifiers, len(valid))) - - # Loop over the 100 best estimators - for num, (p_est, p_all) in enumerate(zip(parameters_est, parameters_all)): - # NOTE: Explicitly exclude validation set, elso refit and score - # somehow still seems to use it. - X_train_temp = [X_train[i] for i in train] - Y_train_temp = [Y_train[i] for i in train] - train_temp = range(0, len(train)) - - # Refit a SearchCV object with the provided parameters - base_estimator.refit_and_score(X_train_temp, Y_train_temp, p_all, - p_est, train_temp, train_temp, - verbose=False) - - # Predict and save scores - X_train_values = [x[0] for x in X_train] # Throw away labels - X_train_values_valid = [X_train_values[i] for i in valid] - Y_valid_score_temp = base_estimator.predict_proba(X_train_values_valid) - - # Only take the probabilities for the second class - Y_valid_score_temp = Y_valid_score_temp[:, 1] - - # Append to array for all classifiers on this validation set - Y_valid_score_it[num, :] = Y_valid_score_temp - - if num == 0: - # Also store the validation ground truths - Y_valid_truth.append(Y_train[valid]) - - performances[it, num] = compute_performance(scoring, - Y_train[valid], - Y_valid_score_temp) - - Y_valid_score.append(Y_valid_score_it) - - # Sorted Ensemble Initialization ------------------------------------- - # Go on adding to the ensemble untill we find the optimal performance - # Initialize variables - - # Note: doing this in a greedy way doesnt work. We compute the - # performances for the ensembles of lengt [1, n_classifiers] and - # select the optimum - best_performance = 0 - new_performance = 0.001 - iteration = 0 - ensemble = list() - y_score = [None]*n_iter - best_index = 0 - single_estimator_performance = new_performance - - if initialize: - # Rank the models based on scoring on the validation set - performances = np.mean(performances, axis=0) - sortedindices = np.argsort(performances)[::-1] - performances_n_class = list() - - if verbose: - print("\n") - print('Sorted Ensemble Initialization.') - # while new_performance > best_performance: - for dummy in range(0, n_classifiers): - # Score is better, so expand ensemble and replace new best score - best_performance = new_performance - - if iteration > 1: - # Stack scores: not needed for first iteration - ensemble.append(best_index) - # N_models += 1 - for num in range(0, n_iter): - y_score[num] = np.vstack((y_score[num], Y_valid_score[num][ensemble[-1], :])) - - elif iteration == 1: - # Create y_score object for second iteration - single_estimator_performance = new_performance - ensemble.append(best_index) - # N_models += 1 - for num in range(0, n_iter): - y_score[num] = Y_valid_score[num][ensemble[-1], :] - - # Perform n-fold cross validation to estimate performance of next best classifier - performances_temp = np.zeros((n_iter)) - for n_crossval in range(0, n_iter): - # For each estimator, add the score to the ensemble and new ensemble performance - if iteration == 0: - # No y_score yet, so we need to build it instead of stacking - y_valid_score_new = Y_valid_score[n_crossval][sortedindices[iteration], :] - else: - # Stack scores of added model on top of previous scores and average - y_valid_score_new = np.mean(np.vstack((y_score[n_crossval], Y_valid_score[n_crossval][sortedindices[iteration], :])), axis=0) - - perf = compute_performance(scoring, Y_valid_truth[n_crossval], y_valid_score_new) - performances_temp[n_crossval] = perf - - # Check which ensemble should be in the ensemble to maximally improve - new_performance = np.mean(performances_temp) - performances_n_class.append(new_performance) - best_index = sortedindices[iteration] - iteration += 1 - - # Select N_models for initialization - new_performance = max(performances_n_class) - N_models = performances_n_class.index(new_performance) + 1 # +1 due to python indexing - ensemble = ensemble[0:N_models] - best_performance = new_performance - - # Print the performance gain - print(f"Ensembling best {scoring}: {best_performance}.") - print(f"Single estimator best {scoring}: {single_estimator_performance}.") - print(f'Ensemble consists of {len(ensemble)} estimators {ensemble}.') - - # Greedy selection ----------------------------------------------- - # Initialize variables - best_performance -= 1e-10 - iteration = 0 - - # Go on adding to the ensemble untill we find the optimal performance - if verbose: - print("\n") - print('Greedy selection.') - while new_performance > best_performance: - # Score is better, so expand ensemble and replace new best score - if verbose: - print(f"Iteration: {iteration}, best {scoring}: {new_performance}.") - best_performance = new_performance - - if iteration > 1: - # Stack scores: not needed for first iteration - ensemble.append(best_index) - for num in range(0, n_iter): - y_score[num] = np.vstack((y_score[num], Y_valid_score[num][ensemble[-1], :])) - - elif iteration == 1: - if not initialize: - # Create y_score object for second iteration - single_estimator_performance = new_performance - ensemble.append(best_index) - for num in range(0, n_iter): - y_score[num] = Y_valid_score[num][ensemble[-1], :] - else: - # Stack scores: not needed when ensemble initialization is already used - ensemble.append(best_index) - for num in range(0, n_iter): - y_score[num] = np.vstack((y_score[num], Y_valid_score[num][ensemble[-1], :])) - - # Perform n-fold cross validation to estimate performance of each possible addition to ensemble - performances_temp = np.zeros((n_iter, n_classifiers)) - for n_crossval in range(0, n_iter): - # For each estimator, add the score to the ensemble and new ensemble performance - for n_estimator in range(0, n_classifiers): - if iteration == 0: - # No y_score yet, so we need to build it instead of stacking - y_valid_score_new = Y_valid_score[n_crossval][n_estimator, :] - else: - # Stack scores of added model on top of previous scores and average - y_valid_score_new = np.mean(np.vstack((y_score[n_crossval], Y_valid_score[n_crossval][n_estimator, :])), axis=0) - - perf = compute_performance(scoring, Y_valid_truth[n_crossval], y_valid_score_new) - performances_temp[n_crossval, n_estimator] = perf - - # Average performances over crossval - performances_temp = list(np.mean(performances_temp, axis=0)) - - # Check which ensemble should be in the ensemble to maximally improve - new_performance = max(performances_temp) - best_index = performances_temp.index(new_performance) - iteration += 1 - - # Print the performance gain - print(f"Ensembling best {scoring}: {best_performance}.") - print(f"Single estimator best {scoring}: {single_estimator_performance}.") - print(f'Ensemble consists of {len(ensemble)} estimators {ensemble}.') - else: - print('[PREDICT WARNING] No valid ensemble method given: {}. Not ensembling').format(str(method)) - return self - - # Create the ensemble -------------------------------------------------- - # Create the ensemble trained on the full training set - parameters_est = [parameters_est[i] for i in ensemble] - parameters_all = [parameters_all[i] for i in ensemble] - estimators = list() - train = range(0, len(X_train)) - nest = len(ensemble) - for enum, (p_est, p_all) in enumerate(zip(parameters_est, parameters_all)): - # Refit a SearchCV object with the provided parameters - print(f"Refitting estimator {enum+1} / {nest}.") - base_estimator = clone(base_estimator) - - # # Check if we need to create a multiclass estimator - # if Y_train.shape[1] > 1 and type(base_estimator) != RankedSVM: - # # Multiclass, hence employ a multiclass classifier for SVM - # base_estimator = OneVsRestClassifier(base_estimator) - - base_estimator.refit_and_score(X_train, Y_train, p_all, - p_est, train, train, - verbose=False) - - estimators.append(base_estimator) - - self.ensemble = Ensemble(estimators) - - print("\n") - return self
                        - - -
                        [docs]class BaseSearchCVfastr(BaseSearchCV): - """Base class for hyper parameter search with cross-validation.""" - - def _fit(self, X, y, groups, parameter_iterable): - """Actual fitting, performing the search over parameters.""" - - regressors = ['SVR', 'RFR', 'SGDR', 'Lasso', 'ElasticNet'] - isclassifier =\ - not any(clf in regressors for clf in self.param_distributions['classifiers']) - - cv = check_cv(self.cv, y, classifier=isclassifier) - - X, y, groups = indexable(X, y, groups) - n_splits = cv.get_n_splits(X, y, groups) - if self.verbose > 0 and isinstance(parameter_iterable, Sized): - n_candidates = len(parameter_iterable) - print(f"Fitting {n_splits} folds for each of {n_candidates} candidates, totalling {n_candidates * n_splits} fits.") - - cv_iter = list(cv.split(X, y, groups)) - name = ''.join(random.choice(string.ascii_uppercase + string.digits) for _ in range(10)) - tempfolder = os.path.join(fastr.config.mounts['tmp'], 'GS', name) - if not os.path.exists(tempfolder): - os.makedirs(tempfolder) - - # Create the parameter files - parameters_temp = dict() - try: - for num, parameters in enumerate(parameter_iterable): - - parameters["Number"] = str(num) - parameters_temp[str(num)] = parameters - except ValueError: - # One of the parameters gives an error. Find out which one. - param_grid = dict() - for k, v in parameter_iterable.param_distributions.iteritems(): - param_grid[k] = v - sampled_params = ParameterSampler(param_grid, 5) - try: - for num, parameters in enumerate(sampled_params): - a = 1 - except ValueError: - break - - message = 'One or more of the values in your parameter sampler ' +\ - 'is either not iterable, or the distribution cannot ' +\ - 'generate valid samples. Please check your ' +\ - (' parameters. At least {} gives an error.').format(k) - raise PREDICTexceptions.PREDICTValueError(message) - - # Split the parameters files in equal parts - keys = list(parameters_temp.keys()) - keys = chunks(keys, self.n_jobspercore) - parameter_files = dict() - for num, k in enumerate(keys): - temp_dict = dict() - for number in k: - temp_dict[number] = parameters_temp[number] - - fname = ('settings_{}.json').format(str(num)) - sourcename = os.path.join(tempfolder, 'parameters', fname) - if not os.path.exists(os.path.dirname(sourcename)): - os.makedirs(os.path.dirname(sourcename)) - with open(sourcename, 'w') as fp: - json.dump(temp_dict, fp, indent=4) - - parameter_files[str(num)] =\ - ('vfs://tmp/{}/{}/{}/{}').format('GS', - name, - 'parameters', - fname) - - # Create test-train splits - traintest_files = dict() - # TODO: ugly nummering solution - num = 0 - for train, test in cv_iter: - source_labels = ['train', 'test'] - - source_data = pd.Series([train, test], - index=source_labels, - name='Train-test data') - - fname = ('traintest_{}.hdf5').format(str(num)) - sourcename = os.path.join(tempfolder, 'traintest', fname) - if not os.path.exists(os.path.dirname(sourcename)): - os.makedirs(os.path.dirname(sourcename)) - traintest_files[str(num)] = ('vfs://tmp/{}/{}/{}/{}').format('GS', - name, - 'traintest', - fname) - - sourcelabel = ("Source Data Iteration {}").format(str(num)) - source_data.to_hdf(sourcename, sourcelabel) - - num += 1 - - # Create the files containing the estimator and settings - estimator_labels = ['X', 'y', 'scoring', - 'verbose', 'fit_params', 'return_train_score', - 'return_n_test_samples', - 'return_times', 'return_parameters', - 'error_score'] - - estimator_data = pd.Series([X, y, self.scoring, - self.verbose, - self.fit_params, self.return_train_score, - True, True, True, - self.error_score], - index=estimator_labels, - name='estimator Data') - fname = 'estimatordata.hdf5' - estimatorname = os.path.join(tempfolder, fname) - estimator_data.to_hdf(estimatorname, 'Estimator Data') - - estimatordata = ("vfs://tmp/{}/{}/{}").format('GS', name, fname) - - # Create the fastr network - network = fastr.create_network('PREDICT_GridSearch_' + name) - estimator_data = network.create_source('HDF5', id='estimator_source') - traintest_data = network.create_source('HDF5', id='traintest') - parameter_data = network.create_source('JsonFile', id='parameters') - sink_output = network.create_sink('HDF5', id='output') - - fitandscore = network.create_node('worc/fitandscore:1.0', tool_version='1.0', id='fitandscore', resources=ResourceLimit(memory='2G')) - fitandscore.inputs['estimatordata'].input_group = 'estimator' - fitandscore.inputs['traintest'].input_group = 'traintest' - fitandscore.inputs['parameters'].input_group = 'parameters' - - fitandscore.inputs['estimatordata'] = estimator_data.output - fitandscore.inputs['traintest'] = traintest_data.output - fitandscore.inputs['parameters'] = parameter_data.output - sink_output.input = fitandscore.outputs['fittedestimator'] - - source_data = {'estimator_source': estimatordata, - 'traintest': traintest_files, - 'parameters': parameter_files} - sink_data = {'output': ("vfs://tmp/{}/{}/output_{{sample_id}}_{{cardinality}}{{ext}}").format('GS', name)} - - network.execute(source_data, sink_data, - tmpdir=os.path.join(tempfolder, 'tmp'), - execution_plugin=self.fastr_plugin) - - # Read in the output data once finished - # TODO: expanding fastr url is probably a nicer way - sink_files = glob.glob(os.path.join(fastr.config.mounts['tmp'], 'GS', name) + '/output*.hdf5') - save_data = list() - for output in sink_files: - data = pd.read_hdf(output) - save_data.extend(list(data['RET'])) - - # if one choose to see train score, "out" will contain train score info - try: - if self.return_train_score: - (train_scores, test_scores, test_sample_counts, - fit_time, score_time, parameters_est, parameters_all) =\ - zip(*save_data) - else: - (test_scores, test_sample_counts, - fit_time, score_time, parameters_est, parameters_all) =\ - zip(*save_data) - except ValueError as e: - print(e) - message = ('Fitting classifiers has failed. The temporary ' + - 'results where not deleted and can be found in {}. ' + - 'Probably your fitting and scoring failed: check out ' + - 'the tmp/fitandscore folder within the tempfolder for ' + - 'the fastr job temporary results.').format(tempfolder) - raise PREDICTexceptions.PREDICTValueError(message) - - # Remove the temporary folder used - shutil.rmtree(tempfolder) - - # Process the results of the fitting procedure - self.process_fit(n_splits=n_splits, - parameters_est=parameters_est, - parameters_all=parameters_all, - test_sample_counts=test_sample_counts, - test_scores=test_scores, - train_scores=train_scores, - fit_time=fit_time, - score_time=score_time, - cv_iter=cv_iter, - X=X, y=y)
                        - - -
                        [docs]class RandomizedSearchCVfastr(BaseSearchCVfastr): - """Randomized search on hyper parameters. - - RandomizedSearchCV implements a "fit" and a "score" method. - It also implements "predict", "predict_proba", "decision_function", - "transform" and "inverse_transform" if they are implemented in the - estimator used. - - The parameters of the estimator used to apply these methods are optimized - by cross-validated search over parameter settings. - - In contrast to GridSearchCV, not all parameter values are tried out, but - rather a fixed number of parameter settings is sampled from the specified - distributions. The number of parameter settings that are tried is - given by n_iter. - - If all parameters are presented as a list, - sampling without replacement is performed. If at least one parameter - is given as a distribution, sampling with replacement is used. - It is highly recommended to use continuous distributions for continuous - parameters. - - Read more in the :ref:`User Guide <randomized_parameter_search>`. - - Parameters - ---------- - estimator : estimator object. - A object of that type is instantiated for each grid point. - This is assumed to implement the scikit-learn estimator interface. - Either estimator needs to provide a ``score`` function, - or ``scoring`` must be passed. - - param_distributions : dict - Dictionary with parameters names (string) as keys and distributions - or lists of parameters to try. Distributions must provide a ``rvs`` - method for sampling (such as those from scipy.stats.distributions). - If a list is given, it is sampled uniformly. - - n_iter : int, default=10 - Number of parameter settings that are sampled. n_iter trades - off runtime vs quality of the solution. - - scoring : string, callable or None, default=None - A string (see model evaluation documentation) or - a scorer callable object / function with signature - ``scorer(estimator, X, y)``. - If ``None``, the ``score`` method of the estimator is used. - - fit_params : dict, optional - Parameters to pass to the fit method. - - n_jobs : int, default=1 - Number of jobs to run in parallel. - - pre_dispatch : int, or string, optional - Controls the number of jobs that get dispatched during parallel - execution. Reducing this number can be useful to avoid an - explosion of memory consumption when more jobs get dispatched - than CPUs can process. This parameter can be: - - - None, in which case all the jobs are immediately - created and spawned. Use this for lightweight and - fast-running jobs, to avoid delays due to on-demand - spawning of the jobs - - - An int, giving the exact number of total jobs that are - spawned - - - A string, giving an expression as a function of n_jobs, - as in '2*n_jobs' - - iid : boolean, default=True - If True, the data is assumed to be identically distributed across - the folds, and the loss minimized is the total loss per sample, - and not the mean loss across the folds. - - cv : int, cross-validation generator or an iterable, optional - Determines the cross-validation splitting strategy. - Possible inputs for cv are: - - None, to use the default 3-fold cross validation, - - integer, to specify the number of folds in a `(Stratified)KFold`, - - An object to be used as a cross-validation generator. - - An iterable yielding train, test splits. - - For integer/None inputs, if the estimator is a classifier and ``y`` is - either binary or multiclass, :class:`StratifiedKFold` is used. In all - other cases, :class:`KFold` is used. - - Refer :ref:`User Guide <cross_validation>` for the various - cross-validation strategies that can be used here. - - refit : boolean, default=True - Refit the best estimator with the entire dataset. - If "False", it is impossible to make predictions using - this RandomizedSearchCV instance after fitting. - - verbose : integer - Controls the verbosity: the higher, the more messages. - - random_state : int or RandomState - Pseudo random number generator state used for random uniform sampling - from lists of possible values instead of scipy.stats distributions. - - error_score : 'raise' (default) or numeric - Value to assign to the score if an error occurs in estimator fitting. - If set to 'raise', the error is raised. If a numeric value is given, - FitFailedWarning is raised. This parameter does not affect the refit - step, which will always raise the error. - - return_train_score : boolean, default=True - If ``'False'``, the ``cv_results_`` attribute will not include training - scores. - - Attributes - ---------- - cv_results_ : dict of numpy (masked) ndarrays - A dict with keys as column headers and values as columns, that can be - imported into a pandas ``DataFrame``. - - For instance the below given table - - +--------------+-------------+-------------------+---+---------------+ - | param_kernel | param_gamma | split0_test_score |...|rank_test_score| - +==============+=============+===================+===+===============+ - | 'rbf' | 0.1 | 0.8 |...| 2 | - +--------------+-------------+-------------------+---+---------------+ - | 'rbf' | 0.2 | 0.9 |...| 1 | - +--------------+-------------+-------------------+---+---------------+ - | 'rbf' | 0.3 | 0.7 |...| 1 | - +--------------+-------------+-------------------+---+---------------+ - - will be represented by a ``cv_results_`` dict of:: - - { - 'param_kernel' : masked_array(data = ['rbf', 'rbf', 'rbf'], - mask = False), - 'param_gamma' : masked_array(data = [0.1 0.2 0.3], mask = False), - 'split0_test_score' : [0.8, 0.9, 0.7], - 'split1_test_score' : [0.82, 0.5, 0.7], - 'mean_test_score' : [0.81, 0.7, 0.7], - 'std_test_score' : [0.02, 0.2, 0.], - 'rank_test_score' : [3, 1, 1], - 'split0_train_score' : [0.8, 0.9, 0.7], - 'split1_train_score' : [0.82, 0.5, 0.7], - 'mean_train_score' : [0.81, 0.7, 0.7], - 'std_train_score' : [0.03, 0.03, 0.04], - 'mean_fit_time' : [0.73, 0.63, 0.43, 0.49], - 'std_fit_time' : [0.01, 0.02, 0.01, 0.01], - 'mean_score_time' : [0.007, 0.06, 0.04, 0.04], - 'std_score_time' : [0.001, 0.002, 0.003, 0.005], - 'params' : [{'kernel' : 'rbf', 'gamma' : 0.1}, ...], - } - - NOTE that the key ``'params'`` is used to store a list of parameter - settings dict for all the parameter candidates. - - The ``mean_fit_time``, ``std_fit_time``, ``mean_score_time`` and - ``std_score_time`` are all in seconds. - - best_estimator_ : estimator - Estimator that was chosen by the search, i.e. estimator - which gave highest score (or smallest loss if specified) - on the left out data. Not available if refit=False. - - best_score_ : float - Score of best_estimator on the left out data. - - best_params_ : dict - Parameter setting that gave the best results on the hold out data. - - best_index_ : int - The index (of the ``cv_results_`` arrays) which corresponds to the best - candidate parameter setting. - - The dict at ``search.cv_results_['params'][search.best_index_]`` gives - the parameter setting for the best model, that gives the highest - mean score (``search.best_score_``). - - scorer_ : function - Scorer function used on the held out data to choose the best - parameters for the model. - - n_splits_ : int - The number of cross-validation splits (folds/iterations). - - Notes - ----- - The parameters selected are those that maximize the score of the held-out - data, according to the scoring parameter. - - If `n_jobs` was set to a value higher than one, the data is copied for each - parameter setting(and not `n_jobs` times). This is done for efficiency - reasons if individual jobs take very little time, but may raise errors if - the dataset is large and not enough memory is available. A workaround in - this case is to set `pre_dispatch`. Then, the memory is copied only - `pre_dispatch` many times. A reasonable value for `pre_dispatch` is `2 * - n_jobs`. - - See Also - -------- - :class:`GridSearchCV`: - Does exhaustive search over a grid of parameters. - - :class:`ParameterSampler`: - A generator over parameter settings, constructed from - param_distributions. - - """ - -
                        [docs] def __init__(self, param_distributions={}, n_iter=10, scoring=None, - fit_params=None, n_jobs=1, iid=True, refit=True, cv=None, - verbose=0, pre_dispatch='2*n_jobs', random_state=None, - error_score='raise', return_train_score=True, - n_jobspercore=100, fastr_plugin=None): - super(RandomizedSearchCVfastr, self).__init__( - param_distributions=param_distributions, scoring=scoring, fit_params=fit_params, - n_iter=n_iter, random_state=random_state, n_jobs=n_jobs, iid=iid, refit=refit, cv=cv, verbose=verbose, - pre_dispatch=pre_dispatch, error_score=error_score, - return_train_score=return_train_score, - n_jobspercore=n_jobspercore, fastr_plugin=None)
                        - -
                        [docs] def fit(self, X, y=None, groups=None): - """Run fit on the estimator with randomly drawn parameters. - - Parameters - ---------- - X : array-like, shape = [n_samples, n_features] - Training vector, where n_samples in the number of samples and - n_features is the number of features. - - y : array-like, shape = [n_samples] or [n_samples, n_output], optional - Target relative to X for classification or regression; - None for unsupervised learning. - - groups : array-like, with shape (n_samples,), optional - Group labels for the samples used while splitting the dataset into - train/test set. - """ - print("Fit: " + str(self.n_iter)) - sampled_params = ParameterSampler(self.param_distributions, - self.n_iter, - random_state=self.random_state) - return self._fit(X, y, groups, sampled_params)
                        - - -
                        [docs]class BaseSearchCVJoblib(BaseSearchCV): - """Base class for hyper parameter search with cross-validation.""" - - def _fit(self, X, y, groups, parameter_iterable): - """Actual fitting, performing the search over parameters.""" - - regressors = ['SVR', 'RFR', 'SGDR', 'Lasso', 'ElasticNet'] - isclassifier =\ - not any(clf in regressors for clf in self.param_distributions['classifiers']) - - cv = check_cv(self.cv, y, classifier=isclassifier) - - X, y, groups = indexable(X, y, groups) - n_splits = cv.get_n_splits(X, y, groups) - if self.verbose > 0 and isinstance(parameter_iterable, Sized): - n_candidates = len(parameter_iterable) - print("Fitting {0} folds for each of {1} candidates, totalling" - " {2} fits".format(n_splits, n_candidates, - n_candidates * n_splits)) - - pre_dispatch = self.pre_dispatch - cv_iter = list(cv.split(X, y, groups)) - - out = Parallel( - n_jobs=self.n_jobs, verbose=self.verbose, - pre_dispatch=pre_dispatch - )(delayed(fit_and_score)(X, y, self.scoring, - train, test, parameters, - fit_params=self.fit_params, - return_train_score=self.return_train_score, - return_n_test_samples=True, - return_times=True, return_parameters=True, - error_score=self.error_score, - verbose=self.verbose, - return_all=False) - for parameters in parameter_iterable - for train, test in cv_iter) - save_data = zip(*out) - - # if one choose to see train score, "out" will contain train score info - if self.return_train_score: - (train_scores, test_scores, test_sample_counts, - fit_time, score_time, parameters_est, parameters_all) =\ - save_data - else: - (test_scores, test_sample_counts, - fit_time, score_time, parameters_est, parameters_all) =\ - save_data - - self.process_fit(n_splits=n_splits, - parameters_est=parameters_est, - parameters_all=parameters_all, - test_sample_counts=test_sample_counts, - test_scores=test_scores, - train_scores=train_scores, - fit_time=fit_time, - score_time=score_time, - cv_iter=cv_iter, - X=X, y=y) - - return self
                        - - -
                        [docs]class GridSearchCVfastr(BaseSearchCVfastr): - """Exhaustive search over specified parameter values for an estimator. - - Important members are fit, predict. - - GridSearchCV implements a "fit" and a "score" method. - It also implements "predict", "predict_proba", "decision_function", - "transform" and "inverse_transform" if they are implemented in the - estimator used. - - The parameters of the estimator used to apply these methods are optimized - by cross-validated grid-search over a parameter grid. - - Read more in the :ref:`User Guide <grid_search>`. - - Parameters - ---------- - estimator : estimator object. - This is assumed to implement the scikit-learn estimator interface. - Either estimator needs to provide a ``score`` function, - or ``scoring`` must be passed. - - param_grid : dict or list of dictionaries - Dictionary with parameters names (string) as keys and lists of - parameter settings to try as values, or a list of such - dictionaries, in which case the grids spanned by each dictionary - in the list are explored. This enables searching over any sequence - of parameter settings. - - scoring : string, callable or None, default=None - A string (see model evaluation documentation) or - a scorer callable object / function with signature - ``scorer(estimator, X, y)``. - If ``None``, the ``score`` method of the estimator is used. - - fit_params : dict, optional - Parameters to pass to the fit method. - - n_jobs : int, default=1 - Number of jobs to run in parallel. - - pre_dispatch : int, or string, optional - Controls the number of jobs that get dispatched during parallel - execution. Reducing this number can be useful to avoid an - explosion of memory consumption when more jobs get dispatched - than CPUs can process. This parameter can be: - - - None, in which case all the jobs are immediately - created and spawned. Use this for lightweight and - fast-running jobs, to avoid delays due to on-demand - spawning of the jobs - - - An int, giving the exact number of total jobs that are - spawned - - - A string, giving an expression as a function of n_jobs, - as in '2*n_jobs' - - iid : boolean, default=True - If True, the data is assumed to be identically distributed across - the folds, and the loss minimized is the total loss per sample, - and not the mean loss across the folds. - - cv : int, cross-validation generator or an iterable, optional - Determines the cross-validation splitting strategy. - Possible inputs for cv are: - - None, to use the default 3-fold cross validation, - - integer, to specify the number of folds in a `(Stratified)KFold`, - - An object to be used as a cross-validation generator. - - An iterable yielding train, test splits. - - For integer/None inputs, if the estimator is a classifier and ``y`` is - either binary or multiclass, :class:`StratifiedKFold` is used. In all - other cases, :class:`KFold` is used. - - Refer :ref:`User Guide <cross_validation>` for the various - cross-validation strategies that can be used here. - - refit : boolean, default=True - Refit the best estimator with the entire dataset. - If "False", it is impossible to make predictions using - this GridSearchCV instance after fitting. - - verbose : integer - Controls the verbosity: the higher, the more messages. - - error_score : 'raise' (default) or numeric - Value to assign to the score if an error occurs in estimator fitting. - If set to 'raise', the error is raised. If a numeric value is given, - FitFailedWarning is raised. This parameter does not affect the refit - step, which will always raise the error. - - return_train_score : boolean, default=True - If ``'False'``, the ``cv_results_`` attribute will not include training - scores. - - - Examples - -------- - >>> from sklearn import svm, datasets - >>> from sklearn.model_selection import GridSearchCV - >>> iris = datasets.load_iris() - >>> parameters = {'kernel':('linear', 'rbf'), 'C':[1, 10]} - >>> svr = svm.SVC() - >>> clf = GridSearchCV(svr, parameters) - >>> clf.fit(iris.data, iris.target) - ... # doctest: +NORMALIZE_WHITESPACE +ELLIPSIS - GridSearchCV(cv=None, error_score=..., - estimator=SVC(C=1.0, cache_size=..., class_weight=..., coef0=..., - decision_function_shape=None, degree=..., gamma=..., - kernel='rbf', max_iter=-1, probability=False, - random_state=None, shrinking=True, tol=..., - verbose=False), - fit_params={}, iid=..., n_jobs=1, - param_grid=..., pre_dispatch=..., refit=..., return_train_score=..., - scoring=..., verbose=...) - >>> sorted(clf.cv_results_.keys()) - ... # doctest: +NORMALIZE_WHITESPACE +ELLIPSIS - ['mean_fit_time', 'mean_score_time', 'mean_test_score',... - 'mean_train_score', 'param_C', 'param_kernel', 'params',... - 'rank_test_score', 'split0_test_score',... - 'split0_train_score', 'split1_test_score', 'split1_train_score',... - 'split2_test_score', 'split2_train_score',... - 'std_fit_time', 'std_score_time', 'std_test_score', 'std_train_score'...] - - Attributes - ---------- - cv_results_ : dict of numpy (masked) ndarrays - A dict with keys as column headers and values as columns, that can be - imported into a pandas ``DataFrame``. - - For instance the below given table - - +------------+-----------+------------+-----------------+---+---------+ - |param_kernel|param_gamma|param_degree|split0_test_score|...|rank_....| - +============+===========+============+=================+===+=========+ - | 'poly' | -- | 2 | 0.8 |...| 2 | - +------------+-----------+------------+-----------------+---+---------+ - | 'poly' | -- | 3 | 0.7 |...| 4 | - +------------+-----------+------------+-----------------+---+---------+ - | 'rbf' | 0.1 | -- | 0.8 |...| 3 | - +------------+-----------+------------+-----------------+---+---------+ - | 'rbf' | 0.2 | -- | 0.9 |...| 1 | - +------------+-----------+------------+-----------------+---+---------+ - - will be represented by a ``cv_results_`` dict of:: - - { - 'param_kernel': masked_array(data = ['poly', 'poly', 'rbf', 'rbf'], - mask = [False False False False]...) - 'param_gamma': masked_array(data = [-- -- 0.1 0.2], - mask = [ True True False False]...), - 'param_degree': masked_array(data = [2.0 3.0 -- --], - mask = [False False True True]...), - 'split0_test_score' : [0.8, 0.7, 0.8, 0.9], - 'split1_test_score' : [0.82, 0.5, 0.7, 0.78], - 'mean_test_score' : [0.81, 0.60, 0.75, 0.82], - 'std_test_score' : [0.02, 0.01, 0.03, 0.03], - 'rank_test_score' : [2, 4, 3, 1], - 'split0_train_score' : [0.8, 0.9, 0.7], - 'split1_train_score' : [0.82, 0.5, 0.7], - 'mean_train_score' : [0.81, 0.7, 0.7], - 'std_train_score' : [0.03, 0.03, 0.04], - 'mean_fit_time' : [0.73, 0.63, 0.43, 0.49], - 'std_fit_time' : [0.01, 0.02, 0.01, 0.01], - 'mean_score_time' : [0.007, 0.06, 0.04, 0.04], - 'std_score_time' : [0.001, 0.002, 0.003, 0.005], - 'params' : [{'kernel': 'poly', 'degree': 2}, ...], - } - - NOTE that the key ``'params'`` is used to store a list of parameter - settings dict for all the parameter candidates. - - The ``mean_fit_time``, ``std_fit_time``, ``mean_score_time`` and - ``std_score_time`` are all in seconds. - - best_estimator_ : estimator - Estimator that was chosen by the search, i.e. estimator - which gave highest score (or smallest loss if specified) - on the left out data. Not available if refit=False. - - best_score_ : float - Score of best_estimator on the left out data. - - best_params_ : dict - Parameter setting that gave the best results on the hold out data. - - best_index_ : int - The index (of the ``cv_results_`` arrays) which corresponds to the best - candidate parameter setting. - - The dict at ``search.cv_results_['params'][search.best_index_]`` gives - the parameter setting for the best model, that gives the highest - mean score (``search.best_score_``). - - scorer_ : function - Scorer function used on the held out data to choose the best - parameters for the model. - - n_splits_ : int - The number of cross-validation splits (folds/iterations). - - Notes - ------ - The parameters selected are those that maximize the score of the left out - data, unless an explicit score is passed in which case it is used instead. - - If `n_jobs` was set to a value higher than one, the data is copied for each - point in the grid (and not `n_jobs` times). This is done for efficiency - reasons if individual jobs take very little time, but may raise errors if - the dataset is large and not enough memory is available. A workaround in - this case is to set `pre_dispatch`. Then, the memory is copied only - `pre_dispatch` many times. A reasonable value for `pre_dispatch` is `2 * - n_jobs`. - - See Also - --------- - :class:`ParameterGrid`: - generates all the combinations of a hyperparameter grid. - - :func:`sklearn.model_selection.train_test_split`: - utility function to split the data into a development set usable - for fitting a GridSearchCV instance and an evaluation set for - its final evaluation. - - :func:`sklearn.metrics.make_scorer`: - Make a scorer from a performance metric or loss function. - - """ - -
                        [docs] def __init__(self, estimator, param_grid, scoring=None, fit_params=None, - n_jobs=1, iid=True, refit=True, cv=None, verbose=0, - pre_dispatch='2*n_jobs', error_score='raise', - return_train_score=True): - super(GridSearchCVfastr, self).__init__( - scoring=scoring, fit_params=fit_params, - n_jobs=n_jobs, iid=iid, refit=refit, cv=cv, verbose=verbose, - pre_dispatch=pre_dispatch, error_score=error_score, - return_train_score=return_train_score, fastr_plugin=None) - self.param_grid = param_grid - _check_param_grid(param_grid)
                        - -
                        [docs] def fit(self, X, y=None, groups=None): - """Run fit with all sets of parameters. - - Parameters - ---------- - - X : array-like, shape = [n_samples, n_features] - Training vector, where n_samples is the number of samples and - n_features is the number of features. - - y : array-like, shape = [n_samples] or [n_samples, n_output], optional - Target relative to X for classification or regression; - None for unsupervised learning. - - groups : array-like, with shape (n_samples,), optional - Group labels for the samples used while splitting the dataset into - train/test set. - """ - return self._fit(X, y, groups, ParameterGrid(self.param_grid))
                        - - -
                        [docs]class RandomizedSearchCVJoblib(BaseSearchCVJoblib): - """Randomized search on hyper parameters. - - RandomizedSearchCV implements a "fit" and a "score" method. - It also implements "predict", "predict_proba", "decision_function", - "transform" and "inverse_transform" if they are implemented in the - estimator used. - - The parameters of the estimator used to apply these methods are optimized - by cross-validated search over parameter settings. - - In contrast to GridSearchCV, not all parameter values are tried out, but - rather a fixed number of parameter settings is sampled from the specified - distributions. The number of parameter settings that are tried is - given by n_iter. - - If all parameters are presented as a list, - sampling without replacement is performed. If at least one parameter - is given as a distribution, sampling with replacement is used. - It is highly recommended to use continuous distributions for continuous - parameters. - - Read more in the :ref:`User Guide <randomized_parameter_search>`. - - Parameters - ---------- - estimator : estimator object. - A object of that type is instantiated for each grid point. - This is assumed to implement the scikit-learn estimator interface. - Either estimator needs to provide a ``score`` function, - or ``scoring`` must be passed. - - param_distributions : dict - Dictionary with parameters names (string) as keys and distributions - or lists of parameters to try. Distributions must provide a ``rvs`` - method for sampling (such as those from scipy.stats.distributions). - If a list is given, it is sampled uniformly. - - n_iter : int, default=10 - Number of parameter settings that are sampled. n_iter trades - off runtime vs quality of the solution. - - scoring : string, callable or None, default=None - A string (see model evaluation documentation) or - a scorer callable object / function with signature - ``scorer(estimator, X, y)``. - If ``None``, the ``score`` method of the estimator is used. - - fit_params : dict, optional - Parameters to pass to the fit method. - - n_jobs : int, default=1 - Number of jobs to run in parallel. - - pre_dispatch : int, or string, optional - Controls the number of jobs that get dispatched during parallel - execution. Reducing this number can be useful to avoid an - explosion of memory consumption when more jobs get dispatched - than CPUs can process. This parameter can be: - - - None, in which case all the jobs are immediately - created and spawned. Use this for lightweight and - fast-running jobs, to avoid delays due to on-demand - spawning of the jobs - - - An int, giving the exact number of total jobs that are - spawned - - - A string, giving an expression as a function of n_jobs, - as in '2*n_jobs' - - iid : boolean, default=True - If True, the data is assumed to be identically distributed across - the folds, and the loss minimized is the total loss per sample, - and not the mean loss across the folds. - - cv : int, cross-validation generator or an iterable, optional - Determines the cross-validation splitting strategy. - Possible inputs for cv are: - - None, to use the default 3-fold cross validation, - - integer, to specify the number of folds in a `(Stratified)KFold`, - - An object to be used as a cross-validation generator. - - An iterable yielding train, test splits. - - For integer/None inputs, if the estimator is a classifier and ``y`` is - either binary or multiclass, :class:`StratifiedKFold` is used. In all - other cases, :class:`KFold` is used. - - Refer :ref:`User Guide <cross_validation>` for the various - cross-validation strategies that can be used here. - - refit : boolean, default=True - Refit the best estimator with the entire dataset. - If "False", it is impossible to make predictions using - this RandomizedSearchCV instance after fitting. - - verbose : integer - Controls the verbosity: the higher, the more messages. - - random_state : int or RandomState - Pseudo random number generator state used for random uniform sampling - from lists of possible values instead of scipy.stats distributions. - - error_score : 'raise' (default) or numeric - Value to assign to the score if an error occurs in estimator fitting. - If set to 'raise', the error is raised. If a numeric value is given, - FitFailedWarning is raised. This parameter does not affect the refit - step, which will always raise the error. - - return_train_score : boolean, default=True - If ``'False'``, the ``cv_results_`` attribute will not include training - scores. - - Attributes - ---------- - cv_results_ : dict of numpy (masked) ndarrays - A dict with keys as column headers and values as columns, that can be - imported into a pandas ``DataFrame``. - - For instance the below given table - - +--------------+-------------+-------------------+---+---------------+ - | param_kernel | param_gamma | split0_test_score |...|rank_test_score| - +==============+=============+===================+===+===============+ - | 'rbf' | 0.1 | 0.8 |...| 2 | - +--------------+-------------+-------------------+---+---------------+ - | 'rbf' | 0.2 | 0.9 |...| 1 | - +--------------+-------------+-------------------+---+---------------+ - | 'rbf' | 0.3 | 0.7 |...| 1 | - +--------------+-------------+-------------------+---+---------------+ - - will be represented by a ``cv_results_`` dict of:: - - { - 'param_kernel' : masked_array(data = ['rbf', 'rbf', 'rbf'], - mask = False), - 'param_gamma' : masked_array(data = [0.1 0.2 0.3], mask = False), - 'split0_test_score' : [0.8, 0.9, 0.7], - 'split1_test_score' : [0.82, 0.5, 0.7], - 'mean_test_score' : [0.81, 0.7, 0.7], - 'std_test_score' : [0.02, 0.2, 0.], - 'rank_test_score' : [3, 1, 1], - 'split0_train_score' : [0.8, 0.9, 0.7], - 'split1_train_score' : [0.82, 0.5, 0.7], - 'mean_train_score' : [0.81, 0.7, 0.7], - 'std_train_score' : [0.03, 0.03, 0.04], - 'mean_fit_time' : [0.73, 0.63, 0.43, 0.49], - 'std_fit_time' : [0.01, 0.02, 0.01, 0.01], - 'mean_score_time' : [0.007, 0.06, 0.04, 0.04], - 'std_score_time' : [0.001, 0.002, 0.003, 0.005], - 'params' : [{'kernel' : 'rbf', 'gamma' : 0.1}, ...], - } - - NOTE that the key ``'params'`` is used to store a list of parameter - settings dict for all the parameter candidates. - - The ``mean_fit_time``, ``std_fit_time``, ``mean_score_time`` and - ``std_score_time`` are all in seconds. - - best_estimator_ : estimator - Estimator that was chosen by the search, i.e. estimator - which gave highest score (or smallest loss if specified) - on the left out data. Not available if refit=False. - - best_score_ : float - Score of best_estimator on the left out data. - - best_params_ : dict - Parameter setting that gave the best results on the hold out data. - - best_index_ : int - The index (of the ``cv_results_`` arrays) which corresponds to the best - candidate parameter setting. - - The dict at ``search.cv_results_['params'][search.best_index_]`` gives - the parameter setting for the best model, that gives the highest - mean score (``search.best_score_``). - - scorer_ : function - Scorer function used on the held out data to choose the best - parameters for the model. - - n_splits_ : int - The number of cross-validation splits (folds/iterations). - - Notes - ----- - The parameters selected are those that maximize the score of the held-out - data, according to the scoring parameter. - - If `n_jobs` was set to a value higher than one, the data is copied for each - parameter setting(and not `n_jobs` times). This is done for efficiency - reasons if individual jobs take very little time, but may raise errors if - the dataset is large and not enough memory is available. A workaround in - this case is to set `pre_dispatch`. Then, the memory is copied only - `pre_dispatch` many times. A reasonable value for `pre_dispatch` is `2 * - n_jobs`. - - See Also - -------- - :class:`GridSearchCV`: - Does exhaustive search over a grid of parameters. - - :class:`ParameterSampler`: - A generator over parameter settins, constructed from - param_distributions. - - """ - -
                        [docs] def __init__(self, param_distributions={}, n_iter=10, scoring=None, - fit_params=None, n_jobs=1, iid=True, refit=True, cv=None, - verbose=0, pre_dispatch='2*n_jobs', random_state=None, - error_score='raise', return_train_score=True, - n_jobspercore=100): - super(RandomizedSearchCVJoblib, self).__init__( - param_distributions=param_distributions, - n_iter=n_iter, scoring=scoring, fit_params=fit_params, - n_jobs=n_jobs, iid=iid, refit=refit, cv=cv, verbose=verbose, - pre_dispatch=pre_dispatch, error_score=error_score, - return_train_score=return_train_score, - n_jobspercore=n_jobspercore, random_state=random_state)
                        - -
                        [docs] def fit(self, X, y=None, groups=None): - """Run fit on the estimator with randomly drawn parameters. - - Parameters - ---------- - X : array-like, shape = [n_samples, n_features] - Training vector, where n_samples in the number of samples and - n_features is the number of features. - - y : array-like, shape = [n_samples] or [n_samples, n_output], optional - Target relative to X for classification or regression; - None for unsupervised learning. - - groups : array-like, with shape (n_samples,), optional - Group labels for the samples used while splitting the dataset into - train/test set. - """ - sampled_params = ParameterSampler(self.param_distributions, - self.n_iter, - random_state=self.random_state) - return self._fit(X, y, groups, sampled_params)
                        - - -
                        [docs]class GridSearchCVJoblib(BaseSearchCVJoblib): - """Exhaustive search over specified parameter values for an estimator. - - Important members are fit, predict. - - GridSearchCV implements a "fit" and a "score" method. - It also implements "predict", "predict_proba", "decision_function", - "transform" and "inverse_transform" if they are implemented in the - estimator used. - - The parameters of the estimator used to apply these methods are optimized - by cross-validated grid-search over a parameter grid. - - Read more in the :ref:`User Guide <grid_search>`. - - Parameters - ---------- - estimator : estimator object. - This is assumed to implement the scikit-learn estimator interface. - Either estimator needs to provide a ``score`` function, - or ``scoring`` must be passed. - - param_grid : dict or list of dictionaries - Dictionary with parameters names (string) as keys and lists of - parameter settings to try as values, or a list of such - dictionaries, in which case the grids spanned by each dictionary - in the list are explored. This enables searching over any sequence - of parameter settings. - - scoring : string, callable or None, default=None - A string (see model evaluation documentation) or - a scorer callable object / function with signature - ``scorer(estimator, X, y)``. - If ``None``, the ``score`` method of the estimator is used. - - fit_params : dict, optional - Parameters to pass to the fit method. - - n_jobs : int, default=1 - Number of jobs to run in parallel. - - pre_dispatch : int, or string, optional - Controls the number of jobs that get dispatched during parallel - execution. Reducing this number can be useful to avoid an - explosion of memory consumption when more jobs get dispatched - than CPUs can process. This parameter can be: - - - None, in which case all the jobs are immediately - created and spawned. Use this for lightweight and - fast-running jobs, to avoid delays due to on-demand - spawning of the jobs - - - An int, giving the exact number of total jobs that are - spawned - - - A string, giving an expression as a function of n_jobs, - as in '2*n_jobs' - - iid : boolean, default=True - If True, the data is assumed to be identically distributed across - the folds, and the loss minimized is the total loss per sample, - and not the mean loss across the folds. - - cv : int, cross-validation generator or an iterable, optional - Determines the cross-validation splitting strategy. - Possible inputs for cv are: - - None, to use the default 3-fold cross validation, - - integer, to specify the number of folds in a `(Stratified)KFold`, - - An object to be used as a cross-validation generator. - - An iterable yielding train, test splits. - - For integer/None inputs, if the estimator is a classifier and ``y`` is - either binary or multiclass, :class:`StratifiedKFold` is used. In all - other cases, :class:`KFold` is used. - - Refer :ref:`User Guide <cross_validation>` for the various - cross-validation strategies that can be used here. - - refit : boolean, default=True - Refit the best estimator with the entire dataset. - If "False", it is impossible to make predictions using - this GridSearchCV instance after fitting. - - verbose : integer - Controls the verbosity: the higher, the more messages. - - error_score : 'raise' (default) or numeric - Value to assign to the score if an error occurs in estimator fitting. - If set to 'raise', the error is raised. If a numeric value is given, - FitFailedWarning is raised. This parameter does not affect the refit - step, which will always raise the error. - - return_train_score : boolean, default=True - If ``'False'``, the ``cv_results_`` attribute will not include training - scores. - - - Examples - -------- - >>> from sklearn import svm, datasets - >>> from sklearn.model_selection import GridSearchCV - >>> iris = datasets.load_iris() - >>> parameters = {'kernel':('linear', 'rbf'), 'C':[1, 10]} - >>> svr = svm.SVC() - >>> clf = GridSearchCV(svr, parameters) - >>> clf.fit(iris.data, iris.target) - ... # doctest: +NORMALIZE_WHITESPACE +ELLIPSIS - GridSearchCV(cv=None, error_score=..., - estimator=SVC(C=1.0, cache_size=..., class_weight=..., coef0=..., - decision_function_shape=None, degree=..., gamma=..., - kernel='rbf', max_iter=-1, probability=False, - random_state=None, shrinking=True, tol=..., - verbose=False), - fit_params={}, iid=..., n_jobs=1, - param_grid=..., pre_dispatch=..., refit=..., return_train_score=..., - scoring=..., verbose=...) - >>> sorted(clf.cv_results_.keys()) - ... # doctest: +NORMALIZE_WHITESPACE +ELLIPSIS - ['mean_fit_time', 'mean_score_time', 'mean_test_score',... - 'mean_train_score', 'param_C', 'param_kernel', 'params',... - 'rank_test_score', 'split0_test_score',... - 'split0_train_score', 'split1_test_score', 'split1_train_score',... - 'split2_test_score', 'split2_train_score',... - 'std_fit_time', 'std_score_time', 'std_test_score', 'std_train_score'...] - - Attributes - ---------- - cv_results_ : dict of numpy (masked) ndarrays - A dict with keys as column headers and values as columns, that can be - imported into a pandas ``DataFrame``. - - For instance the below given table - - +------------+-----------+------------+-----------------+---+---------+ - |param_kernel|param_gamma|param_degree|split0_test_score|...|rank_....| - +============+===========+============+=================+===+=========+ - | 'poly' | -- | 2 | 0.8 |...| 2 | - +------------+-----------+------------+-----------------+---+---------+ - | 'poly' | -- | 3 | 0.7 |...| 4 | - +------------+-----------+------------+-----------------+---+---------+ - | 'rbf' | 0.1 | -- | 0.8 |...| 3 | - +------------+-----------+------------+-----------------+---+---------+ - | 'rbf' | 0.2 | -- | 0.9 |...| 1 | - +------------+-----------+------------+-----------------+---+---------+ - - will be represented by a ``cv_results_`` dict of:: - - { - 'param_kernel': masked_array(data = ['poly', 'poly', 'rbf', 'rbf'], - mask = [False False False False]...) - 'param_gamma': masked_array(data = [-- -- 0.1 0.2], - mask = [ True True False False]...), - 'param_degree': masked_array(data = [2.0 3.0 -- --], - mask = [False False True True]...), - 'split0_test_score' : [0.8, 0.7, 0.8, 0.9], - 'split1_test_score' : [0.82, 0.5, 0.7, 0.78], - 'mean_test_score' : [0.81, 0.60, 0.75, 0.82], - 'std_test_score' : [0.02, 0.01, 0.03, 0.03], - 'rank_test_score' : [2, 4, 3, 1], - 'split0_train_score' : [0.8, 0.9, 0.7], - 'split1_train_score' : [0.82, 0.5, 0.7], - 'mean_train_score' : [0.81, 0.7, 0.7], - 'std_train_score' : [0.03, 0.03, 0.04], - 'mean_fit_time' : [0.73, 0.63, 0.43, 0.49], - 'std_fit_time' : [0.01, 0.02, 0.01, 0.01], - 'mean_score_time' : [0.007, 0.06, 0.04, 0.04], - 'std_score_time' : [0.001, 0.002, 0.003, 0.005], - 'params' : [{'kernel': 'poly', 'degree': 2}, ...], - } - - NOTE that the key ``'params'`` is used to store a list of parameter - settings dict for all the parameter candidates. - - The ``mean_fit_time``, ``std_fit_time``, ``mean_score_time`` and - ``std_score_time`` are all in seconds. - - best_estimator_ : estimator - Estimator that was chosen by the search, i.e. estimator - which gave highest score (or smallest loss if specified) - on the left out data. Not available if refit=False. - - best_score_ : float - Score of best_estimator on the left out data. - - best_params_ : dict - Parameter setting that gave the best results on the hold out data. - - best_index_ : int - The index (of the ``cv_results_`` arrays) which corresponds to the best - candidate parameter setting. - - The dict at ``search.cv_results_['params'][search.best_index_]`` gives - the parameter setting for the best model, that gives the highest - mean score (``search.best_score_``). - - scorer_ : function - Scorer function used on the held out data to choose the best - parameters for the model. - - n_splits_ : int - The number of cross-validation splits (folds/iterations). - - Notes - ------ - The parameters selected are those that maximize the score of the left out - data, unless an explicit score is passed in which case it is used instead. - - If `n_jobs` was set to a value higher than one, the data is copied for each - point in the grid (and not `n_jobs` times). This is done for efficiency - reasons if individual jobs take very little time, but may raise errors if - the dataset is large and not enough memory is available. A workaround in - this case is to set `pre_dispatch`. Then, the memory is copied only - `pre_dispatch` many times. A reasonable value for `pre_dispatch` is `2 * - n_jobs`. - - See Also - --------- - :class:`ParameterGrid`: - generates all the combinations of a hyperparameter grid. - - :func:`sklearn.model_selection.train_test_split`: - utility function to split the data into a development set usable - for fitting a GridSearchCV instance and an evaluation set for - its final evaluation. - - :func:`sklearn.metrics.make_scorer`: - Make a scorer from a performance metric or loss function. - - """ - -
                        [docs] def __init__(self, estimator, param_grid, scoring=None, fit_params=None, - n_jobs=1, iid=True, refit=True, cv=None, verbose=0, - pre_dispatch='2*n_jobs', error_score='raise', - return_train_score=True): - super(GridSearchCVJoblib, self).__init__( - scoring=scoring, fit_params=fit_params, - n_jobs=n_jobs, iid=iid, refit=refit, cv=cv, verbose=verbose, - pre_dispatch=pre_dispatch, error_score=error_score, - return_train_score=return_train_score) - self.param_grid = param_grid - _check_param_grid(param_grid)
                        - -
                        [docs] def fit(self, X, y=None, groups=None): - """Run fit with all sets of parameters. - - Parameters - ---------- - - X : array-like, shape = [n_samples, n_features] - Training vector, where n_samples is the number of samples and - n_features is the number of features. - - y : array-like, shape = [n_samples] or [n_samples, n_output], optional - Target relative to X for classification or regression; - None for unsupervised learning. - - groups : array-like, with shape (n_samples,), optional - Group labels for the samples used while splitting the dataset into - train/test set. - """ - return self._fit(X, y, groups, ParameterGrid(self.param_grid))
                        -
                        - -
                        - -
                        -
                        - - -
                        - -
                        -

                        - © Copyright 2016 -- 2019, Biomedical Imaging Group Rotterdam, Departments of Medical Informatics and Radiology, Erasmus MC, Rotterdam, The Netherlands - -

                        -
                        - Built with Sphinx using a theme provided by Read the Docs. - -
                        - -
                        -
                        - -
                        - -
                        - - - - - - - - - - - - \ No newline at end of file diff --git a/build/lib/WORC/doc/_build/html/_modules/WORC/classification/construct_classifier.html b/build/lib/WORC/doc/_build/html/_modules/WORC/classification/construct_classifier.html deleted file mode 100644 index dc787260..00000000 --- a/build/lib/WORC/doc/_build/html/_modules/WORC/classification/construct_classifier.html +++ /dev/null @@ -1,442 +0,0 @@ - - - - - - - - - - - WORC.classification.construct_classifier — WORC 3.0.0 documentation - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
                        - - - -
                        - - - - - -
                        - -
                        - - - - - - - - - - - - - - - - - -
                        - -
                          - -
                        • Docs »
                        • - -
                        • Module code »
                        • - -
                        • WORC.classification.construct_classifier
                        • - - -
                        • - -
                        • - -
                        - - -
                        -
                        -
                        -
                        - -

                        Source code for WORC.classification.construct_classifier

                        -#!/usr/bin/env python
                        -
                        -# Copyright 2016-2019 Biomedical Imaging Group Rotterdam, Departments of
                        -# Medical Informatics and Radiology, Erasmus MC, Rotterdam, The Netherlands
                        -#
                        -# 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.
                        -
                        -from sklearn.svm import SVC
                        -from sklearn.svm import SVR as SVMR
                        -from sklearn.ensemble import RandomForestClassifier, RandomForestRegressor
                        -from sklearn.linear_model import SGDClassifier, ElasticNet, SGDRegressor
                        -from sklearn.linear_model import LogisticRegression, Lasso
                        -from sklearn.naive_bayes import GaussianNB, ComplementNB
                        -from sklearn.discriminant_analysis import LinearDiscriminantAnalysis as LDA
                        -from sklearn.discriminant_analysis import QuadraticDiscriminantAnalysis as QDA
                        -import scipy
                        -from WORC.classification.estimators import RankedSVM
                        -from WORC.classification.AdvancedSampler import log_uniform, discrete_uniform
                        -import WORC.addexceptions as ae
                        -
                        -
                        -
                        [docs]def construct_classifier(config): - """Interface to create classification - - Different classifications can be created using this common interface - - Parameters - ---------- - config: dict, mandatory - Contains the required config settings. See the Github Wiki for - all available fields. - - Returns: - Constructed classifier - """ - - # NOTE: Function is not working anymore for regression: need - # to move param grid creation to the create_param_grid function - max_iter = config['max_iter'] - if 'SVM' in config['classifiers']: - # Support Vector Machine - classifier = construct_SVM(config) - - elif config['classifiers'] == 'SVR': - # Support Vector Regression - classifier = construct_SVM(config, True) - - elif config['classifiers'] == 'RF': - # Random forest kernel - classifier = RandomForestClassifier(verbose=0, - class_weight='balanced', - n_estimators=config['RFn_estimators'], - min_samples_split=config['RFmin_samples_split'], - max_depth=config['RFmax_depth']) - - elif config['classifiers'] == 'RFR': - # Random forest kernel regression - classifier = RandomForestRegressor(verbose=0, - n_estimators=config['RFn_estimators'], - min_samples_split=config['RFmin_samples_split'], - max_depth=config['RFmax_depth']) - - elif config['classifiers'] == 'ElasticNet': - # Elastic Net Regression - classifier = ElasticNet(alpha=config['ElasticNet_alpha'], - l1_ratio=config['ElasticNet_l1_ratio'], - max_iter=max_iter) - - elif config['classifiers'] == 'Lasso': - # LASSO Regression - param_grid = {'alpha': scipy.stats.uniform(loc=1.0, scale=0.5)} - classifier = Lasso(max_iter=max_iter) - - elif config['classifiers'] == 'SGD': - # Stochastic Gradient Descent classifier - classifier = SGDClassifier(n_iter=config['max_iter'], - alpha=config['SGD_alpha'], - l1_ratio=config['SGD_l1_ratio'], - loss=config['SGD_loss'], - penalty=config['SGD_penalty']) - - elif config['classifiers'] == 'SGDR': - # Stochastic Gradient Descent regressor - classifier = SGDRegressor(n_iter=config['max_iter'], - alpha=config['SGD_alpha'], - l1_ratio=config['SGD_l1_ratio'], - loss=config['SGD_loss'], - penalty=config['SGD_penalty']) - - elif config['classifiers'] == 'LR': - # Logistic Regression - classifier = LogisticRegression(max_iter=max_iter, - penalty=config['LRpenalty'], - C=config['LRC']) - elif config['classifiers'] == 'GaussianNB': - # Naive Bayes classifier using Gaussian distributions - classifier = GaussianNB() - - elif config['classifiers'] == 'ComplementNB': - # Complement Naive Bayes classifier - classifier = ComplementNB() - - elif config['classifiers'] == 'LDA': - # Linear Discriminant Analysis - if config['LDA_solver'] == 'svd': - # Shrinkage does not work with svd solver - shrinkage = None - else: - shrinkage = config['LDA_shrinkage'] - - classifier = LDA(solver=config['LDA_solver'], - shrinkage=shrinkage) - - elif config['classifiers'] == 'QDA': - # Linear Discriminant Analysis - classifier = QDA(reg_param=config['QDA_reg_param']) - else: - message = ('Classifier {} unknown.').format(str(config['classifiers'])) - raise ae.WORCKeyError(message) - - return classifier
                        - - -
                        [docs]def construct_SVM(config, regression=False): - """ - Constructs a SVM classifier - - Args: - config (dict): Dictionary of the required config settings - features (pandas dataframe): A pandas dataframe containing the features - to be used for classification - - Returns: - SVM/SVR classifier, parameter grid - """ - - max_iter = config['max_iter'] - if not regression: - clf = SVC(class_weight='balanced', probability=True, max_iter=max_iter) - else: - clf = SVMR(max_iter=max_iter) - - clf.kernel = str(config['SVMKernel']) - clf.C = config['SVMC'] - clf.degree = config['SVMdegree'] - clf.coef0 = config['SVMcoef0'] - clf.gamma = config['SVMgamma'] - - # Check if we need to use a ranked SVM - if config['classifiers'] == 'RankedSVM': - clf = RankedSVM() - param_grid = {'svm': ['Poly'], - 'degree': [2, 3, 4, 5], - 'gamma': scipy.stats.uniform(loc=0, scale=1e-3), - 'coefficient': scipy.stats.uniform(loc=0, scale=1e-2), - } - - return clf
                        - - -
                        [docs]def create_param_grid(config): - ''' Create a parameter grid for the WORC classifiers based on the - provided configuration. ''' - - # We only need parameters from the Classification part of the config - config = config['Classification'] - - # Create grid and put in name of classifiers and maximum iterations - param_grid = dict() - param_grid['classifiers'] = config['classifiers'] - param_grid['max_iter'] = config['max_iter'] - - # SVM parameters - param_grid['SVMKernel'] = config['SVMKernel'] - param_grid['SVMC'] = log_uniform(loc=config['SVMC'][0], - scale=config['SVMC'][1]) - param_grid['SVMdegree'] = scipy.stats.uniform(loc=config['SVMdegree'][0], - scale=config['SVMdegree'][1]) - param_grid['SVMcoef0'] = scipy.stats.uniform(loc=config['SVMcoef0'][0], - scale=config['SVMcoef0'][1]) - param_grid['SVMgamma'] = log_uniform(loc=config['SVMgamma'][0], - scale=config['SVMgamma'][1]) - - # RF parameters - # RF parameters - param_grid['RFn_estimators'] =\ - discrete_uniform(loc=config['RFn_estimators'][0], - scale=config['RFn_estimators'][1]) - param_grid['RFmin_samples_split'] =\ - discrete_uniform(loc=config['RFmin_samples_split'][0], - scale=config['RFmin_samples_split'][1]) - param_grid['RFmax_depth'] =\ - discrete_uniform(loc=config['RFmax_depth'][0], - scale=config['RFmax_depth'][1]) - - # Logistic Regression parameters - param_grid['LRpenalty'] = config['LRpenalty'] - param_grid['LRC'] = scipy.stats.uniform(loc=config['LRC'][0], - scale=config['LRC'][1]) - - # LDA/QDA parameters - param_grid['LDA_solver'] = config['LDA_solver'] - param_grid['LDA_shrinkage'] = log_uniform(loc=config['LDA_shrinkage'][0], - scale=config['LDA_shrinkage'][1]) - param_grid['QDA_reg_param'] = log_uniform(loc=config['QDA_reg_param'][0], - scale=config['QDA_reg_param'][1]) - - # ElasticNet parameters - param_grid['ElasticNet_alpha'] =\ - log_uniform(loc=config['ElasticNet_alpha'][0], - scale=config['ElasticNet_alpha'][1]) - param_grid['ElasticNet_l1_ratio'] =\ - scipy.stats.uniform(loc=config['ElasticNet_l1_ratio'][0], - scale=config['ElasticNet_l1_ratio'][1]) - - # SGD Regression parameters - param_grid['SGD_alpha'] =\ - log_uniform(loc=config['SGD_alpha'][0], - scale=config['SGD_alpha'][1]) - - param_grid['SGD_l1_ratio'] =\ - scipy.stats.uniform(loc=config['SGD_l1_ratio'][0], - scale=config['SGD_l1_ratio'][1]) - param_grid['SGD_loss'] = config['SGD_loss'] - param_grid['SGD_penalty'] = config['SGD_penalty'] - - # Naive Bayes parameters - param_grid['CNB_alpha'] =\ - scipy.stats.uniform(loc=config['CNB_alpha'][0], - scale=config['CNB_alpha'][1]) - - return param_grid
                        -
                        - -
                        - -
                        -
                        - - -
                        - -
                        -

                        - © Copyright 2016 -- 2019, Biomedical Imaging Group Rotterdam, Departments of Medical Informatics and Radiology, Erasmus MC, Rotterdam, The Netherlands - -

                        -
                        - Built with Sphinx using a theme provided by Read the Docs. - -
                        - -
                        -
                        - -
                        - -
                        - - - - - - - - - - - - \ No newline at end of file diff --git a/build/lib/WORC/doc/_build/html/_modules/WORC/classification/crossval.html b/build/lib/WORC/doc/_build/html/_modules/WORC/classification/crossval.html deleted file mode 100644 index d0efbfd2..00000000 --- a/build/lib/WORC/doc/_build/html/_modules/WORC/classification/crossval.html +++ /dev/null @@ -1,701 +0,0 @@ - - - - - - - - - - - WORC.classification.crossval — WORC 3.0.0 documentation - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
                        - - - -
                        - - - - - -
                        - -
                        - - - - - - - - - - - - - - - - - -
                        - -
                          - -
                        • Docs »
                        • - -
                        • Module code »
                        • - -
                        • WORC.classification.crossval
                        • - - -
                        • - -
                        • - -
                        - - -
                        -
                        -
                        -
                        - -

                        Source code for WORC.classification.crossval

                        -#!/usr/bin/env python
                        -
                        -# Copyright 2016-2019 Biomedical Imaging Group Rotterdam, Departments of
                        -# Medical Informatics and Radiology, Erasmus MC, Rotterdam, The Netherlands
                        -#
                        -# 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 numpy as np
                        -import pandas as pd
                        -import logging
                        -import os
                        -from sklearn.model_selection import train_test_split
                        -import xlrd
                        -from .parameter_optimization import random_search_parameters
                        -import WORC.addexceptions as ae
                        -
                        -
                        -
                        [docs]def crossval(config, label_data, image_features, - param_grid=None, use_fastr=False, - fastr_plugin=None, tempsave=False, - fixedsplits=None, ensemble={'Use': False}, outputfolder=None, - modus='singlelabel'): - """ - Constructs multiple individual classifiers based on the label settings - - Parameters - ---------- - config: dict, mandatory - Dictionary with config settings. See the Github Wiki for the - available fields and formatting. - - label_data: dict, mandatory - Should contain the following: - patient_IDs (list): IDs of the patients, used to keep track of test and - training sets, and label data - label (list): List of lists, where each list contains the - label status for that patient for each - label - label_name (list): Contains the different names that are stored - in the label object - - image_features: numpy array, mandatory - Consists of a tuple of two lists for each patient: - (feature_values, feature_labels) - - param_grid: dictionary, optional - Contains the parameters and their values wich are used in the - grid or randomized search hyperparamater optimization. See the - construct_classifier function for some examples. - - use_fastr: boolean, default False - If False, parallel execution through Joblib is used for fast - execution of the hyperparameter optimization. Especially suited - for execution on mutlicore (H)PC's. The settings used are - specified in the config.ini file in the IOparser folder, which you - can adjust to your system. - - If True, fastr is used to split the hyperparameter optimization in - separate jobs. Parameters for the splitting can be specified in the - config file. Especially suited for clusters. - - fastr_plugin: string, default None - Determines which plugin is used for fastr executions. - When None, uses the default plugin from the fastr config. - - tempsave: boolean, default False - If True, create a .hdf5 file after each cross validation containing - the classifier and results from that that split. This is written to - the GSOut folder in your fastr output mount. If False, only - the result of all combined cross validations will be saved to a .hdf5 - file. This will also be done if set to True. - - fixedsplits: string, optional - By default, random split cross validation is used to train and - evaluate the machine learning methods. Optionally, you can provide - a .xlsx file containing fixed splits to be used. See the Github Wiki - for the format. - - ensemble: dictionary, optional - Contains the configuration for constructing an ensemble. - - modus: string, default 'singlelabel' - Determine whether one-vs-all classification (or regression) for - each single label is used ('singlelabel') or if multilabel - classification is performed ('multilabel'). - - Returns - ---------- - panda_data: pandas dataframe - Contains all information on the trained classifier. - - """ - if tempsave: - import fastr - - - # Define all possible regressors - regressors = ['SVR', 'RFR', 'SGDR', 'Lasso', 'ElasticNet'] - - # Process input data - patient_IDs = label_data['patient_IDs'] - label_value = label_data['label'] - label_name = label_data['label_name'] - - if outputfolder is None: - logfilename = os.path.join(os.getcwd(), 'classifier.log') - else: - logfilename = os.path.join(outputfolder, 'classifier.log') - print("Logging to file " + str(logfilename)) - - for handler in logging.root.handlers[:]: - logging.root.removeHandler(handler) - - logging.basicConfig(filename=logfilename, level=logging.DEBUG) - N_iterations = config['CrossValidation']['N_iterations'] - test_size = config['CrossValidation']['test_size'] - - classifier_labelss = dict() - logging.debug('Starting classifier') - - # We only need one label instance, assuming they are all the sample - feature_labels = image_features[0][1] - - # Check if we need to use fixedsplits: - if fixedsplits is not None and '.xlsx' in fixedsplits: - # fixedsplits = '/home/mstarmans/Settings/RandomSufflingOfData.xlsx' - wb = xlrd.open_workbook(fixedsplits) - wb = wb.sheet_by_index(1) - - if modus == 'singlelabel': - print('Performing Single class classification.') - logging.debug('Performing Single class classification.') - elif modus == 'multilabel': - print('Performing Multi label classification.') - logging.debug('Performing Multi class classification.') - label_value = [label_value] - label_name = [label_name] - else: - m = ('{} is not a valid modus!').format(modus) - logging.debug(m) - raise ae.WORCKeyError(m) - - for i_class, i_name in zip(label_value, label_name): - if modus == 'singlelabel': - i_class_temp = i_class.ravel() - - save_data = list() - - for i in range(0, N_iterations): - print(('Cross validation iteration {} / {} .').format(str(i + 1), str(N_iterations))) - logging.debug(('Cross validation iteration {} / {} .').format(str(i + 1), str(N_iterations))) - random_seed = np.random.randint(5000) - - # Split into test and training set, where the percentage of each - # label is maintained - if any(clf in regressors for clf in param_grid['classifiers']): - # We cannot do a stratified shuffle split with regression - stratify = None - else: - if modus == 'singlelabel': - stratify = i_class_temp - elif modus == 'multilabel': - # Create a stratification object from the labels - # Label = 0 means no label equals one - # Other label numbers refer to the label name that is 1 - stratify = list() - for pnum in range(0, len(i_class[0])): - plabel = 0 - for lnum, slabel in enumerate(i_class): - if slabel[pnum] == 1: - plabel = lnum + 1 - stratify.append(plabel) - - # Sklearn multiclass requires rows to be objects/patients - # i_class = i_class.reshape(i_class.shape[1], i_class.shape[0]) - i_class_temp = np.zeros((i_class.shape[1], i_class.shape[0])) - for n_patient in range(0, i_class.shape[1]): - for n_label in range(0, i_class.shape[0]): - i_class_temp[n_patient, n_label] = i_class[n_label, n_patient] - i_class_temp = i_class_temp - else: - raise ae.WORCKeyError('{} is not a valid modus!').format(modus) - - if fixedsplits is None: - # Use Random Split. Split per patient, not per sample - unique_patient_IDs, unique_indices =\ - np.unique(np.asarray(patient_IDs), return_index=True) - if any(clf in regressors for clf in param_grid['classifiers']): - unique_stratify = None - else: - unique_stratify = [stratify[i] for i in unique_indices] - - try: - unique_PID_train, indices_PID_test\ - = train_test_split(unique_patient_IDs, - test_size=test_size, - random_state=random_seed, - stratify=unique_stratify) - except ValueError as e: - e = str(e) + ' Increase the size of your validation set.' - raise ae.WORCValueError(e) - - # Check for all IDs if they are in test or training - indices_train = list() - indices_test = list() - patient_ID_train = list() - patient_ID_test = list() - for num, pid in enumerate(patient_IDs): - if pid in unique_PID_train: - indices_train.append(num) - - # Make sure we get a unique ID - if pid in patient_ID_train: - n = 1 - while str(pid + '_' + str(n)) in patient_ID_train: - n += 1 - pid = str(pid + '_' + str(n)) - patient_ID_train.append(pid) - else: - indices_test.append(num) - - # Make sure we get a unique ID - if pid in patient_ID_test: - n = 1 - while str(pid + '_' + str(n)) in patient_ID_test: - n += 1 - pid = str(pid + '_' + str(n)) - patient_ID_test.append(pid) - - # Split features and labels accordingly - X_train = [image_features[i] for i in indices_train] - X_test = [image_features[i] for i in indices_test] - if modus == 'singlelabel': - Y_train = i_class_temp[indices_train] - Y_test = i_class_temp[indices_test] - elif modus == 'multilabel': - Y_train = i_class_temp[indices_train, :] - Y_test = i_class_temp[indices_test, :] - else: - raise ae.WORCKeyError('{} is not a valid modus!').format(modus) - - else: - # Use pre defined splits - indices = wb.col_values(i) - indices = [int(j) for j in indices[1:]] # First element is "Iteration x" - train = indices[0:121] - test = indices[121:] - - # Convert the numbers to the correct indices - ind_train = list() - for j in train: - success = False - for num, p in enumerate(patient_IDs): - if str(j).zfill(3) == p[0:3]: - ind_train.append(num) - success = True - if not success: - raise ae.WORCIOError("Patient " + str(j).zfill(3) + " is not included!") - - ind_test = list() - for j in test: - success = False - for num, p in enumerate(patient_IDs): - if str(j).zfill(3) == p[0:3]: - ind_test.append(num) - success = True - if not success: - raise ae.WORCIOError("Patient " + str(j).zfill(3) + " is not included!") - - X_train = np.asarray(image_features)[ind_train].tolist() - Y_train = np.asarray(i_class_temp)[ind_train].tolist() - patient_ID_train = patient_IDs[ind_train] - X_test = np.asarray(image_features)[ind_test].tolist() - Y_test = np.asarray(i_class_temp)[ind_test].tolist() - patient_ID_test = patient_IDs[ind_test] - - # Find best hyperparameters and construct classifier - config['HyperOptimization']['use_fastr'] = use_fastr - config['HyperOptimization']['fastr_plugin'] = fastr_plugin - n_cores = config['General']['Joblib_ncores'] - trained_classifier = random_search_parameters(features=X_train, - labels=Y_train, - param_grid=param_grid, - n_cores=n_cores, - **config['HyperOptimization']) - - # Create an ensemble if required - if ensemble['Use']: - trained_classifier.create_ensemble(X_train, Y_train) - - # We only want to save the feature values and one label array - X_train = [x[0] for x in X_train] - X_test = [x[0] for x in X_test] - - temp_save_data = (trained_classifier, X_train, X_test, Y_train, - Y_test, patient_ID_train, patient_ID_test, random_seed) - - save_data.append(temp_save_data) - - # Create a temporary save - if tempsave: - panda_labels = ['trained_classifier', 'X_train', 'X_test', 'Y_train', 'Y_test', - 'config', 'patient_ID_train', 'patient_ID_test', - 'random_seed'] - - panda_data_temp =\ - pd.Series([trained_classifier, X_train, X_test, Y_train, - Y_test, config, patient_ID_train, - patient_ID_test, random_seed], - index=panda_labels, - name='Constructed crossvalidation') - - panda_data = pd.DataFrame(panda_data_temp) - n = 0 - filename = os.path.join(fastr.config.mounts['tmp'], 'GSout', 'RS_' + str(i) + '.hdf5') - while os.path.exists(filename): - n += 1 - filename = os.path.join(fastr.config.mounts['tmp'], 'GSout', 'RS_' + str(i + n) + '.hdf5') - - if not os.path.exists(os.path.dirname(filename)): - os.makedirs(os.path.dirname(filename)) - - panda_data.to_hdf(filename, 'SVMdata') - del panda_data, panda_data_temp - - [classifiers, X_train_set, X_test_set, Y_train_set, Y_test_set, - patient_ID_train_set, patient_ID_test_set, seed_set] =\ - zip(*save_data) - - panda_labels = ['classifiers', 'X_train', 'X_test', 'Y_train', 'Y_test', - 'config', 'patient_ID_train', 'patient_ID_test', - 'random_seed', 'feature_labels'] - - panda_data_temp =\ - pd.Series([classifiers, X_train_set, X_test_set, Y_train_set, - Y_test_set, config, patient_ID_train_set, - patient_ID_test_set, seed_set, feature_labels], - index=panda_labels, - name='Constructed crossvalidation') - - if modus == 'singlelabel': - i_name = ''.join(i_name) - elif modus == 'multilabel': - i_name = ','.join(i_name) - - classifier_labelss[i_name] = panda_data_temp - - panda_data = pd.DataFrame(classifier_labelss) - - return panda_data
                        - - -
                        [docs]def nocrossval(config, label_data_train, label_data_test, image_features_train, - image_features_test, param_grid=None, use_fastr=False, - fastr_plugin=None, ensemble={'Use': False}, - modus='singlelabel'): - """ - Constructs multiple individual classifiers based on the label settings - - Arguments: - config (Dict): Dictionary with config settings - label_data (Dict): should contain: - patient_IDs (list): IDs of the patients, used to keep track of test and - training sets, and label data - label (list): List of lists, where each list contains the - label status for that patient for each - label - label_name (list): Contains the different names that are stored - in the label object - image_features (numpy array): Consists of a tuple of two lists for each patient: - (feature_values, feature_labels) - - ensemble: dictionary, optional - Contains the configuration for constructing an ensemble. - - modus: string, default 'singlelabel' - Determine whether one-vs-all classification (or regression) for - each single label is used ('singlelabel') or if multilabel - classification is performed ('multilabel'). - - Returns: - classifier_data (pandas dataframe) - """ - - patient_IDs_train = label_data_train['patient_IDs'] - label_value_train = label_data_train['label'] - label_name_train = label_data_train['label_name'] - - patient_IDs_test = label_data_test['patient_IDs'] - if 'label' in label_data_test.keys(): - label_value_test = label_data_test['label'] - else: - label_value_test = [None] * len(patient_IDs_test) - - logfilename = os.path.join(os.getcwd(), 'classifier.log') - logging.basicConfig(filename=logfilename, level=logging.DEBUG) - - classifier_labelss = dict() - - print('features') - logging.debug('Starting classifier') - print(len(image_features_train)) - - # Determine modus - if modus == 'singlelabel': - print('Performing Single class classification.') - logging.debug('Performing Single class classification.') - elif modus == 'multilabel': - print('Performing Multi label classification.') - logging.debug('Performing Multi class classification.') - label_name_train = [label_name_train] - else: - m = ('{} is not a valid modus!').format(modus) - logging.debug(m) - raise ae.WORCKeyError(m) - - # We only need one label instance, assuming they are all the sample - feature_labels = image_features_train[0][1] - for i_name in label_name_train: - - save_data = list() - - random_seed = np.random.randint(5000) - - # Split into test and training set, where the percentage of each - # label is maintained - X_train = image_features_train - X_test = image_features_test - if modus == 'singlelabel': - Y_train = label_value_train.ravel() - Y_test = label_value_test.ravel() - else: - # Sklearn multiclass requires rows to be objects/patients - Y_train = label_value_train - Y_train_temp = np.zeros((Y_train.shape[1], Y_train.shape[0])) - for n_patient in range(0, Y_train.shape[1]): - for n_label in range(0, Y_train.shape[0]): - Y_train_temp[n_patient, n_label] = Y_train[n_label, n_patient] - Y_train = Y_train_temp - - Y_test = label_value_test - Y_test_temp = np.zeros((Y_test.shape[1], Y_test.shape[0])) - for n_patient in range(0, Y_test.shape[1]): - for n_label in range(0, Y_test.shape[0]): - Y_test_temp[n_patient, n_label] = Y_test[n_label, n_patient] - Y_test = Y_test_temp - - # Find best hyperparameters and construct classifier - config['HyperOptimization']['use_fastr'] = use_fastr - config['HyperOptimization']['fastr_plugin'] = fastr_plugin - n_cores = config['General']['Joblib_ncores'] - trained_classifier = random_search_parameters(features=X_train, - labels=Y_train, - param_grid=param_grid, - n_cores=n_cores, - **config['HyperOptimization']) - - # Create an ensemble if required - if ensemble['Use']: - trained_classifier.create_ensemble(X_train, Y_train) - - # Extract the feature values - X_train = np.asarray([x[0] for x in X_train]) - X_test = np.asarray([x[0] for x in X_test]) - - temp_save_data = (trained_classifier, X_train, X_test, Y_train, - Y_test, patient_IDs_train, patient_IDs_test, random_seed) - - save_data.append(temp_save_data) - - [classifiers, X_train_set, X_test_set, Y_train_set, Y_test_set, - patient_ID_train_set, patient_ID_test_set, seed_set] =\ - zip(*save_data) - - panda_labels = ['classifiers', 'X_train', 'X_test', 'Y_train', 'Y_test', - 'config', 'patient_ID_train', 'patient_ID_test', - 'random_seed', 'feature_labels'] - - panda_data_temp =\ - pd.Series([classifiers, X_train_set, X_test_set, Y_train_set, - Y_test_set, config, patient_ID_train_set, - patient_ID_test_set, seed_set, feature_labels], - index=panda_labels, - name='Constructed crossvalidation') - - i_name = ''.join(i_name) - classifier_labelss[i_name] = panda_data_temp - - panda_data = pd.DataFrame(classifier_labelss) - - return panda_data
                        -
                        - -
                        - -
                        -
                        - - -
                        - -
                        -

                        - © Copyright 2016 -- 2019, Biomedical Imaging Group Rotterdam, Departments of Medical Informatics and Radiology, Erasmus MC, Rotterdam, The Netherlands - -

                        -
                        - Built with Sphinx using a theme provided by Read the Docs. - -
                        - -
                        -
                        - -
                        - -
                        - - - - - - - - - - - - \ No newline at end of file diff --git a/build/lib/WORC/doc/_build/html/_modules/WORC/classification/estimators.html b/build/lib/WORC/doc/_build/html/_modules/WORC/classification/estimators.html deleted file mode 100644 index 61bd77aa..00000000 --- a/build/lib/WORC/doc/_build/html/_modules/WORC/classification/estimators.html +++ /dev/null @@ -1,351 +0,0 @@ - - - - - - - - - - - WORC.classification.estimators — WORC 3.0.0 documentation - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
                        - - - -
                        - - - - - -
                        - -
                        - - - - - - - - - - - - - - - - - -
                        - -
                          - -
                        • Docs »
                        • - -
                        • Module code »
                        • - -
                        • WORC.classification.estimators
                        • - - -
                        • - -
                        • - -
                        - - -
                        -
                        -
                        -
                        - -

                        Source code for WORC.classification.estimators

                        -#!/usr/bin/env python
                        -
                        -# Copyright 2016-2019 Biomedical Imaging Group Rotterdam, Departments of
                        -# Medical Informatics and Radiology, Erasmus MC, Rotterdam, The Netherlands
                        -#
                        -# 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 numpy as np
                        -from sklearn.base import BaseEstimator, ClassifierMixin
                        -from sklearn.utils.validation import check_is_fitted
                        -from sklearn.utils.multiclass import unique_labels
                        -import WORC.classification.RankedSVM as RSVM
                        -
                        -
                        -
                        [docs]class RankedSVM(BaseEstimator, ClassifierMixin): - """ An example classifier which implements a 1-NN algorithm. - - Parameters - ---------- - demo_param : str, optional - A parameter used for demonstation of how to pass and store paramters. - - Attributes - ---------- - X_ : array, shape = [n_samples, n_features] - The input passed during :meth:`fit` - y_ : array, shape = [n_samples] - The labels passed during :meth:`fit` - """ -
                        [docs] def __init__(self, cost=1, lambda_tol=1e-6, - norm_tol=1e-4, max_iter=500, svm='Poly', gamma=0.05, - coefficient=0.05, degree=3): - self.cost = cost - self.lambda_tol = lambda_tol - self.norm_tol = norm_tol - self.max_iter = max_iter - self.svm = svm - self.gamma = gamma - self.coefficient = coefficient - self.degree = 3
                        - -
                        [docs] def fit(self, X, y): - """A reference implementation of a fitting function for a classifier. - - Parameters - ---------- - X : array-like, shape = [n_samples, n_features] - The training input samples. - y : array-like, shape = [n_samples] - The target values. An array of int. - - Returns - ------- - self : object - Returns self. - """ - - # Store the classes seen during fit - self.classes_ = unique_labels(y) - - # RankedSVM requires a very specific format of y - # Each row should represent a label, consisiting of ones and minus ones - y = np.transpose(y).astype(np.int16) - y[y == 0] = -1 - self.X_ = X - self.y_ = y - self.num_class = y.shape[0] - - Weights, Bias, SVs =\ - RSVM.RankSVM_train(train_data=X, - train_target=y, - cost=self.cost, - lambda_tol=self.lambda_tol, - norm_tol=self.norm_tol, - max_iter=self.max_iter, - svm=self.svm, gamma=self.gamma, - coefficient=self.coefficient, - degree=self.degree) - - self.Weights = Weights - self.Bias = Bias - self.SVs = SVs - - return self
                        - -
                        [docs] def predict(self, X, y=None): - """ A reference implementation of a prediction for a classifier. - - Parameters - ---------- - X : array-like of shape = [n_samples, n_features] - The input samples. - - Returns - ------- - y : array of int of shape = [n_samples] - The label for each sample is the label of the closest sample - seen udring fit. - """ - # Check is fit had been called - check_is_fitted(self, ['X_', 'y_']) - - _, Predicted_Labels =\ - RSVM.RankSVM_test(test_data=X, - num_class=self.num_class, - Weights=self.Weights, - Bias=self.Bias, - SVs=self.SVs, - svm=self.svm, gamma=self.gamma, - coefficient=self.coefficient, - degree=self.degree) - - return Predicted_Labels
                        - -
                        [docs] def predict_proba(self, X, y): - """ A reference implementation of a prediction for a classifier. - - Parameters - ---------- - X : array-like of shape = [n_samples, n_features] - The input samples. - - Returns - ------- - y : array of int of shape = [n_samples] - The label for each sample is the label of the closest sample - seen udring fit. - """ - # Check is fit had been called - check_is_fitted(self, ['X_', 'y_']) - - Probs, _ =\ - RSVM.RankSVM_test(test_data=X, - num_class=self.num_class, - Weights=self.Weights, - Bias=self.Bias, - svm=self.svm, gamma=self.gamma, - coefficient=self.coefficient, - degree=self.degree) - - return Probs
                        -
                        - -
                        - -
                        -
                        - - -
                        - -
                        -

                        - © Copyright 2016 -- 2019, Biomedical Imaging Group Rotterdam, Departments of Medical Informatics and Radiology, Erasmus MC, Rotterdam, The Netherlands - -

                        -
                        - Built with Sphinx using a theme provided by Read the Docs. - -
                        - -
                        -
                        - -
                        - -
                        - - - - - - - - - - - - \ No newline at end of file diff --git a/build/lib/WORC/doc/_build/html/_modules/WORC/classification/fitandscore.html b/build/lib/WORC/doc/_build/html/_modules/WORC/classification/fitandscore.html deleted file mode 100644 index d1e42047..00000000 --- a/build/lib/WORC/doc/_build/html/_modules/WORC/classification/fitandscore.html +++ /dev/null @@ -1,982 +0,0 @@ - - - - - - - - - - - WORC.classification.fitandscore — WORC 3.0.0 documentation - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
                        - - - -
                        - - - - - -
                        - -
                        - - - - - - - - - - - - - - - - - -
                        - -
                          - -
                        • Docs »
                        • - -
                        • Module code »
                        • - -
                        • WORC.classification.fitandscore
                        • - - -
                        • - -
                        • - -
                        - - -
                        -
                        -
                        -
                        - -

                        Source code for WORC.classification.fitandscore

                        -#!/usr/bin/env python
                        -
                        -# Copyright 2016-2019 Biomedical Imaging Group Rotterdam, Departments of
                        -# Medical Informatics and Radiology, Erasmus MC, Rotterdam, The Netherlands
                        -#
                        -# 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.
                        -
                        -from sklearn.preprocessing import StandardScaler
                        -from sklearn.preprocessing import MinMaxScaler
                        -from sklearn.model_selection._validation import _fit_and_score
                        -import numpy as np
                        -from sklearn.linear_model import Lasso
                        -from sklearn.feature_selection import SelectFromModel
                        -import scipy
                        -from sklearn.decomposition import PCA
                        -from sklearn.multiclass import OneVsRestClassifier
                        -from imblearn.over_sampling import SMOTE, RandomOverSampler
                        -from sklearn.utils import check_random_state
                        -import random
                        -from sklearn.metrics import make_scorer, average_precision_score
                        -from WORC.classification.estimators import RankedSVM
                        -from WORC.classification import construct_classifier as cc
                        -from WORC.classification.metrics import check_scoring
                        -from WORC.featureprocessing.Relief import SelectMulticlassRelief
                        -from WORC.featureprocessing.Imputer import Imputer
                        -from WORC.featureprocessing.VarianceThreshold import selfeat_variance
                        -from WORC.featureprocessing.StatisticalTestThreshold import StatisticalTestThreshold
                        -from WORC.featureprocessing.SelectGroups import SelectGroups
                        -
                        -
                        -
                        [docs]def fit_and_score(X, y, scoring, - train, test, para, - fit_params=None, - return_train_score=True, - return_n_test_samples=True, - return_times=True, return_parameters=True, - error_score='raise', verbose=True, - return_all=True): - ''' - Fit an estimator to a dataset and score the performance. The following - methods can currently be applied as preprocessing before fitting, in - this order: - 1. Select features based on feature type group (e.g. shape, histogram). - 2. Oversampling - 3. Apply feature imputation (WIP). - 4. Apply feature selection based on variance of feature among patients. - 5. Univariate statistical testing (e.g. t-test, Wilcoxon). - 6. Scale features with e.g. z-scoring. - 7. Use Relief feature selection. - 8. Select features based on a fit with a LASSO model. - 9. Select features using PCA. - 10. If a SingleLabel classifier is used for a MultiLabel problem, - a OneVsRestClassifier is employed around it. - - All of the steps are optional. - - Parameters - ---------- - estimator: sklearn estimator, mandatory - Unfitted estimator which will be fit. - - X: array, mandatory - Array containingfor each object (rows) the feature values - (1st Column) and the associated feature label (2nd Column). - - y: list(?), mandatory - List containing the labels of the objects. - - scorer: sklearn scorer, mandatory - Function used as optimization criterion for the hyperparamater optimization. - - train: list, mandatory - Indices of the objects to be used as training set. - - test: list, mandatory - Indices of the objects to be used as testing set. - - para: dictionary, mandatory - Contains the settings used for the above preprocessing functions - and the fitting. TODO: Create a default object and show the - fields. - - fit_params:dictionary, default None - Parameters supplied to the estimator for fitting. See the SKlearn - site for the parameters of the estimators. - - return_train_score: boolean, default True - Save the training score to the final SearchCV object. - - return_n_test_samples: boolean, default True - Save the number of times each sample was used in the test set - to the final SearchCV object. - - return_times: boolean, default True - Save the time spend for each fit to the final SearchCV object. - - return_parameters: boolean, default True - Return the parameters used in the final fit to the final SearchCV - object. - - error_score: numeric or "raise" by default - Value to assign to the score if an error occurs in estimator - fitting. If set to "raise", the error is raised. If a numeric - value is given, FitFailedWarning is raised. This parameter - does not affect the refit step, which will always raise the error. - - verbose: boolean, default=True - If True, print intermediate progress to command line. Warnings are - always printed. - - return_all: boolean, default=True - If False, only the ret object containing the performance will be - returned. If True, the ret object plus all fitted objects will be - returned. - - Returns - ---------- - Depending on the return_all input parameter, either only ret or all objects - below are returned. - - ret: list - Contains optionally the train_scores and the test_scores, - test_sample_counts, fit_time, score_time, parameters_est - and parameters_all. - - GroupSel: WORC GroupSel Object - Either None if the groupwise feature selection is not used, or - the fitted object. - - VarSel: WORC VarSel Object - Either None if the variance threshold feature selection is not used, or - the fitted object. - - SelectModel: WORC SelectModel Object - Either None if the feature selection based on a fittd model is not - used, or the fitted object. - - feature_labels: list - Labels of the features. Only one list is returned, not one per - feature object, as we assume all samples have the same feature names. - - scaler: scaler object - Either None if feature scaling is not used, or - the fitted object. - - imputer: WORC Imputater Object - Either None if feature imputation is not used, or - the fitted object. - - pca: WORC PCA Object - Either None if PCA based feature selection is not used, or - the fitted object. - - StatisticalSel: WORC StatisticalSel Object - Either None if the statistical test feature selection is not used, or - the fitted object. - - ReliefSel: WORC ReliefSel Object - Either None if the RELIEF feature selection is not used, or - the fitted object. - - sm: WORC SMOTE Object - Either None if the SMOTE oversampling is not used, or - the fitted object. - - ros: WORC ROS Object - Either None if Random Oversampling is not used, or - the fitted object. - - ''' - # We copy the parameter object so we can alter it and keep the original - para_estimator = para.copy() - estimator = cc.construct_classifier(para_estimator) - if scoring != 'average_precision_weighted': - scorer = check_scoring(estimator, scoring=scoring) - else: - scorer = make_scorer(average_precision_score, average='weighted') - - para_estimator = delete_cc_para(para_estimator) - - # X is a tuple: split in two arrays - feature_values = np.asarray([x[0] for x in X]) - feature_labels = np.asarray([x[1] for x in X]) - - # ------------------------------------------------------------------------ - # Feature imputation - if 'Imputation' in para_estimator.keys(): - if para_estimator['Imputation'] == 'True': - imp_type = para_estimator['ImputationMethod'] - if verbose: - message = ('Imputing NaN with {}.').format(imp_type) - print(message) - imp_nn = para_estimator['ImputationNeighbours'] - - imputer = Imputer(missing_values=np.nan, strategy=imp_type, - n_neighbors=imp_nn) - imputer.fit(feature_values) - feature_values = imputer.transform(feature_values) - else: - imputer = None - else: - imputer = None - - if 'Imputation' in para_estimator.keys(): - del para_estimator['Imputation'] - del para_estimator['ImputationMethod'] - del para_estimator['ImputationNeighbours'] - - # Delete the object if we do not need to return it - if not return_all: - del imputer - - # ------------------------------------------------------------------------ - # Use SMOTE oversampling - if 'SampleProcessing_SMOTE' in para_estimator.keys(): - if para_estimator['SampleProcessing_SMOTE'] == 'True': - - # Determine our starting balance - pos_initial = int(np.sum(y)) - neg_initial = int(len(y) - pos_initial) - len_in = len(y) - - # Fit SMOTE object and transform dataset - # NOTE: need to save random state for this one as well! - sm = SMOTE(random_state=None, - ratio=para_estimator['SampleProcessing_SMOTE_ratio'], - m_neighbors=para_estimator['SampleProcessing_SMOTE_neighbors'], - kind='borderline1', - n_jobs=para_estimator['SampleProcessing_SMOTE_n_cores']) - - feature_values, y = sm.fit_sample(feature_values, y) - - # Also make sure our feature label object has the same size - # NOTE: Not sure if this is the best implementation - feature_labels = np.asarray([feature_labels[0] for x in X]) - - # Note the user what SMOTE did - pos = int(np.sum(y)) - neg = int(len(y) - pos) - if verbose: - message = ("Sampling with SMOTE from {} ({} pos, {} neg) to {} ({} pos, {} neg) patients.").format(str(len_in), - str(pos_initial), - str(neg_initial), - str(len(y)), - str(pos), - str(neg)) - print(message) - else: - sm = None - - if 'SampleProcessing_SMOTE' in para_estimator.keys(): - del para_estimator['SampleProcessing_SMOTE'] - del para_estimator['SampleProcessing_SMOTE_ratio'] - del para_estimator['SampleProcessing_SMOTE_neighbors'] - del para_estimator['SampleProcessing_SMOTE_n_cores'] - - # Delete the object if we do not need to return it - if not return_all: - del sm - - # ------------------------------------------------------------------------ - # Full Oversampling: To Do - if 'SampleProcessing_Oversampling' in para_estimator.keys(): - if para_estimator['SampleProcessing_Oversampling'] == 'True': - if verbose: - print('Oversample underrepresented classes in training.') - - # Oversample underrepresented classes in training - # We always use a factor 1, e.g. all classes end up with an - # equal number of samples - if len(y.shape) == 1: - # Single Class, use imblearn oversampling - - # Create another random state - # NOTE: Also need to save this random seed. Can be same as SMOTE - random_seed2 = np.random.randint(5000) - random_state2 = check_random_state(random_seed2) - - ros = RandomOverSampler(random_state=random_state2) - feature_values, y = ros.fit_sample(feature_values, y) - - else: - # Multi class, use own method as imblearn cannot do this - sumclass = [np.sum(y[:, i]) for i in range(y.shape[1])] - maxclass = np.argmax(sumclass) - for i in range(y.shape[1]): - if i != maxclass: - # Oversample - nz = np.nonzero(y[:, i])[0] - noversample = sumclass[maxclass] - sumclass[i] - while noversample > 0: - n_sample = random.randint(0, len(nz) - 1) - n_sample = nz[n_sample] - i_sample = y[n_sample, :] - x_sample = feature_values[n_sample] - y = np.vstack((y, i_sample)) - feature_values.append(x_sample) - noversample -= 1 - else: - ros = None - - if 'SampleProcessing_Oversampling' in para_estimator.keys(): - del para_estimator['SampleProcessing_Oversampling'] - - # Delete the object if we do not need to return it - if not return_all: - del ros - - # ------------------------------------------------------------------------ - # Groupwise feature selection - if 'SelectGroups' in para_estimator: - if verbose: - print("Selecting groups of features.") - del para_estimator['SelectGroups'] - # TODO: more elegant way to solve this - feature_groups = ["histogram_features", "orientation_features", - "patient_features", "semantic_features", - "shape_features", - "coliage_features", 'vessel_features', - "phase_features", "log_features", - "texture_gabor_features", "texture_glcm_features", - "texture_glcmms_features", "texture_glrlm_features", - "texture_glszm_features", "texture_ngtdm_features", - "texture_lbp_features"] - - # Backwards compatability - if 'texture_features' in para_estimator.keys(): - feature_groups.append('texture_features') - - # Check per feature group if the parameter is present - parameters_featsel = dict() - for group in feature_groups: - if group not in para_estimator: - # Default: do use the group, except for texture features - if group == 'texture_features': - value = 'False' - else: - value = 'True' - else: - value = para_estimator[group] - del para_estimator[group] - - parameters_featsel[group] = value - - GroupSel = SelectGroups(parameters=parameters_featsel) - GroupSel.fit(feature_labels[0]) - if verbose: - print("Original Length: " + str(len(feature_values[0]))) - feature_values = GroupSel.transform(feature_values) - if verbose: - print("New Length: " + str(len(feature_values[0]))) - feature_labels = GroupSel.transform(feature_labels) - else: - GroupSel = None - - # Delete the object if we do not need to return it - if not return_all: - del GroupSel - - # Check whether there are any features left - if len(feature_values[0]) == 0: - # TODO: Make a specific WORC exception for this warning. - if verbose: - print('[WARNING]: No features are selected! Probably all feature groups were set to False. Parameters:') - print(para) - - # Return a zero performance dummy - VarSel = None - scaler = None - SelectModel = None - pca = None - StatisticalSel = None - ReliefSel = None - - # Delete the non-used fields - para_estimator = delete_nonestimator_parameters(para_estimator) - - ret = [0, 0, 0, 0, 0, para_estimator, para] - if return_all: - return ret, GroupSel, VarSel, SelectModel, feature_labels[0], scaler, imputer, pca, StatisticalSel, ReliefSel, sm, ros - else: - return ret - - # ------------------------------------------------------------------------ - # FIXME: When only using LBP feature, X is 3 dimensional with 3rd dimension length 1 - if len(feature_values.shape) == 3: - feature_values = np.reshape(feature_values, (feature_values.shape[0], feature_values.shape[1])) - if len(feature_labels.shape) == 3: - feature_labels = np.reshape(feature_labels, (feature_labels.shape[0], feature_labels.shape[1])) - - # Remove any NaN feature values if these are still left after imputation - feature_values = replacenan(feature_values, verbose=verbose, feature_labels=feature_labels[0]) - - # -------------------------------------------------------------------- - # Feature selection based on variance - if para_estimator['Featsel_Variance'] == 'True': - if verbose: - print("Selecting features based on variance.") - if verbose: - print("Original Length: " + str(len(feature_values[0]))) - try: - feature_values, feature_labels, VarSel =\ - selfeat_variance(feature_values, feature_labels) - except ValueError: - if verbose: - print('[WARNING]: No features meet the selected Variance threshold! Skipping selection.') - VarSel = None - if verbose: - print("New Length: " + str(len(feature_values[0]))) - else: - VarSel = None - del para_estimator['Featsel_Variance'] - - # Delete the object if we do not need to return it - if not return_all: - del VarSel - - # Check whether there are any features left - if len(feature_values[0]) == 0: - # TODO: Make a specific WORC exception for this warning. - if verbose: - print('[WARNING]: No features are selected! Probably you selected a feature group that is not in your feature file. Parameters:') - print(para) - para_estimator = delete_nonestimator_parameters(para_estimator) - - # Return a zero performance dummy - scaler = None - SelectModel = None - pca = None - StatisticalSel = None - ret = [0, 0, 0, 0, 0, para_estimator, para] - if return_all: - return ret, GroupSel, VarSel, SelectModel, feature_labels[0], scaler, imputer, pca, StatisticalSel, ReliefSel, sm, ros - else: - return ret - - # -------------------------------------------------------------------- - # Feature selection based on a statistical test - if 'StatisticalTestUse' in para_estimator.keys(): - if para_estimator['StatisticalTestUse'] == 'True': - metric = para_estimator['StatisticalTestMetric'] - threshold = para_estimator['StatisticalTestThreshold'] - if verbose: - print("Selecting features based on statistical test. Method {}, threshold {}.").format(metric, str(round(threshold, 2))) - if verbose: - print("Original Length: " + str(len(feature_values[0]))) - - StatisticalSel = StatisticalTestThreshold(metric=metric, - threshold=threshold) - - StatisticalSel.fit(feature_values, y) - feature_values = StatisticalSel.transform(feature_values) - feature_labels = StatisticalSel.transform(feature_labels) - if verbose: - print("New Length: " + str(len(feature_values[0]))) - else: - StatisticalSel = None - del para_estimator['StatisticalTestUse'] - del para_estimator['StatisticalTestMetric'] - del para_estimator['StatisticalTestThreshold'] - else: - StatisticalSel = None - - # Delete the object if we do not need to return it - if not return_all: - del StatisticalSel - - # Check whether there are any features left - if len(feature_values[0]) == 0: - # TODO: Make a specific WORC exception for this warning. - if verbose: - print('[WARNING]: No features are selected! Probably you selected a feature group that is not in your feature file. Parameters:') - print(para) - - para_estimator = delete_nonestimator_parameters(para_estimator) - - # Return a zero performance dummy - scaler = None - SelectModel = None - pca = None - ret = [0, 0, 0, 0, 0, para_estimator, para] - if return_all: - return ret, GroupSel, VarSel, SelectModel, feature_labels[0], scaler, imputer, pca, StatisticalSel, ReliefSel, sm, ros - else: - return ret - - # ------------------------------------------------------------------------ - # Feature scaling - if 'FeatureScaling' in para_estimator: - if verbose: - print("Fitting scaler and transforming features.") - - if para_estimator['FeatureScaling'] == 'z_score': - scaler = StandardScaler().fit(feature_values) - elif para_estimator['FeatureScaling'] == 'minmax': - scaler = MinMaxScaler().fit(feature_values) - else: - scaler = None - - if scaler is not None: - feature_values = scaler.transform(feature_values) - del para_estimator['FeatureScaling'] - else: - scaler = None - - # Delete the object if we do not need to return it - if not return_all: - del scaler - - # -------------------------------------------------------------------- - # Relief feature selection, possibly multi classself. - # Needs to be done after scaling! - # para_estimator['ReliefUse'] = 'True' - if 'ReliefUse' in para_estimator.keys(): - if para_estimator['ReliefUse'] == 'True': - if verbose: - print("Selecting features using relief.") - - # Get parameters from para_estimator - n_neighbours = para_estimator['ReliefNN'] - sample_size = para_estimator['ReliefSampleSize'] - distance_p = para_estimator['ReliefDistanceP'] - numf = para_estimator['ReliefNumFeatures'] - - ReliefSel = SelectMulticlassRelief(n_neighbours=n_neighbours, - sample_size=sample_size, - distance_p=distance_p, - numf=numf) - ReliefSel.fit(feature_values, y) - if verbose: - print("Original Length: " + str(len(feature_values[0]))) - feature_values = ReliefSel.transform(feature_values) - if verbose: - print("New Length: " + str(len(feature_values[0]))) - feature_labels = ReliefSel.transform(feature_labels) - else: - ReliefSel = None - else: - ReliefSel = None - - # Delete the object if we do not need to return it - if not return_all: - del ReliefSel - - if 'ReliefUse' in para_estimator.keys(): - del para_estimator['ReliefUse'] - del para_estimator['ReliefNN'] - del para_estimator['ReliefSampleSize'] - del para_estimator['ReliefDistanceP'] - del para_estimator['ReliefNumFeatures'] - - # ------------------------------------------------------------------------ - # Perform feature selection using a model - if 'SelectFromModel' in para_estimator.keys() and para_estimator['SelectFromModel'] == 'True': - if verbose: - print("Selecting features using lasso model.") - # Use lasso model for feature selection - - # First, draw a random value for alpha and the penalty ratio - alpha = scipy.stats.uniform(loc=0.0, scale=1.5).rvs() - # l1_ratio = scipy.stats.uniform(loc=0.5, scale=0.4).rvs() - - # Create and fit lasso model - lassomodel = Lasso(alpha=alpha) - lassomodel.fit(feature_values, y) - - # Use fit to select optimal features - SelectModel = SelectFromModel(lassomodel, prefit=True) - if verbose: - print("Original Length: " + str(len(feature_values[0]))) - feature_values = SelectModel.transform(feature_values) - if verbose: - print("New Length: " + str(len(feature_values[0]))) - feature_labels = SelectModel.transform(feature_labels) - else: - SelectModel = None - if 'SelectFromModel' in para_estimator.keys(): - del para_estimator['SelectFromModel'] - - # Delete the object if we do not need to return it - if not return_all: - del SelectModel - - # ---------------------------------------------------------------- - # PCA dimensionality reduction - # Principle Component Analysis - if 'UsePCA' in para_estimator.keys() and para_estimator['UsePCA'] == 'True': - if verbose: - print('Fitting PCA') - print("Original Length: " + str(len(feature_values[0]))) - if para_estimator['PCAType'] == '95variance': - # Select first X components that describe 95 percent of the explained variance - pca = PCA(n_components=None) - pca.fit(feature_values) - evariance = pca.explained_variance_ratio_ - num = 0 - sum = 0 - while sum < 0.95: - sum += evariance[num] - num += 1 - - # Make a PCA based on the determined amound of components - pca = PCA(n_components=num) - pca.fit(feature_values) - feature_values = pca.transform(feature_values) - - else: - # Assume a fixed number of components - n_components = int(para_estimator['PCAType']) - pca = PCA(n_components=n_components) - pca.fit(feature_values) - feature_values = pca.transform(feature_values) - - if verbose: - print("New Length: " + str(len(feature_values[0]))) - else: - pca = None - - # Delete the object if we do not need to return it - if not return_all: - del pca - - if 'UsePCA' in para_estimator.keys(): - del para_estimator['UsePCA'] - del para_estimator['PCAType'] - - # ---------------------------------------------------------------- - # Fitting and scoring - # Only when using fastr this is an entry - if 'Number' in para_estimator.keys(): - del para_estimator['Number'] - - # For certainty, we delete all parameters again - para_estimator = delete_nonestimator_parameters(para_estimator) - - # NOTE: This just has to go to the construct classifier function, - # although it is more convenient here due to the hyperparameter search - if type(y) is list: - labellength = 1 - else: - try: - labellength = y.shape[1] - except IndexError: - labellength = 1 - - if labellength > 1 and type(estimator) != RankedSVM: - # Multiclass, hence employ a multiclass classifier for e.g. SVM, RF - estimator.set_params(**para_estimator) - estimator = OneVsRestClassifier(estimator) - para_estimator = {} - - if verbose: - print("Fitting ML.") - ret = _fit_and_score(estimator, feature_values, y, - scorer, train, - test, verbose, - para_estimator, fit_params, return_train_score, - return_parameters, - return_n_test_samples, - return_times, error_score) - - # Remove 'estimator object', it's the causes of a bug. - # Somewhere between scikit-learn 0.18.2 and 0.20.2 - # the estimator object return value was added - # removing this element fixes a bug that occurs later - # in SearchCV.py, where an array without estimator - # object is expected. - del ret[-1] - - # Paste original parameters in performance - ret.append(para) - - if return_all: - return ret, GroupSel, VarSel, SelectModel, feature_labels[0], scaler, imputer, pca, StatisticalSel, ReliefSel, sm, ros - else: - return ret
                        - - -
                        [docs]def delete_nonestimator_parameters(parameters): - ''' - Delete all parameters in a parameter dictionary that are not used for the - actual estimator. - ''' - if 'Number' in parameters.keys(): - del parameters['Number'] - - if 'UsePCA' in parameters.keys(): - del parameters['UsePCA'] - del parameters['PCAType'] - - if 'Imputation' in parameters.keys(): - del parameters['Imputation'] - del parameters['ImputationMethod'] - del parameters['ImputationNeighbours'] - - if 'SelectFromModel' in parameters.keys(): - del parameters['SelectFromModel'] - - if 'Featsel_Variance' in parameters.keys(): - del parameters['Featsel_Variance'] - - if 'FeatureScaling' in parameters.keys(): - del parameters['FeatureScaling'] - - if 'StatisticalTestUse' in parameters.keys(): - del parameters['StatisticalTestUse'] - del parameters['StatisticalTestMetric'] - del parameters['StatisticalTestThreshold'] - - if 'SampleProcessing_SMOTE' in parameters.keys(): - del parameters['SampleProcessing_SMOTE'] - del parameters['SampleProcessing_SMOTE_ratio'] - del parameters['SampleProcessing_SMOTE_neighbors'] - del parameters['SampleProcessing_SMOTE_n_cores'] - - if 'SampleProcessing_Oversampling' in parameters.keys(): - del parameters['SampleProcessing_Oversampling'] - - return parameters
                        - - -
                        [docs]def replacenan(image_features, verbose=True, feature_labels=None): - ''' - Replace the NaNs in an image feature matrix. - ''' - image_features_temp = image_features.copy() - for pnum, x in enumerate(image_features_temp): - for fnum, value in enumerate(x): - if np.isnan(value): - if verbose: - if feature_labels is not None: - print("[WORC WARNING] NaN found, patient {}, label {}. Replacing with zero.").format(pnum, feature_labels[fnum]) - else: - print("[WORC WARNING] NaN found, patient {}, label {}. Replacing with zero.").format(pnum, fnum) - # Note: X is a list of lists, hence we cannot index the element directly - image_features_temp[pnum, fnum] = 0 - - return image_features_temp
                        - - -
                        [docs]def delete_cc_para(para): - ''' - Delete all parameters that are involved in classifier construction. - ''' - deletekeys = ['classifiers', - 'max_iter', - 'SVMKernel', - 'SVMC', - 'SVMdegree', - 'SVMcoef0', - 'SVMgamma', - 'RFn_estimators', - 'RFmin_samples_split', - 'RFmax_depth', - 'LRpenalty', - 'LRC', - 'LDA_solver', - 'LDA_shrinkage', - 'QDA_reg_param', - 'ElasticNet_alpha', - 'ElasticNet_l1_ratio', - 'SGD_alpha', - 'SGD_l1_ratio', - 'SGD_loss', - 'SGD_penalty', - 'CNB_alpha'] - - for k in deletekeys: - if k in para.keys(): - del para[k] - - return para
                        -
                        - -
                        - -
                        -
                        - - -
                        - -
                        -

                        - © Copyright 2016 -- 2019, Biomedical Imaging Group Rotterdam, Departments of Medical Informatics and Radiology, Erasmus MC, Rotterdam, The Netherlands - -

                        -
                        - Built with Sphinx using a theme provided by Read the Docs. - -
                        - -
                        -
                        - -
                        - -
                        - - - - - - - - - - - - \ No newline at end of file diff --git a/build/lib/WORC/doc/_build/html/_modules/WORC/classification/metrics.html b/build/lib/WORC/doc/_build/html/_modules/WORC/classification/metrics.html deleted file mode 100644 index 22daa37e..00000000 --- a/build/lib/WORC/doc/_build/html/_modules/WORC/classification/metrics.html +++ /dev/null @@ -1,493 +0,0 @@ - - - - - - - - - - - WORC.classification.metrics — WORC 3.0.0 documentation - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
                        - - - -
                        - - - - - -
                        - -
                        - - - - - - - - - - - - - - - - - -
                        - -
                          - -
                        • Docs »
                        • - -
                        • Module code »
                        • - -
                        • WORC.classification.metrics
                        • - - -
                        • - -
                        • - -
                        - - -
                        -
                        -
                        -
                        - -

                        Source code for WORC.classification.metrics

                        -#!/usr/bin/env python
                        -
                        -# Copyright 2016-2019 Biomedical Imaging Group Rotterdam, Departments of
                        -# Medical Informatics and Radiology, Erasmus MC, Rotterdam, The Netherlands
                        -#
                        -# 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.
                        -
                        -from __future__ import division
                        -from sklearn.metrics import accuracy_score
                        -from sklearn.metrics import roc_auc_score
                        -from sklearn.metrics import confusion_matrix
                        -from sklearn.metrics import f1_score
                        -import numpy as np
                        -from sklearn import metrics
                        -from scipy.stats import pearsonr, spearmanr
                        -from sklearn.metrics import make_scorer, average_precision_score
                        -from sklearn.metrics import check_scoring as check_scoring_sklearn
                        -from scipy.linalg import pinv
                        -
                        -
                        -
                        [docs]def performance_singlelabel(y_truth, y_prediction, y_score, regression=False): - ''' - Singleclass performance metrics - ''' - if regression: - r2score = metrics.r2_score(y_truth, y_prediction) - MSE = metrics.mean_squared_error(y_truth, y_prediction) - coefICC = ICC(np.column_stack((y_prediction, y_truth))) - C = pearsonr(y_prediction, y_truth) - PearsonC = C[0] - PearsonP = C[1] - C = spearmanr(y_prediction, y_truth) - SpearmanC = C.correlation - SpearmanP = C.pvalue - - return r2score, MSE, coefICC, PearsonC, PearsonP, SpearmanC, SpearmanP - - else: - # Compute confuction matrics and extract measures - c_mat = confusion_matrix(y_truth, y_prediction) - TN = c_mat[0, 0] - FN = c_mat[1, 0] - TP = c_mat[1, 1] - FP = c_mat[0, 1] - - # compute confusion metric based statistics - if FN == 0 and TP == 0: - sensitivity = 0 - else: - sensitivity = float(TP)/(TP+FN) - - if FP == 0 and TN == 0: - specificity = 0 - else: - specificity = float(TN)/(FP+TN) - - if TP == 0 and FP == 0: - precision = 0 - else: - precision = float(TP)/(TP+FP) - - if TN == 0 and FN == 0: - NPV = 0 - else: - NPV = float(TN) / (TN + FN) - - # Additionally, compute accuracy, AUC and f1-score - accuracy = accuracy_score(y_truth, y_prediction) - auc = roc_auc_score(y_truth, y_score) - f1_score_out = f1_score(y_truth, y_prediction, average='weighted') - - return accuracy, sensitivity, specificity, precision, f1_score_out, auc
                        - - -
                        [docs]def performance_multilabel(y_truth, y_prediction, y_score=None, beta=1): - ''' - Multiclass performance metrics. - - y_truth and y_prediction should both be lists with the multiclass label of each - object, e.g. - - y_truth = [0, 0, 0, 0, 0, 0, 2, 2, 1, 1, 2] ### Groundtruth - y_prediction = [0, 0, 0, 0, 0, 0, 1, 2, 1, 2, 2] ### Predicted labels - - - Calculation of accuracy accorading to formula suggested in CAD Dementia Grand Challege http://caddementia.grand-challenge.org - Calculation of Multi Class AUC according to classpy: https://bitbucket.org/bigr_erasmusmc/classpy/src/master/classpy/multi_class_auc.py - - ''' - cm = confusion_matrix(y_truth, y_prediction) - - # Determine no. of classes - labels_class = np.unique(y_truth) - n_class = len(labels_class) - - # Splits confusion matrix in true and false positives and negatives - TP = np.zeros(shape=(1, n_class), dtype=int) - FN = np.zeros(shape=(1, n_class), dtype=int) - FP = np.zeros(shape=(1, n_class), dtype=int) - TN = np.zeros(shape=(1, n_class), dtype=int) - n = np.zeros(shape=(1, n_class), dtype=int) - for i in range(n_class): - TP[:, i] = cm[i, i] - FN[:, i] = np.sum(cm[i, :])-cm[i, i] - FP[:, i] = np.sum(cm[:, i])-cm[i, i] - TN[:, i] = np.sum(cm[:])-TP[:, i]-FP[:, i]-FN[:, i] - n[:, i] = np.sum(cm[:, i]) - - # Calculation of accuracy accorading to formula suggested in CAD Dementia Grand Challege http://caddementia.grand-challenge.org - Accuracy = (np.sum(TP))/(np.sum(n)) - - # Determine total positives and negatives - P = TP + FN - N = FP + TN - - # Calculation of sensitivity - Sensitivity = TP/P - Sensitivity = np.mean(Sensitivity) - - # Calculation of specifitity - Specificity = TN/N - Specificity = np.mean(Specificity) - - # Calculation of precision - Precision = TP/(TP+FP) - Precision = np.nan_to_num(Precision) - Precision = np.mean(Precision) - - # Calculation of F1_Score - F1_score = ((1+(beta**2))*(Sensitivity*Precision))/((beta**2)*(Precision + Sensitivity)) - F1_score = np.nan_to_num(F1_score) - F1_score = np.mean(F1_score) - - # Calculation of Multi Class AUC according to classpy: https://bitbucket.org/bigr_erasmusmc/classpy/src/master/classpy/multi_class_auc.py - if y_score is not None: - AUC = multi_class_auc(y_truth, y_score) - else: - AUC = None - - return Accuracy, Sensitivity, Specificity, Precision, F1_score, AUC
                        - - -
                        [docs]def pairwise_auc(y_truth, y_score, class_i, class_j): - # Filter out the probabilities for class_i and class_j - y_score = [est[class_i] for ref, est in zip(y_truth, y_score) if ref in (class_i, class_j)] - y_truth = [ref for ref in y_truth if ref in (class_i, class_j)] - - # Sort the y_truth by the estimated probabilities - sorted_y_truth = [y for x, y in sorted(zip(y_score, y_truth), key=lambda p: p[0])] - - # Calculated the sum of ranks for class_i - sum_rank = 0 - for index, element in enumerate(sorted_y_truth): - if element == class_i: - sum_rank += index + 1 - sum_rank = float(sum_rank) - - # Get the counts for class_i and class_j - n_class_i = float(y_truth.count(class_i)) - n_class_j = float(y_truth.count(class_j)) - - # If a class in empty, AUC is 0.0 - if n_class_i == 0 or n_class_j == 0: - return 0.0 - - # Calculate the pairwise AUC - return (sum_rank - (0.5 * n_class_i * (n_class_i + 1))) / (n_class_i * n_class_j)
                        - - -
                        [docs]def multi_class_auc(y_truth, y_score): - classes = np.unique(y_truth) - - if any(t == 0.0 for t in np.sum(y_score, axis=1)): - raise ValueError('No AUC is calculated, output probabilities are missing') - - pairwise_auc_list = [0.5 * (pairwise_auc(y_truth, y_score, i, j) + - pairwise_auc(y_truth, y_score, j, i)) for i in classes for j in classes if i < j] - - c = len(classes) - return (2.0 * sum(pairwise_auc_list)) / (c * (c - 1))
                        - - -
                        [docs]def multi_class_auc_score(y_truth, y_score): - return metrics.make_scorer(multi_class_auc, needs_proba=True)
                        - - -
                        [docs]def check_scoring(estimator, scoring=None, allow_none=False): - ''' - Surrogate for sklearn's check_scoring to enable use of some other - scoring metrics. - ''' - if scoring == 'average_precision_weighted': - scorer = make_scorer(average_precision_score, average='weighted') - else: - scorer = check_scoring_sklearn(estimator, scoring=scoring) - return scorer
                        - - -
                        [docs]def ICC(M, ICCtype='inter'): - ''' - Input: - M is matrix of observations. Rows: patients, columns: observers. - type: ICC type, currently "inter" or "intra". - ''' - - n, k = M.shape - - SStotal = np.var(M, ddof=1) * (n*k - 1) - MSR = np.var(np.mean(M, 1), ddof=1) * k - MSW = np.sum(np.var(M, 1, ddof=1)) / n - MSC = np.var(np.mean(M, 0), ddof=1) * n - MSE = (SStotal - MSR * (n - 1) - MSC * (k -1)) / ((n - 1) * (k - 1)) - - if ICCtype == 'intra': - r = (MSR - MSW) / (MSR + (k-1)*MSW) - elif ICCtype == 'inter': - r = (MSR - MSE) / (MSR + (k-1)*MSE + k*(MSC-MSE)/n) - else: - raise ValueError('No valid ICC type given.') - - return r
                        - - -
                        [docs]def ICC_anova(Y, ICCtype='inter', more=False): - ''' - Adopted from Nipype with a slight alteration to distinguish inter and intra. - the data Y are entered as a 'table' ie subjects are in rows and repeated - measures in columns - One Sample Repeated measure ANOVA - Y = XB + E with X = [FaTor / Subjects] - ''' - - [nb_subjects, nb_conditions] = Y.shape - dfc = nb_conditions - 1 - dfe = (nb_subjects - 1) * dfc - dfr = nb_subjects - 1 - - # Compute the repeated measure effect - # ------------------------------------ - - # Sum Square Total - mean_Y = np.mean(Y) - SST = ((Y - mean_Y) ** 2).sum() - - # create the design matrix for the different levels - x = np.kron(np.eye(nb_conditions), np.ones((nb_subjects, 1))) # sessions - x0 = np.tile(np.eye(nb_subjects), (nb_conditions, 1)) # subjects - X = np.hstack([x, x0]) - - # Sum Square Error - predicted_Y = np.dot(np.dot(np.dot(X, pinv(np.dot(X.T, X))), X.T), Y.flatten('F')) - residuals = Y.flatten('F') - predicted_Y - SSE = (residuals ** 2).sum() - - residuals.shape = Y.shape - - MSE = SSE / dfe - - # Sum square session effect - between colums/sessions - SSC = ((np.mean(Y, 0) - mean_Y) ** 2).sum() * nb_subjects - MSC = SSC / dfc / nb_subjects - - session_effect_F = MSC / MSE - - # Sum Square subject effect - between rows/subjects - SSR = SST - SSC - SSE - MSR = SSR / dfr - - # ICC(3,1) = (mean square subjeT - mean square error) / (mean square subjeT + (k-1)*-mean square error) - if ICCtype == 'intra': - ICC = (MSR - MSE) / (MSR + dfc*MSE) - elif ICCtype == 'inter': - ICC = (MSR - MSE) / (MSR + dfc*MSE + nb_conditions*(MSC-MSE)/nb_subjects) - else: - raise ValueError('No valid ICC type given.') - - e_var = MSE # variance of error - r_var = (MSR - MSE) / nb_conditions # variance between subjects - - if more: - return ICC, r_var, e_var, session_effect_F, dfc, dfe - else: - return ICC
                        -
                        - -
                        - -
                        -
                        - - -
                        - -
                        -

                        - © Copyright 2016 -- 2019, Biomedical Imaging Group Rotterdam, Departments of Medical Informatics and Radiology, Erasmus MC, Rotterdam, The Netherlands - -

                        -
                        - Built with Sphinx using a theme provided by Read the Docs. - -
                        - -
                        -
                        - -
                        - -
                        - - - - - - - - - - - - \ No newline at end of file diff --git a/build/lib/WORC/doc/_build/html/_modules/WORC/classification/parameter_optimization.html b/build/lib/WORC/doc/_build/html/_modules/WORC/classification/parameter_optimization.html deleted file mode 100644 index fabbbdd1..00000000 --- a/build/lib/WORC/doc/_build/html/_modules/WORC/classification/parameter_optimization.html +++ /dev/null @@ -1,288 +0,0 @@ - - - - - - - - - - - WORC.classification.parameter_optimization — WORC 3.0.0 documentation - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
                        - - - -
                        - - - - - -
                        - -
                        - - - - - - - - - - - - - - - - - -
                        - -
                          - -
                        • Docs »
                        • - -
                        • Module code »
                        • - -
                        • WORC.classification.parameter_optimization
                        • - - -
                        • - -
                        • - -
                        - - -
                        -
                        -
                        -
                        - -

                        Source code for WORC.classification.parameter_optimization

                        -#!/usr/bin/env python
                        -
                        -# Copyright 2016-2019 Biomedical Imaging Group Rotterdam, Departments of
                        -# Medical Informatics and Radiology, Erasmus MC, Rotterdam, The Netherlands
                        -#
                        -# 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 numpy as np
                        -from sklearn.utils import check_random_state
                        -from sklearn.model_selection import StratifiedShuffleSplit, ShuffleSplit
                        -from WORC.classification.SearchCV import RandomizedSearchCVfastr, RandomizedSearchCVJoblib
                        -
                        -
                        -
                        [docs]def random_search_parameters(features, labels, N_iter, test_size, - param_grid, scoring_method, - n_jobspercore=200, use_fastr=False, - n_cores=1, fastr_plugin=None): - """ - Train a classifier and simultaneously optimizes hyperparameters using a - randomized search. - - Arguments: - features: numpy array containing the training features. - labels: list containing the object labels to be trained on. - N_iter: integer listing the number of iterations to be used in the - hyperparameter optimization. - test_size: float listing the test size percentage used in the cross - validation. - classifier: sklearn classifier to be tested - param_grid: dictionary containing all possible hyperparameters and their - values or distrubitions. - scoring_method: string defining scoring method used in optimization, - e.g. f1_weighted for a SVM. - n_jobsperscore: integer listing the number of jobs that are ran on a - single core when using the fastr randomized search. - use_fastr: Boolean determining of either fastr or joblib should be used - for the opimization. - fastr_plugin: determines which plugin is used for fastr executions. - When None, uses the default plugin from the fastr config. - - Returns: - random_search: sklearn randomsearch object containing the results. - """ - - random_seed = np.random.randint(1, 5000) - random_state = check_random_state(random_seed) - - regressors = ['SVR', 'RFR', 'SGDR', 'Lasso', 'ElasticNet'] - if any(clf in regressors for clf in param_grid['classifiers']): - # We cannot do a stratified shuffle split with regression - cv = ShuffleSplit(n_splits=5, test_size=test_size, - random_state=random_state) - else: - cv = StratifiedShuffleSplit(n_splits=5, test_size=test_size, - random_state=random_state) - - if use_fastr: - random_search = RandomizedSearchCVfastr(param_distributions=param_grid, - n_iter=N_iter, - scoring=scoring_method, - n_jobs=n_cores, - n_jobspercore=n_jobspercore, - verbose=1, cv=cv, - fastr_plugin=fastr_plugin) - else: - random_search = RandomizedSearchCVJoblib(param_distributions=param_grid, - n_iter=N_iter, - scoring=scoring_method, - n_jobs=n_cores, - verbose=1, cv=cv) - random_search.fit(features, labels) - print("Best found parameters:") - for i in random_search.best_params_: - print(f'{i}: {random_search.best_params_[i]}.') - print("\n Best score using best parameters:") - print(random_search.best_score_) - - return random_search
                        -
                        - -
                        - -
                        -
                        - - -
                        - -
                        -

                        - © Copyright 2016 -- 2019, Biomedical Imaging Group Rotterdam, Departments of Medical Informatics and Radiology, Erasmus MC, Rotterdam, The Netherlands - -

                        -
                        - Built with Sphinx using a theme provided by Read the Docs. - -
                        - -
                        -
                        - -
                        - -
                        - - - - - - - - - - - - \ No newline at end of file diff --git a/build/lib/WORC/doc/_build/html/_modules/WORC/classification/trainclassifier.html b/build/lib/WORC/doc/_build/html/_modules/WORC/classification/trainclassifier.html deleted file mode 100644 index 126638e9..00000000 --- a/build/lib/WORC/doc/_build/html/_modules/WORC/classification/trainclassifier.html +++ /dev/null @@ -1,526 +0,0 @@ - - - - - - - - - - - WORC.classification.trainclassifier — WORC 3.0.0 documentation - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
                        - - - -
                        - - - - - -
                        - -
                        - - - - - - - - - - - - - - - - - -
                        - -
                          - -
                        • Docs »
                        • - -
                        • Module code »
                        • - -
                        • WORC.classification.trainclassifier
                        • - - -
                        • - -
                        • - -
                        - - -
                        -
                        -
                        -
                        - -

                        Source code for WORC.classification.trainclassifier

                        -#!/usr/bin/env python
                        -
                        -# Copyright 2016-2019 Biomedical Imaging Group Rotterdam, Departments of
                        -# Medical Informatics and Radiology, Erasmus MC, Rotterdam, The Netherlands
                        -#
                        -# 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 json
                        -import os
                        -import sklearn
                        -
                        -from WORC.classification import crossval as cv
                        -from WORC.classification import construct_classifier as cc
                        -from WORC.plotting.plot_SVM import plot_SVM
                        -from WORC.plotting.plot_SVR import plot_single_SVR
                        -import WORC.IOparser.file_io as file_io
                        -import WORC.IOparser.config_io_classifier as config_io
                        -from scipy.stats import uniform
                        -from WORC.classification.AdvancedSampler import discrete_uniform
                        -
                        -
                        -
                        [docs]def trainclassifier(feat_train, patientinfo_train, config, - output_hdf, output_json, - feat_test=None, patientinfo_test=None, - fixedsplits=None, verbose=True): - ''' - Train a classifier using machine learning from features. By default, if no - split in training and test is supplied, a cross validation - will be performed. - - Parameters - ---------- - feat_train: string, mandatory - contains the paths to all .hdf5 feature files used. - modalityname1=file1,file2,file3,... modalityname2=file1,... - Thus, modalities names are always between a space and a equal - sign, files are split by commas. We assume that the lists of - files for each modality has the same length. Files on the - same position on each list should belong to the same patient. - - patientinfo: string, mandatory - Contains the path referring to a .txt file containing the - patient label(s) and value(s) to be used for learning. See - the Github Wiki for the format. - - config: string, mandatory - path referring to a .ini file containing the parameters - used for feature extraction. See the Github Wiki for the possible - fields and their description. - - output_hdf: string, mandatory - path refering to a .hdf5 file to which the final classifier and - it's properties will be written to. - - output_json: string, mandatory - path refering to a .json file to which the performance of the final - classifier will be written to. This file is generated through one of - the WORC plotting functions. - - feat_test: string, optional - When this argument is supplied, the machine learning will not be - trained using a cross validation, but rather using a fixed training - and text split. This field should contain paths of the test set - feature files, similar to the feat_train argument. - - patientinfo_test: string, optional - When feat_test is supplied, you can supply optionally a patient label - file through which the performance will be evaluated. - - fixedsplits: string, optional - By default, random split cross validation is used to train and - evaluate the machine learning methods. Optionally, you can provide - a .xlsx file containing fixed splits to be used. See the Github Wiki - for the format. - - verbose: boolean, default True - print final feature values and labels to command line or not. - - ''' - - # Convert inputs from lists to strings - if type(patientinfo_train) is list: - patientinfo_train = ''.join(patientinfo_train) - - if type(patientinfo_test) is list: - patientinfo_test = ''.join(patientinfo_test) - - if type(config) is list: - if len(config) == 1: - config = ''.join(config) - else: - # FIXME - print('[WORC Warning] You provided multiple configuration files: only the first one will be used!') - config = config[0] - - if type(output_hdf) is list: - if len(output_hdf) == 1: - output_hdf = ''.join(output_hdf) - else: - # FIXME - print('[WORC Warning] You provided multiple output hdf files: only the first one will be used!') - output_hdf = output_hdf[0] - - if type(output_json) is list: - if len(output_json) == 1: - output_json = ''.join(output_json) - else: - # FIXME - print('[WORC Warning] You provided multiple output json files: only the first one will be used!') - output_json = output_json[0] - - # Load variables from the config file - config = config_io.load_config(config) - label_type = config['Labels']['label_names'] - modus = config['Labels']['modus'] - - # Load the feature files and match to label data - label_data_train, image_features_train =\ - load_features(feat_train, patientinfo_train, label_type) - - if feat_test: - label_data_test, image_features_test =\ - load_features(feat_test, patientinfo_test, label_type) - - # Create tempdir name from patientinfo file name - basename = os.path.basename(patientinfo_train) - filename, _ = os.path.splitext(basename) - path = patientinfo_train - for i in range(4): - # Use temp dir: result -> sample# -> parameters - > temppath - path = os.path.dirname(path) - - _, path = os.path.split(path) - path = os.path.join(path, 'trainclassifier', filename) - - # Construct the required classifier grid - param_grid = cc.create_param_grid(config) - - # IF at least once groupwise search is turned on, add it to the param grid - if 'True'in config['Featsel']['GroupwiseSearch']: - param_grid['SelectGroups'] = config['Featsel']['GroupwiseSearch'] - for group in config['SelectFeatGroup'].keys(): - param_grid[group] = config['SelectFeatGroup'][group] - - # If scaling is to be applied, add to parameters - if config['FeatureScaling']['scale_features']: - if type(config['FeatureScaling']['scaling_method']) is not list: - param_grid['FeatureScaling'] = [config['FeatureScaling']['scaling_method']] - else: - param_grid['FeatureScaling'] = config['FeatureScaling']['scaling_method'] - - # Add parameters for oversampling methods - param_grid['SampleProcessing_SMOTE'] = config['SampleProcessing']['SMOTE'] - param_grid['SampleProcessing_SMOTE_ratio'] =\ - uniform(loc=config['SampleProcessing']['SMOTE_ratio'][0], - scale=config['SampleProcessing']['SMOTE_ratio'][1]) - param_grid['SampleProcessing_SMOTE_neighbors'] =\ - discrete_uniform(loc=config['SampleProcessing']['SMOTE_neighbors'][0], - scale=config['SampleProcessing']['SMOTE_neighbors'][1]) - param_grid['SampleProcessing_SMOTE_n_cores'] = [config['General']['Joblib_ncores']] - param_grid['SampleProcessing_Oversampling'] = config['SampleProcessing']['Oversampling'] - - # Extract hyperparameter grid settings for SearchCV from config - param_grid['Featsel_Variance'] = config['Featsel']['Variance'] - - param_grid['Imputation'] = config['Imputation']['use'] - param_grid['ImputationMethod'] = config['Imputation']['strategy'] - param_grid['ImputationNeighbours'] =\ - discrete_uniform(loc=config['Imputation']['n_neighbors'][0], - scale=config['Imputation']['n_neighbors'][1]) - - param_grid['SelectFromModel'] = config['Featsel']['SelectFromModel'] - - param_grid['UsePCA'] = config['Featsel']['UsePCA'] - param_grid['PCAType'] = config['Featsel']['PCAType'] - - param_grid['StatisticalTestUse'] =\ - config['Featsel']['StatisticalTestUse'] - param_grid['StatisticalTestMetric'] =\ - config['Featsel']['StatisticalTestMetric'] - param_grid['StatisticalTestThreshold'] =\ - uniform(loc=config['Featsel']['StatisticalTestThreshold'][0], - scale=config['Featsel']['StatisticalTestThreshold'][1]) - - param_grid['ReliefUse'] =\ - config['Featsel']['ReliefUse'] - - param_grid['ReliefNN'] =\ - discrete_uniform(loc=config['Featsel']['ReliefNN'][0], - scale=config['Featsel']['ReliefNN'][1]) - - param_grid['ReliefSampleSize'] =\ - discrete_uniform(loc=config['Featsel']['ReliefSampleSize'][0], - scale=config['Featsel']['ReliefSampleSize'][1]) - - param_grid['ReliefDistanceP'] =\ - discrete_uniform(loc=config['Featsel']['ReliefDistanceP'][0], - scale=config['Featsel']['ReliefDistanceP'][1]) - - param_grid['ReliefNumFeatures'] =\ - discrete_uniform(loc=config['Featsel']['ReliefNumFeatures'][0], - scale=config['Featsel']['ReliefNumFeatures'][1]) - - # For N_iter, perform k-fold crossvalidation - outputfolder = os.path.dirname(output_hdf) - if feat_test is None: - trained_classifier = cv.crossval(config, label_data_train, - image_features_train, - param_grid, - modus=modus, - use_fastr=config['Classification']['fastr'], - fastr_plugin=config['Classification']['fastr_plugin'], - fixedsplits=fixedsplits, - ensemble=config['Ensemble'], - outputfolder=outputfolder, - tempsave=config['General']['tempsave']) - else: - trained_classifier = cv.nocrossval(config, label_data_train, - label_data_test, - image_features_train, - image_features_test, - param_grid, - modus=modus, - use_fastr=config['Classification']['fastr'], - fastr_plugin=config['Classification']['fastr_plugin'], - ensemble=config['Ensemble']) - - if not os.path.exists(os.path.dirname(output_hdf)): - os.makedirs(os.path.dirname(output_hdf)) - - trained_classifier.to_hdf(output_hdf, 'SVMdata') - - # Check whether we do regression or classification - regressors = ['SVR', 'RFR', 'SGDR', 'Lasso', 'ElasticNet'] - isclassifier =\ - not any(clf in regressors for clf in config['Classification']['classifiers']) - - # Calculate statistics of performance - if feat_test is None: - if not isclassifier: - statistics = plot_single_SVR(trained_classifier, label_data_train, - label_type) - else: - statistics = plot_SVM(trained_classifier, label_data_train, - label_type, modus=modus) - else: - if patientinfo_test is not None: - if not isclassifier: - statistics = plot_single_SVR(trained_classifier, - label_data_test, - label_type) - else: - statistics = plot_SVM(trained_classifier, - label_data_test, - label_type, - modus=modus) - else: - statistics = None - - # Save output - savedict = dict() - savedict["Statistics"] = statistics - - if not os.path.exists(os.path.dirname(output_json)): - os.makedirs(os.path.dirname(output_json)) - - with open(output_json, 'w') as fp: - json.dump(savedict, fp, indent=4) - - print("Saved data!")
                        - - -
                        [docs]def load_features(feat, patientinfo, label_type): - ''' Read feature files and stack the features per patient in an array. - Additionally, if a patient label file is supplied, the features from - a patient will be matched to the labels. - - Parameters - ---------- - featurefiles: list, mandatory - List containing all paths to the .hdf5 feature files to be loaded. - The argument should contain a list per modelity, e.g. - [[features_mod1_patient1, features_mod1_patient2, ...], - [features_mod2_patient1, features_mod2_patient2, ...]]. - - patientinfo: string, optional - Path referring to the .txt file to be used to read patient - labels from. See the Github Wiki for the format. - - label_names: list, optional - List containing all the labels that should be extracted from - the patientinfo file. - - ''' - # Split the feature files per modality - feat_temp = list() - modnames = list() - for feat_mod in feat: - feat_mod_temp = [str(item).strip() for item in feat_mod.split(',')] - - # The first item contains the name of the modality, followed by a = sign - temp = [str(item).strip() for item in feat_mod_temp[0].split('=')] - modnames.append(temp[0]) - feat_mod_temp[0] = temp[1] - - # Append the files to the main list - feat_temp.append(feat_mod_temp) - - feat = feat_temp - - # Read the features and classification data - label_data, image_features =\ - file_io.load_data(feat, patientinfo, - label_type, modnames) - - return label_data, image_features
                        -
                        - -
                        - -
                        -
                        - - -
                        - -
                        -

                        - © Copyright 2016 -- 2019, Biomedical Imaging Group Rotterdam, Departments of Medical Informatics and Radiology, Erasmus MC, Rotterdam, The Netherlands - -

                        -
                        - Built with Sphinx using a theme provided by Read the Docs. - -
                        - -
                        -
                        - -
                        - -
                        - - - - - - - - - - - - \ No newline at end of file diff --git a/build/lib/WORC/doc/_build/html/_modules/WORC/featureprocessing/Imputer.html b/build/lib/WORC/doc/_build/html/_modules/WORC/featureprocessing/Imputer.html deleted file mode 100644 index 4ddce7c4..00000000 --- a/build/lib/WORC/doc/_build/html/_modules/WORC/featureprocessing/Imputer.html +++ /dev/null @@ -1,284 +0,0 @@ - - - - - - - - - - - WORC.featureprocessing.Imputer — WORC 3.0.0 documentation - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
                        - - - -
                        - - - - - -
                        - -
                        - - - - - - - - - - - - - - - - - -
                        - -
                          - -
                        • Docs »
                        • - -
                        • Module code »
                        • - -
                        • WORC.featureprocessing.Imputer
                        • - - -
                        • - -
                        • - -
                        - - -
                        -
                        -
                        -
                        - -

                        Source code for WORC.featureprocessing.Imputer

                        -#!/usr/bin/env python
                        -
                        -# Copyright 2016-2019 Biomedical Imaging Group Rotterdam, Departments of
                        -# Medical Informatics and Radiology, Erasmus MC, Rotterdam, The Netherlands
                        -#
                        -# 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.
                        -
                        -from sklearn.impute import SimpleImputer
                        -from missingpy import KNNImputer
                        -
                        -
                        -
                        [docs]class Imputer(object): - """Module for feature imputation.""" - -
                        [docs] def __init__(self, missing_values='nan', strategy='mean', - n_neighbors=5): - ''' - Imputation of feature values using either sklearn, missingpy or - (WIP) fancyimpute approaches. - - Parameters - ---------- - missing_values : number, string, np.nan (default) or None - The placeholder for the missing values. All occurrences of - `missing_values` will be imputed. - - - strategy : string, optional (default="mean") - The imputation strategy. - - Supported using sklearn: - - If "mean", then replace missing values using the mean along - each column. Can only be used with numeric data. - - If "median", then replace missing values using the median along - each column. Can only be used with numeric data. - - If "most_frequent", then replace missing using the most frequent - value along each column. Can be used with strings or numeric data. - - If "constant", then replace missing values with fill_value. Can be - used with strings or numeric data. - - Supported using missingpy: - - If 'knn', then use a nearest neighbor search. Can be - used with strings or numeric data. - - WIP: More strategies using fancyimpute - - n_neighbors : int, optional (default = 5) - Number of neighboring samples to use for imputation if method - is knn. - - ''' - - # Set parameters to objects - self.missing_values = missing_values - self.strategy = strategy - self.n_neighbors = n_neighbors - - # Depending on the imputations strategy, use a specific toolbox - if strategy in ['mean', 'median', 'most_frequent', 'constant']: - self.Imputer =\ - SimpleImputer(missing_values=self.missing_values, - strategy=self.strategy) - elif strategy == 'knn': - if missing_values == 'nan': - # Slightly different API for missingpy - self.missing_values = 'NaN' - self.Imputer = KNNImputer(missing_values=self.missing_values, - n_neighbors=self.n_neighbors)
                        - -
                        [docs] def fit(self, X, y=None): - self.Imputer.fit(X, y)
                        - -
                        [docs] def transform(self, X): - return self.Imputer.transform(X)
                        -
                        - -
                        - -
                        -
                        - - -
                        - -
                        -

                        - © Copyright 2016 -- 2019, Biomedical Imaging Group Rotterdam, Departments of Medical Informatics and Radiology, Erasmus MC, Rotterdam, The Netherlands - -

                        -
                        - Built with Sphinx using a theme provided by Read the Docs. - -
                        - -
                        -
                        - -
                        - -
                        - - - - - - - - - - - - \ No newline at end of file diff --git a/build/lib/WORC/doc/_build/html/_modules/WORC/featureprocessing/Relief.html b/build/lib/WORC/doc/_build/html/_modules/WORC/featureprocessing/Relief.html deleted file mode 100644 index 1f69734b..00000000 --- a/build/lib/WORC/doc/_build/html/_modules/WORC/featureprocessing/Relief.html +++ /dev/null @@ -1,432 +0,0 @@ - - - - - - - - - - - WORC.featureprocessing.Relief — WORC 3.0.0 documentation - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
                        - - - -
                        - - - - - -
                        - -
                        - - - - - - - - - - - - - - - - - -
                        - -
                          - -
                        • Docs »
                        • - -
                        • Module code »
                        • - -
                        • WORC.featureprocessing.Relief
                        • - - -
                        • - -
                        • - -
                        - - -
                        -
                        -
                        -
                        - -

                        Source code for WORC.featureprocessing.Relief

                        -#!/usr/bin/env python
                        -
                        -# Copyright 2016-2019 Biomedical Imaging Group Rotterdam, Departments of
                        -# Medical Informatics and Radiology, Erasmus MC, Rotterdam, The Netherlands
                        -#
                        -# 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.
                        -
                        -from sklearn.base import BaseEstimator
                        -from sklearn.feature_selection.base import SelectorMixin
                        -import numpy as np
                        -import sklearn.neighbors as nn
                        -# from skrebate import ReliefF
                        -
                        -
                        -
                        [docs]class SelectMulticlassRelief(BaseEstimator, SelectorMixin): - ''' - Object to fit feature selection based on the type group the feature belongs - to. The label for the feature is used for this procedure. - ''' -
                        [docs] def __init__(self, n_neighbours=3, sample_size=1, distance_p=2, numf=None): - ''' - Parameters - ---------- - n_neightbors: integer - Number of nearest neighbours used. - - sample_size: float - Percentage of samples used to calculate score - - distance_p: integer - Parameter in minkov distance usde for nearest neighbour calculation - - numf: integer, default None - Number of important features to be selected with respect to their - ranking. If None, all are used. - - ''' - self.no_neighbours = n_neighbours - self.sample_size = sample_size - self.distance_p = distance_p - self.numf = numf
                        - -
                        [docs] def fit(self, X, y): - ''' - Select only features specificed by parameters per patient. - - Parameters - ---------- - feature_values: numpy array, mandatory - Array containing feature values used for model_selection. - Number of objects on first axis, features on second axis. - - feature_labels: list, mandatory - Contains the labels of all features used. The index in this - list will be used in the transform funtion to select features. - ''' - # Multiclass relief function - if len(y.shape) > 1: - indices, _ = self.multi_class_relief(X, y, - nb=self.no_neighbours, - sample_size=self.sample_size, - distance_p=self.distance_p, - numf=self.numf) - else: - indices, _ = self.single_class_relief(X, y, - nb=self.no_neighbours, - sample_size=self.sample_size, - distance_p=self.distance_p, - numf=self.numf) - - self.selectrows = indices
                        - -
                        [docs] def transform(self, inputarray): - ''' - Transform the inputarray to select only the features based on the - result from the fit function. - - Parameters - ---------- - inputarray: numpy array, mandatory - Array containing the items to use selection on. The type of - item in this list does not matter, e.g. floats, strings etc. - ''' - return np.asarray([np.asarray(x)[self.selectrows].tolist() for x in inputarray])
                        - # return self.ReliefF.transform(inputarray) - - def _get_support_mask(self): - # NOTE: Method is required for the Selector class, but can be empty - pass - -
                        [docs] def multi_class_relief(self, feature_set, label_set, nb=3, sample_size=1, - distance_p=2, numf=None): - - nrow, ncol = feature_set.shape - nlabel = label_set.shape[1] - sample_list = np.random.choice(range(nrow), int(nrow * sample_size), replace=False) - - feature_score = np.zeros((1, ncol)) - - prob = label_set.mean(axis=0) - n_sample = dict() - pair_score = dict() - - # find positive and negative samples for each label - for label in range(nlabel): - n_sample[label, 0] = [] - n_sample[label, 1] = [] - for row in sample_list: - if label_set[row, label] == 0: - n_sample[label, 0].append(row) - else: - n_sample[label, 1].append(row) - - for label1 in range(nlabel - 1): - for label2 in range(label1 + 1, nlabel): - pair_score[label1, label2] = np.zeros((1, ncol)) - if n_sample[label1, 0].__len__() >= nb and n_sample[label1, 1].__len__() >= nb: - # find near miss for label1 - n_neighbor_finder = nn.NearestNeighbors(n_neighbors=nb, p=distance_p) - n_neighbor_finder.fit(np.asarray(feature_set[n_sample[label1, 0], :])) - near_miss = n_neighbor_finder.kneighbors(np.asarray(feature_set[n_sample[label1, 0], :]), return_distance=False) - - # find near hit for label1 - p_neighbor_finder = nn.NearestNeighbors(n_neighbors=nb, p=distance_p) - p_neighbor_finder.fit(np.asarray(feature_set[n_sample[label1, 1], :])) - near_hit = p_neighbor_finder.kneighbors(np.asarray(feature_set[n_sample[label1, 1], :]), return_distance=False) - - for label2 in range(label1 + 1, nlabel): - for r in range(near_miss.__len__()): - for c in range(nb): - if label_set[near_miss[r, c], label2] == 1: - pair_score[label1, label2] += 1.0 * (prob[label2] / (1 - prob[label1])) *\ - np.abs(feature_set[n_sample[label1, 0][r], :] - - feature_set[near_miss[r, c], :]) / nb - for r in range(n_sample[label1, 1].__len__()): - for c in range(nb): - if label_set[near_hit[r, c], label2] == 1: - pair_score[label1, label2] -= (prob[label2] /(1 - prob[label1])) *\ - np.abs(feature_set[n_sample[label1, 1][r], :] - - feature_set[near_hit[r, c], :]) / nb - - for label1 in range(nlabel - 1): - for label2 in range(label1 + 1, nlabel): - feature_score += pair_score[label1, label2] - - feature_score = feature_score[0] - sorted_index = feature_score.argsort().tolist() - sorted_index.reverse() - sorted_index = np.array(sorted_index) - feature_score = feature_score[sorted_index] - - if numf is None: - numf = len(sorted_index) - - # Make sure we select at maximum all features - numf = min(numf, len(sorted_index)) - sorted_index = sorted_index[0:numf] - - return sorted_index, feature_score
                        - -
                        [docs] def single_class_relief(self, feature_set, label_set, nb=3, sample_size=1, - distance_p=2, numf=None): - - nrow, ncol = feature_set.shape - sample_list = np.random.choice(range(nrow), int(nrow * sample_size), replace=False) - - feature_score = np.zeros((1, ncol)) - - n_sample = dict() - - # find positive and negative samples for each label - n_sample[0] = [] - n_sample[1] = [] - for row in sample_list: - if label_set[row] == 0: - n_sample[0].append(row) - else: - n_sample[1].append(row) - - if n_sample[0].__len__() >= nb and n_sample[1].__len__() >= nb: - # find near miss for label1 - n_neighbor_finder = nn.NearestNeighbors(n_neighbors=nb, p=distance_p) - n_neighbor_finder.fit(np.asarray(feature_set[n_sample[0], :])) - near_miss = n_neighbor_finder.kneighbors(np.asarray(feature_set[n_sample[0], :]), return_distance=False) - - # find near hit for label1 - p_neighbor_finder = nn.NearestNeighbors(n_neighbors=nb, p=distance_p) - p_neighbor_finder.fit(np.asarray(feature_set[n_sample[1], :])) - near_hit = p_neighbor_finder.kneighbors(np.asarray(feature_set[n_sample[1], :]), return_distance=False) - - for r in range(near_miss.__len__()): - for c in range(nb): - if label_set[near_miss[r, c]] == 1: - feature_score += 1.0 * np.abs(feature_set[n_sample[0][r], :] - - feature_set[near_miss[r, c], :]) / nb - for r in range(n_sample[1].__len__()): - for c in range(nb): - if label_set[near_hit[r, c]] == 1: - feature_score -= 1.0 * np.abs(feature_set[n_sample[1][r], :] - - feature_set[near_hit[r, c], :]) / nb - - feature_score = feature_score[0] - sorted_index = feature_score.argsort().tolist() - sorted_index.reverse() - sorted_index = np.array(sorted_index) - feature_score = feature_score[sorted_index] - - if numf is None: - numf = len(sorted_index) - - # Make sure we select at maximum all features - numf = min(numf, len(sorted_index)) - sorted_index = sorted_index[0:numf] - - return sorted_index, feature_score
                        - - - # def single_class_relief_skrebate(self, feature_set, label_set, nb=3, sample_size=1, - # distance_p=2, numf=None): - # self.ReliefF = ReliefF(n_features_to_select=numf, n_neighbors=nb, n_jobs=1) - # self.ReliefF.fit(feature_set, label_set) - # return None, None -
                        - -
                        - -
                        -
                        - - -
                        - -
                        -

                        - © Copyright 2016 -- 2019, Biomedical Imaging Group Rotterdam, Departments of Medical Informatics and Radiology, Erasmus MC, Rotterdam, The Netherlands - -

                        -
                        - Built with Sphinx using a theme provided by Read the Docs. - -
                        - -
                        -
                        - -
                        - -
                        - - - - - - - - - - - - \ No newline at end of file diff --git a/build/lib/WORC/doc/_build/html/_modules/WORC/featureprocessing/SelectGroups.html b/build/lib/WORC/doc/_build/html/_modules/WORC/featureprocessing/SelectGroups.html deleted file mode 100644 index 5e636265..00000000 --- a/build/lib/WORC/doc/_build/html/_modules/WORC/featureprocessing/SelectGroups.html +++ /dev/null @@ -1,333 +0,0 @@ - - - - - - - - - - - WORC.featureprocessing.SelectGroups — WORC 3.0.0 documentation - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
                        - - - -
                        - - - - - -
                        - -
                        - - - - - - - - - - - - - - - - - -
                        - -
                          - -
                        • Docs »
                        • - -
                        • Module code »
                        • - -
                        • WORC.featureprocessing.SelectGroups
                        • - - -
                        • - -
                        • - -
                        - - -
                        -
                        -
                        -
                        - -

                        Source code for WORC.featureprocessing.SelectGroups

                        -#!/usr/bin/env python
                        -
                        -# Copyright 2016-2019 Biomedical Imaging Group Rotterdam, Departments of
                        -# Medical Informatics and Radiology, Erasmus MC, Rotterdam, The Netherlands
                        -#
                        -# 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.
                        -
                        -from sklearn.base import BaseEstimator
                        -from sklearn.feature_selection.base import SelectorMixin
                        -import numpy as np
                        -
                        -
                        -
                        [docs]class SelectGroups(BaseEstimator, SelectorMixin): - ''' - Object to fit feature selection based on the type group the feature belongs - to. The label for the feature is used for this procedure. - ''' -
                        [docs] def __init__(self, parameters): - ''' - Parameters - ---------- - parameters: dict, mandatory - Contains the settings for the groups to be selected. Should - contain the settings for the following groups: - - histogram_features - - shape_features - - orientation_features - - semantic_features - - patient_features - - coliage_features - - phase_features - - vessel_features - - log_features - - texture_Gabor_features - - texture_GLCM_features - - texture_GLCMMS_features - - texture_GLRLM_features - - texture_GLSZM_features - - texture_NGTDM_features - - texture_LBP_features - - ''' - params = list() - if parameters['histogram_features'] == 'True': - params.append('hf_') - if parameters['shape_features'] == 'True': - params.append('sf_') - if parameters['orientation_features'] == 'True': - params.append('of_') - if parameters['semantic_features'] == 'True': - params.append('semf_') - if parameters['patient_features'] == 'True': - params.append('pf_') - if parameters['coliage_features'] == 'True': - params.append('cf_') - if parameters['phase_features'] == 'True': - params.append('phasef_') - if parameters['vessel_features'] == 'True': - params.append('vf_') - if parameters['log_features'] == 'True': - params.append('logf_') - - if 'texture_features' in parameters.keys(): - # Backwards compatability - if parameters['texture_features'] == 'True': - params.append('tf_') - elif parameters['texture_features'] == 'False': - pass - else: - params.append('tf_' + parameters['texture_features']) - else: - # Hyperparameter per feature group - if parameters['texture_gabor_features'] == 'True': - params.append('tf_Gabor') - if parameters['texture_glcm_features'] == 'True': - params.append('tf_GLCM_') - if parameters['texture_glcmms_features'] == 'True': - params.append('tf_GLCMMS') - if parameters['texture_glrlm_features'] == 'True': - params.append('tf_GLRLM') - if parameters['texture_glszm_features'] == 'True': - params.append('tf_GLSZM') - if parameters['texture_ngtdm_features'] == 'True': - params.append('tf_NGTDM') - if parameters['texture_lbp_features'] == 'True': - params.append('tf_LBP') - - self.parameters = params
                        - -
                        [docs] def fit(self, feature_labels): - ''' - Select only features specificed by parameters per patient. - - Parameters - ---------- - feature_labels: list, optional - Contains the labels of all features used. The index in this - list will be used in the transform funtion to select features. - ''' - # Remove NAN - selectrows = list() - for num, l in enumerate(feature_labels): - if any(x in l for x in self.parameters): - selectrows.append(num) - - self.selectrows = selectrows
                        - -
                        [docs] def transform(self, inputarray): - ''' - Transform the inputarray to select only the features based on the - result from the fit function. - - Parameters - ---------- - inputarray: numpy array, mandatory - Array containing the items to use selection on. The type of - item in this list does not matter, e.g. floats, strings etc. - ''' - return np.asarray([np.asarray(x)[self.selectrows].tolist() for x in inputarray])
                        - - def _get_support_mask(self): - # NOTE: Method is required for the Selector class, but can be empty - pass
                        -
                        - -
                        - -
                        -
                        - - -
                        - -
                        -

                        - © Copyright 2016 -- 2019, Biomedical Imaging Group Rotterdam, Departments of Medical Informatics and Radiology, Erasmus MC, Rotterdam, The Netherlands - -

                        -
                        - Built with Sphinx using a theme provided by Read the Docs. - -
                        - -
                        -
                        - -
                        - -
                        - - - - - - - - - - - - \ No newline at end of file diff --git a/build/lib/WORC/doc/_build/html/_modules/WORC/featureprocessing/SelectIndividuals.html b/build/lib/WORC/doc/_build/html/_modules/WORC/featureprocessing/SelectIndividuals.html deleted file mode 100644 index 341ac7b6..00000000 --- a/build/lib/WORC/doc/_build/html/_modules/WORC/featureprocessing/SelectIndividuals.html +++ /dev/null @@ -1,282 +0,0 @@ - - - - - - - - - - - WORC.featureprocessing.SelectIndividuals — WORC 3.0.0 documentation - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
                        - - - -
                        - - - - - -
                        - -
                        - - - - - - - - - - - - - - - - - -
                        - -
                          - -
                        • Docs »
                        • - -
                        • Module code »
                        • - -
                        • WORC.featureprocessing.SelectIndividuals
                        • - - -
                        • - -
                        • - -
                        - - -
                        -
                        -
                        -
                        - -

                        Source code for WORC.featureprocessing.SelectIndividuals

                        -#!/usr/bin/env python
                        -
                        -# Copyright 2016-2019 Biomedical Imaging Group Rotterdam, Departments of
                        -# Medical Informatics and Radiology, Erasmus MC, Rotterdam, The Netherlands
                        -#
                        -# 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.
                        -
                        -from sklearn.base import BaseEstimator
                        -from sklearn.feature_selection.base import SelectorMixin
                        -import numpy as np
                        -
                        -
                        -
                        [docs]class SelectIndividuals(BaseEstimator, SelectorMixin): - ''' - Object to fit feature selection based on the type group the feature belongs - to. The label for the feature is used for this procedure. - ''' -
                        [docs] def __init__(self, parameters=['hf_mean', 'sf_compactness']): - ''' - Parameters - ---------- - parameters: dict, mandatory - Contains the settings for the groups to be selected. Should - contain the settings for the following groups: - - histogram_features - - shape_features - - orientation_features - - semantic_features - - patient_features - - coliage_features - - phase_features - - vessel_features - - log_features - - texture_features - - ''' - self.parameters = parameters
                        - -
                        [docs] def fit(self, feature_labels): - ''' - Select only features specificed by parameters per patient. - - Parameters - ---------- - feature_labels: list, optional - Contains the labels of all features used. The index in this - list will be used in the transform funtion to select features. - ''' - # Remove NAN - selectrows = list() - for num, l in enumerate(feature_labels): - if any(x in l for x in self.parameters): - selectrows.append(num) - - self.selectrows = selectrows
                        - -
                        [docs] def transform(self, inputarray): - ''' - Transform the inputarray to select only the features based on the - result from the fit function. - - Parameters - ---------- - inputarray: numpy array, mandatory - Array containing the items to use selection on. The type of - item in this list does not matter, e.g. floats, strings etc. - ''' - return np.asarray([np.asarray(x)[self.selectrows].tolist() for x in inputarray])
                        - - def _get_support_mask(self): - # NOTE: Method is required for the Selector class, but can be empty - pass
                        -
                        - -
                        - -
                        -
                        - - -
                        - -
                        -

                        - © Copyright 2016 -- 2019, Biomedical Imaging Group Rotterdam, Departments of Medical Informatics and Radiology, Erasmus MC, Rotterdam, The Netherlands - -

                        -
                        - Built with Sphinx using a theme provided by Read the Docs. - -
                        - -
                        -
                        - -
                        - -
                        - - - - - - - - - - - - \ No newline at end of file diff --git a/build/lib/WORC/doc/_build/html/_modules/WORC/featureprocessing/StatisticalTestThreshold.html b/build/lib/WORC/doc/_build/html/_modules/WORC/featureprocessing/StatisticalTestThreshold.html deleted file mode 100644 index eceeb535..00000000 --- a/build/lib/WORC/doc/_build/html/_modules/WORC/featureprocessing/StatisticalTestThreshold.html +++ /dev/null @@ -1,305 +0,0 @@ - - - - - - - - - - - WORC.featureprocessing.StatisticalTestThreshold — WORC 3.0.0 documentation - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
                        - - - -
                        - - - - - -
                        - -
                        - - - - - - - - - - - - - - - - - -
                        - -
                          - -
                        • Docs »
                        • - -
                        • Module code »
                        • - -
                        • WORC.featureprocessing.StatisticalTestThreshold
                        • - - -
                        • - -
                        • - -
                        - - -
                        -
                        -
                        -
                        - -

                        Source code for WORC.featureprocessing.StatisticalTestThreshold

                        -#!/usr/bin/env python
                        -
                        -# Copyright 2016-2019 Biomedical Imaging Group Rotterdam, Departments of
                        -# Medical Informatics and Radiology, Erasmus MC, Rotterdam, The Netherlands
                        -#
                        -# 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.
                        -
                        -from sklearn.base import BaseEstimator
                        -from sklearn.feature_selection.base import SelectorMixin
                        -import numpy as np
                        -from scipy.stats import ttest_ind, ranksums, mannwhitneyu
                        -
                        -
                        -
                        [docs]class StatisticalTestThreshold(BaseEstimator, SelectorMixin): - ''' - Object to fit feature selection based on statistical tests. - ''' -
                        [docs] def __init__(self, metric='ttest', threshold=0.05): - ''' - Parameters - ---------- - metric: string, default 'ttest' - Statistical test used for selection. Options are ttest, - Welch, Wilcoxon, MannWhitneyU - threshold: float, default 0.05 - Threshold for p-value in order for feature to be selected - - ''' - self.metric = metric - self.threshold = threshold
                        - -
                        [docs] def fit(self, X_train, Y_train): - ''' - Select only features specificed by the metric and threshold per patient. - - Parameters - ---------- - X_train: numpy array, mandatory - Array containing feature values used for model_selection. - Number of objects on first axis, features on second axis. - - Y_train: numpy array, mandatory - Array containing the binary labels for each object in X_train. - ''' - - self.selectrows = list() - self.metric_values = list() - - # Set the metric function - if self.metric == 'ttest': - self.metric_function = ttest_ind - self.parameters = {'equal_var': True} - elif self.metric == 'Welch': - self.metric_function = ttest_ind - self.parameters = {'equal_var': False} - elif self.metric == 'Wilcoxon': - self.metric_function = ranksums - self.parameters = {} - elif self.metric == 'MannWhitneyU': - self.metric_function = mannwhitneyu - self.parameters = {} - - # Perform the statistical test for each feature - for n_feat in range(0, X_train.shape[1]): - fv = X_train[:, n_feat] - - class1 = [i for j, i in enumerate(fv) if Y_train[j] == 1] - class2 = [i for j, i in enumerate(fv) if Y_train[j] == 0] - - try: - metric_value = self.metric_function(class1, class2, **self.parameters)[1] - except ValueError as e: - print("[PREDICT Warning] " + str(e) + '. Replacing metric value by 1.') - metric_value = 1 - - self.metric_values.append(metric_value) - if metric_value < self.threshold: - self.selectrows.append(n_feat)
                        - -
                        [docs] def transform(self, inputarray): - ''' - Transform the inputarray to select only the features based on the - result from the fit function. - - Parameters - ---------- - inputarray: numpy array, mandatory - Array containing the items to use selection on. The type of - item in this list does not matter, e.g. floats, strings etc. - ''' - return np.asarray([np.asarray(x)[self.selectrows].tolist() for x in inputarray])
                        - - def _get_support_mask(self): - # NOTE: metric is required for the Selector class, but can be empty - pass
                        -
                        - -
                        - -
                        -
                        - - -
                        - -
                        -

                        - © Copyright 2016 -- 2019, Biomedical Imaging Group Rotterdam, Departments of Medical Informatics and Radiology, Erasmus MC, Rotterdam, The Netherlands - -

                        -
                        - Built with Sphinx using a theme provided by Read the Docs. - -
                        - -
                        -
                        - -
                        - -
                        - - - - - - - - - - - - \ No newline at end of file diff --git a/build/lib/WORC/doc/_build/html/_modules/WORC/featureprocessing/VarianceThreshold.html b/build/lib/WORC/doc/_build/html/_modules/WORC/featureprocessing/VarianceThreshold.html deleted file mode 100644 index 739c8860..00000000 --- a/build/lib/WORC/doc/_build/html/_modules/WORC/featureprocessing/VarianceThreshold.html +++ /dev/null @@ -1,313 +0,0 @@ - - - - - - - - - - - WORC.featureprocessing.VarianceThreshold — WORC 3.0.0 documentation - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
                        - - - -
                        - - - - - -
                        - -
                        - - - - - - - - - - - - - - - - - -
                        - -
                          - -
                        • Docs »
                        • - -
                        • Module code »
                        • - -
                        • WORC.featureprocessing.VarianceThreshold
                        • - - -
                        • - -
                        • - -
                        - - -
                        -
                        -
                        -
                        - -

                        Source code for WORC.featureprocessing.VarianceThreshold

                        -#!/usr/bin/env python
                        -
                        -# Copyright 2016-2019 Biomedical Imaging Group Rotterdam, Departments of
                        -# Medical Informatics and Radiology, Erasmus MC, Rotterdam, The Netherlands
                        -#
                        -# 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.
                        -
                        -from sklearn.feature_selection import VarianceThreshold
                        -from sklearn.base import BaseEstimator
                        -from sklearn.feature_selection.base import SelectorMixin
                        -import numpy as np
                        -import PREDICT.addexceptions as ae
                        -
                        -
                        -
                        [docs]class VarianceThresholdMean(BaseEstimator, SelectorMixin): - ''' - Select features based on variance among objects. Similar to VarianceThreshold - from sklearn, but does take the mean of the feature into account. - ''' -
                        [docs] def __init__(self, threshold): - self.threshold = threshold
                        - -
                        [docs] def fit(self, image_features): - selectrows = list() - means = np.mean(image_features, axis=0) - variances = np.var(image_features, axis=0) - - for i in range(image_features.shape[1]): - if variances[i] > self.threshold*(1-self.threshold)*means[i]: - selectrows.append(i) - - self.selectrows = selectrows - return self
                        - -
                        [docs] def transform(self, inputarray): - ''' - Transform the inputarray to select only the features based on the - result from the fit function. - Parameters - ---------- - inputarray: numpy array, mandatory - Array containing the items to use selection on. The type of - item in this list does not matter, e.g. floats, strings etc. - ''' - return np.asarray([np.asarray(x)[self.selectrows].tolist() for x in inputarray])
                        - - def _get_support_mask(self): - # NOTE: Method is required for the Selector class, but can be empty - pass
                        - - -
                        [docs]def selfeat_variance(image_features, labels=None, thresh=0.99, - method='nomean'): - ''' - Select features using a variance threshold. - - Parameters - ---------- - image_features: numpy array, mandatory - Array containing the feature values to apply the variance threshold - selection on. The rows correspond to the patients, the column to the - features. - - labels: numpy array, optional - Array containing the labels of the corresponding features. Array - should therefore have the same shape as the image_features array. - - thresh: float, default 0.99 - Threshold to be used as lower boundary for feature variance among - patients. - method: string, default nomean. - Method to use for selection. Default: do not use the mean of the - features. Other valid option is 'mean'. - - Returns - ---------- - image_features: numpy array - Transformed features array. - - labels: list or None - When labels are given, returns the transformed labels. That object - contains a list of all label names kept. - - sel: VarianceThreshold object - The fitted variance threshold object. - - ''' - if method == 'nomean': - sel = VarianceThreshold(threshold=thresh*(1 - thresh)) - elif method == 'mean': - sel = VarianceThresholdMean(threshold=thresh*(1 - thresh)) - else: - raise ae.PREDICTKeyError(('Invalid method {} given for ' + - 'VarianceThreshold feature selection. ' + - 'Should be "mean" or ' + - '"nomean".').format(str(method))) - - sel = sel.fit(image_features) - image_features = sel.transform(image_features) - if labels is not None: - labels = sel.transform(labels) - - return image_features, labels, sel
                        -
                        - -
                        - -
                        -
                        - - -
                        - -
                        -

                        - © Copyright 2016 -- 2019, Biomedical Imaging Group Rotterdam, Departments of Medical Informatics and Radiology, Erasmus MC, Rotterdam, The Netherlands - -

                        -
                        - Built with Sphinx using a theme provided by Read the Docs. - -
                        - -
                        -
                        - -
                        - -
                        - - - - - - - - - - - - \ No newline at end of file diff --git a/build/lib/WORC/doc/_build/html/_modules/WORC/plotting/compute_CI.html b/build/lib/WORC/doc/_build/html/_modules/WORC/plotting/compute_CI.html deleted file mode 100644 index 6b2f37f8..00000000 --- a/build/lib/WORC/doc/_build/html/_modules/WORC/plotting/compute_CI.html +++ /dev/null @@ -1,291 +0,0 @@ - - - - - - - - - - - WORC.plotting.compute_CI — WORC 3.0.0 documentation - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
                        - - - -
                        - - - - - -
                        - -
                        - - - - - - - - - - - - - - - - - -
                        - -
                          - -
                        • Docs »
                        • - -
                        • Module code »
                        • - -
                        • WORC.plotting.compute_CI
                        • - - -
                        • - -
                        • - -
                        - - -
                        -
                        -
                        -
                        - -

                        Source code for WORC.plotting.compute_CI

                        -#!/usr/bin/env python
                        -
                        -# Copyright 2016-2019 Biomedical Imaging Group Rotterdam, Departments of
                        -# Medical Informatics and Radiology, Erasmus MC, Rotterdam, The Netherlands
                        -#
                        -# 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 numpy as np
                        -import scipy.stats as st
                        -from scipy.special import logit, expit
                        -
                        -
                        -
                        [docs]def compute_confidence(metric, N_train, N_test, alpha=0.95): - """ - Function to calculate the adjusted confidence interval - metric: numpy array containing the result for a metric for the different cross validations - (e.g. If 20 cross-validations are performed it is a list of length 20 with the calculated accuracy for - each cross validation) - N_train: Integer, number of training samples - N_test: Integer, number of test_samples - alpha: float ranging from 0 to 1 to calculate the alpha*100% CI, default 95% - """ - - # Convert to floats, as python 2 rounds the divisions if we have integers - N_train = float(N_train) - N_test = float(N_test) - N_iterations = float(len(metric)) - - if N_iterations == 1.0: - print('[WORC Warning] Cannot compute a confidence interval for a single iteration.') - print('[WORC Warning] CI will be set to value of single iteration.') - metric_average = np.mean(metric) - CI = (metric_average, metric_average) - else: - metric_average = np.mean(metric) - S_uj = 1.0 / (N_iterations - 1) * np.sum((metric_average - metric)**2.0) - - metric_std = np.sqrt((1.0/N_iterations + N_test/N_train)*S_uj) - - CI = st.t.interval(alpha, N_iterations-1, loc=metric_average, scale=metric_std) - - if np.isnan(CI[0]) and np.isnan(CI[1]): - # When we cannot compute a CI, just give the averages - CI = (metric_average, metric_average) - return CI
                        - - -
                        [docs]def compute_confidence_logit(metric, N_train, N_test, alpha=0.95): - """ - Function to calculate the adjusted confidence interval - metric: numpy array containing the result for a metric for the different cross validations - (e.g. If 20 cross-validations are performed it is a list of length 20 with the calculated accuracy for - each cross validation) - N_train: Integer, number of training samples - N_test: Integer, number of test_samples - alpha: float ranging from 0 to 1 to calculate the alpha*100% CI, default 95% - """ - N_iterations = len(metric) - - # Compute average of logit function - # metric_logit = [logit(x) for x in metric] - logit_average = logit(np.mean(metric)) - - # Compute metric average and corrected resampled t-test metric std - metric_average = np.mean(metric) - S_uj = 1.0 / (N_iterations - 1) * np.sum((metric_average - metric)**2.0) - metric_std = np.sqrt((1.0/N_iterations + N_test/N_train)*S_uj) - - # Compute z(1-alpha/2) quantile - q1 = 1.0-(1-alpha)/2 - z = st.t.ppf(q1, N_iterations - 1) - - # Compute logit confidence intervals according to Barbiero - theta_L = logit_average - z * metric_std/(metric_average*(1 - metric_average)) - theta_U = logit_average + z * metric_std/(metric_average*(1 - metric_average)) - - # Transform back - CI = (expit(theta_L), expit(theta_U)) - - return CI
                        -
                        - -
                        - -
                        -
                        - - -
                        - -
                        -

                        - © Copyright 2016 -- 2019, Biomedical Imaging Group Rotterdam, Departments of Medical Informatics and Radiology, Erasmus MC, Rotterdam, The Netherlands - -

                        -
                        - Built with Sphinx using a theme provided by Read the Docs. - -
                        - -
                        -
                        - -
                        - -
                        - - - - - - - - - - - - \ No newline at end of file diff --git a/build/lib/WORC/doc/_build/html/_modules/WORC/plotting/linstretch.html b/build/lib/WORC/doc/_build/html/_modules/WORC/plotting/linstretch.html deleted file mode 100644 index bd7a7833..00000000 --- a/build/lib/WORC/doc/_build/html/_modules/WORC/plotting/linstretch.html +++ /dev/null @@ -1,231 +0,0 @@ - - - - - - - - - - - WORC.plotting.linstretch — WORC 3.0.0 documentation - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
                        - - - -
                        - - - - - -
                        - -
                        - - - - - - - - - - - - - - - - - -
                        - -
                          - -
                        • Docs »
                        • - -
                        • Module code »
                        • - -
                        • WORC.plotting.linstretch
                        • - - -
                        • - -
                        • - -
                        - - -
                        -
                        -
                        -
                        - -

                        Source code for WORC.plotting.linstretch

                        -#!/usr/bin/env python
                        -
                        -# Copyright 2016-2019 Biomedical Imaging Group Rotterdam, Departments of
                        -# Medical Informatics and Radiology, Erasmus MC, Rotterdam, The Netherlands
                        -#
                        -# 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 numpy as np
                        -
                        -
                        -
                        [docs]def linstretch(i, i_max=255, i_min=0): - ''' - Stretch the input image i pixel values from i_min to i_max - ''' - rmin = np.min(i.flatten()) # find the min. value of pixel in the image - rmax = np.max(i.flatten()) # find the max. value of pixel in the image - m = (i_max - i_min)/(rmax - rmin) # find the slope of line joining point (0, 255) to (rmin,rmax) - c = i_max - m*rmax # find the intercept of the straight line with the axis - i_stretch = m*i + c # transform the image according to new slope - - return i_stretch
                        -
                        - -
                        - -
                        -
                        - - -
                        - -
                        -

                        - © Copyright 2016 -- 2019, Biomedical Imaging Group Rotterdam, Departments of Medical Informatics and Radiology, Erasmus MC, Rotterdam, The Netherlands - -

                        -
                        - Built with Sphinx using a theme provided by Read the Docs. - -
                        - -
                        -
                        - -
                        - -
                        - - - - - - - - - - - - \ No newline at end of file diff --git a/build/lib/WORC/doc/_build/html/_modules/WORC/plotting/plot_ROC.html b/build/lib/WORC/doc/_build/html/_modules/WORC/plotting/plot_ROC.html deleted file mode 100644 index f89e028e..00000000 --- a/build/lib/WORC/doc/_build/html/_modules/WORC/plotting/plot_ROC.html +++ /dev/null @@ -1,588 +0,0 @@ - - - - - - - - - - - WORC.plotting.plot_ROC — WORC 3.0.0 documentation - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
                        - - - -
                        - - - - - -
                        - -
                        - - - - - - - - - - - - - - - - - -
                        - - - - -
                        -
                        -
                        -
                        - -

                        Source code for WORC.plotting.plot_ROC

                        -#!/usr/bin/env python
                        -
                        -# Copyright 2016-2019 Biomedical Imaging Group Rotterdam, Departments of
                        -# Medical Informatics and Radiology, Erasmus MC, Rotterdam, The Netherlands
                        -#
                        -# 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 matplotlib
                        -matplotlib.use('agg')
                        -import matplotlib.pyplot as plt
                        -
                        -from matplotlib2tikz import save as tikz_save
                        -import pandas as pd
                        -import argparse
                        -from WORC.plotting.compute_CI import compute_confidence as CI
                        -import numpy as np
                        -from sklearn.metrics import roc_auc_score, auc
                        -import csv
                        -from WORC.plotting.plot_SVM import plot_SVM
                        -
                        -
                        -
                        [docs]def plot_single_ROC(y_truth, y_score, verbose=False): - ''' - Get the False Positive Ratio (FPR) and True Positive Ratio (TPR) - for the ground truth and score of a single estimator. These ratios - can be used to plot a Receiver Operator Characteristic (ROC) curve. - ''' - # Sort both lists based on the scores - y_truth = np.asarray(y_truth) - y_truth = np.int_(y_truth) - y_score = np.asarray(y_score) - inds = y_score.argsort() - y_truth_sorted = y_truth[inds] - y_score = y_score[inds] - - # Compute the TPR and FPR for all possible thresholds - FP = 0 - TP = 0 - fpr = list() - tpr = list() - thresholds = list() - fprev = -np.inf - i = 0 - N = float(np.bincount(y_truth)[0]) - P = float(np.bincount(y_truth)[1]) - while i < len(y_truth_sorted): - if y_score[i] != fprev: - fpr.append(1 - FP/N) - tpr.append(1 - TP/P) - thresholds.append(y_score[i]) - fprev = y_score[i] - - if y_truth_sorted[i] == 1: - TP += 1 - else: - FP += 1 - - i += 1 - - if verbose: - roc_auc = auc(fpr, tpr) - plt.figure() - lw = 2 - plt.plot(fpr, tpr, color='darkorange', - lw=lw, label='ROC curve (area = %0.2f)' % roc_auc) - plt.plot([0, 1], [0, 1], color='navy', lw=lw, linestyle='--') - plt.xlim([0.0, 1.0]) - plt.ylim([0.0, 1.05]) - plt.xlabel('False Positive Rate') - plt.ylabel('True Positive Rate') - plt.title('Receiver operating characteristic example') - plt.legend(loc="lower right") - - return fpr[::-1], tpr[::-1], thresholds[::-1]
                        - - -
                        [docs]def ROC_thresholding(fprt, tprt, thresholds, nsamples=20): - ''' - Construct FPR and TPR ratios at different thresholds for the scores of an - estimator. - ''' - # Combine all found thresholds in a list and create samples - T = list() - for t in thresholds: - T.extend(t) - T = sorted(T) - tsamples = np.linspace(0, len(T) - 1, nsamples) - - # Compute the fprs and tprs at the sample points - nrocs = len(fprt) - fpr = np.zeros((nsamples, nrocs)) - tpr = np.zeros((nsamples, nrocs)) - - th = list() - for n_sample, tidx in enumerate(tsamples): - tidx = int(tidx) - th.append(T[tidx]) - for i_roc in range(0, nrocs): - idx = 0 - while float(thresholds[i_roc][idx]) > float(T[tidx]) and idx < (len(thresholds[i_roc]) - 1): - idx += 1 - fpr[n_sample, i_roc] = fprt[i_roc][idx] - tpr[n_sample, i_roc] = tprt[i_roc][idx] - - return fpr, tpr, th
                        - - -
                        [docs]def plot_ROC_CIc(y_truth, y_score, N_1, N_2, plot='default', alpha=0.95, - verbose=False, DEBUG=False, tsamples=20): - ''' - Plot a Receiver Operator Characteristic (ROC) curve with confidence intervals. - - tsamples: number of sample points on which to determine the confidence intervals. - The sample pointsare used on the thresholds for y_score. - ''' - # Compute ROC curve and ROC area for each class - fprt = list() - tprt = list() - roc_auc = list() - thresholds = list() - for yt, ys in zip(y_truth, y_score): - fpr_temp, tpr_temp, thresholds_temp = plot_single_ROC(yt, ys) - roc_auc.append(roc_auc_score(yt, ys)) - fprt.append(fpr_temp) - tprt.append(tpr_temp) - thresholds.append(thresholds_temp) - - # Sample FPR and TPR at numerous points - fpr, tpr, th = ROC_thresholding(fprt, tprt, thresholds, tsamples) - - # Compute the confidence intervals for the ROC - CIs_tpr = list() - CIs_fpr = list() - for i in range(0, tsamples): - if i == 0: - # Point (1, 1) is always in there, but shows as (nan, nan) - CIs_fpr.append([1, 1]) - CIs_tpr.append([1, 1]) - else: - cit_fpr = CI(fpr[i, :], N_1, N_2, alpha) - CIs_fpr.append([cit_fpr[0], cit_fpr[1]]) - cit_tpr = CI(tpr[i, :], N_1, N_2, alpha) - CIs_tpr.append([cit_tpr[0], cit_tpr[1]]) - - # The point (0, 0) is also always there but not computed - CIs_fpr.append([0, 0]) - CIs_tpr.append([0, 0]) - - # Calculate also means of CIs after converting to array - CIs_tpr = np.asarray(CIs_tpr) - CIs_fpr = np.asarray(CIs_fpr) - CIs_tpr_means = np.mean(CIs_tpr, axis=1).tolist() - CIs_fpr_means = np.mean(CIs_fpr, axis=1).tolist() - - # compute AUC CI - roc_auc = CI(roc_auc, N_1, N_2, alpha) - - f = plt.figure() - lw = 2 - subplot = f.add_subplot(111) - subplot.plot(CIs_fpr_means, CIs_tpr_means, color='orange', - lw=lw, label='ROC curve (AUC = (%0.2f, %0.2f))' % (roc_auc[0], roc_auc[1])) - - for i in range(0, len(CIs_fpr_means)): - if CIs_tpr[i, 1] <= 1: - ymax = CIs_tpr[i, 1] - else: - ymax = 1 - - if CIs_tpr[i, 0] <= 0: - ymin = 0 - else: - ymin = CIs_tpr[i, 0] - - if CIs_tpr_means[i] <= 1: - ymean = CIs_tpr_means[i] - else: - ymean = 1 - - if CIs_fpr[i, 1] <= 1: - xmax = CIs_fpr[i, 1] - else: - xmax = 1 - - if CIs_fpr[i, 0] <= 0: - xmin = 0 - else: - xmin = CIs_fpr[i, 0] - - if CIs_fpr_means[i] <= 1: - xmean = CIs_fpr_means[i] - else: - xmean = 1 - - if DEBUG: - print(xmin, xmax, ymean) - print(ymin, ymax, xmean) - - subplot.plot([xmin, xmax], - [ymean, ymean], - color='black', alpha=0.15) - subplot.plot([xmean, xmean], - [ymin, ymax], - color='black', alpha=0.15) - - subplot.plot([0, 1], [0, 1], color='navy', lw=lw, linestyle='--') - plt.xlim([0.0, 1.0]) - plt.ylim([0.0, 1.05]) - plt.xlabel('False Positive Rate (1 - Specificity)') - plt.ylabel('True Positive Rate (Sensitivity)') - plt.title('Receiver operating characteristic') - plt.legend(loc="lower right") - - if verbose: - plt.show() - - f = plt.figure() - lw = 2 - subplot = f.add_subplot(111) - subplot.plot(CIs_fpr_means, CIs_tpr_means, color='darkorange', - lw=lw, label='ROC curve (AUC = (%0.2f, %0.2f))' % (roc_auc[0], roc_auc[1])) - - for i in range(0, len(CIs_fpr_means)): - if CIs_tpr[i, 1] <= 1: - ymax = CIs_tpr[i, 1] - else: - ymax = 1 - - if CIs_tpr[i, 0] <= 0: - ymin = 0 - else: - ymin = CIs_tpr[i, 0] - - if CIs_tpr_means[i] <= 1: - ymean = CIs_tpr_means[i] - else: - ymean = 1 - - if CIs_fpr[i, 1] <= 1: - xmax = CIs_fpr[i, 1] - else: - xmax = 1 - - if CIs_fpr[i, 0] <= 0: - xmin = 0 - else: - xmin = CIs_fpr[i, 0] - - if CIs_fpr_means[i] <= 1: - xmean = CIs_fpr_means[i] - else: - xmean = 1 - - subplot.plot([xmin, xmax], - [ymean, ymean], - color='black', alpha=0.15) - subplot.plot([xmean, xmean], - [ymin, ymax], - color='black', alpha=0.15) - - subplot.plot([0, 1], [0, 1], color='navy', lw=lw, linestyle='--') - plt.xlim([0.0, 1.0]) - plt.ylim([0.0, 1.05]) - plt.xlabel('False Positive Rate (1 - Specificity)') - plt.ylabel('True Positive Rate (Sensitivity)') - plt.title('Receiver operating characteristic') - plt.legend(loc="lower right") - - return f, CIs_fpr, CIs_tpr
                        - - -
                        [docs]def main(): - parser = argparse.ArgumentParser(description='Plot the ROC Curve of an estimator') - parser.add_argument('-prediction', '--prediction', metavar='prediction', - nargs='+', dest='prediction', type=str, required=True, - help='Prediction file (HDF)') - parser.add_argument('-pinfo', '--pinfo', metavar='pinfo', - nargs='+', dest='pinfo', type=str, required=True, - help='Patient Info File (txt)') - parser.add_argument('-ensemble', '--ensemble', metavar='ensemble', - nargs='+', dest='ensemble', type=str, required=True, - help='Length of ensemble (int)') - parser.add_argument('-label_type', '--label_type', metavar='label_type', - nargs='+', dest='label_type', type=str, required=True, - help='Label name that is predicted (string)') - parser.add_argument('-output_png', '--output_png', metavar='output_png', - nargs='+', dest='output_png', type=str, required=False, - help='File to write output to (PNG)') - parser.add_argument('-output_csv', '--output_csv', metavar='output_csv', - nargs='+', dest='output_csv', type=str, required=False, - help='File to write output to (csv)') - parser.add_argument('-output_tex', '--output_tex', metavar='output_tex', - nargs='+', dest='output_tex', type=str, required=False, - help='File to write output to (tex)') - args = parser.parse_args() - - plot_ROC(prediction=args.prediction, - pinfo=args.pinfo, - ensemble=args.ensemble, - label_type=args.label_type, - output_png=args.output_png, - output_tex=args.output_tex, - output_csv=args.output_csv)
                        - - -
                        [docs]def plot_ROC(prediction, pinfo, ensemble=1, label_type=None, - output_png=None, output_tex=None, output_csv=None): - # Convert the inputs to the correct format - if type(prediction) is list: - prediction = ''.join(prediction) - - if type(pinfo) is list: - pinfo = ''.join(pinfo) - - if type(ensemble) is list: - ensemble = int(ensemble[0]) - # ensemble = ''.join(ensemble) - - if type(output_png) is list: - output_png = ''.join(output_png) - - if type(output_csv) is list: - output_csv = ''.join(output_csv) - - if type(output_tex) is list: - output_tex = ''.join(output_tex) - - if type(label_type) is list: - label_type = ''.join(label_type) - - # Read the inputs - prediction = pd.read_hdf(prediction) - if label_type is None: - # Assume we want to have the first key - label_type = prediction.keys()[0] - N_1 = len(prediction[label_type].Y_train[0]) - N_2 = len(prediction[label_type].Y_test[0]) - - # Determine the predicted score per patient - print('Determining score per patient.') - y_truths, y_scores, _, _ = plot_SVM(prediction, pinfo, label_type, - show_plots=False, - alpha=0.95, ensemble=ensemble, - output='decision') - - # Plot the ROC with confidence intervals - print("Plotting the ROC with confidence intervals.") - plot = 'default' - f, fpr, tpr = plot_ROC_CIc(y_truths, y_scores, N_1, N_2) - - if plot == 'default': - plot = '' - - # Save the outputs - if output_png is not None: - f.savefig(output_png) - print(("ROC saved as {} !").format(output_png)) - - if output_tex is not None: - tikz_save(output_tex) - print(("ROC saved as {} !").format(output_tex)) - - # Save ROC values as JSON - if output_csv is not None: - with open(output_csv, 'wb') as csv_file: - writer = csv.writer(csv_file) - writer.writerow(['FPR', 'TPR']) - for i in range(0, len(fpr)): - data = [str(fpr[i]), str(tpr[i])] - writer.writerow(data) - - print(("ROC saved as {} !").format(output_csv)) - - return f, fpr, tpr
                        - - -if __name__ == '__main__': - main() -
                        - -
                        - -
                        -
                        - - -
                        - -
                        -

                        - © Copyright 2016 -- 2019, Biomedical Imaging Group Rotterdam, Departments of Medical Informatics and Radiology, Erasmus MC, Rotterdam, The Netherlands - -

                        -
                        - Built with Sphinx using a theme provided by Read the Docs. - -
                        - -
                        -
                        - -
                        - -
                        - - - - - - - - - - - - \ No newline at end of file diff --git a/build/lib/WORC/doc/_build/html/_modules/WORC/plotting/plot_SVM.html b/build/lib/WORC/doc/_build/html/_modules/WORC/plotting/plot_SVM.html deleted file mode 100644 index 598adc35..00000000 --- a/build/lib/WORC/doc/_build/html/_modules/WORC/plotting/plot_SVM.html +++ /dev/null @@ -1,638 +0,0 @@ - - - - - - - - - - - WORC.plotting.plot_SVM — WORC 3.0.0 documentation - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
                        - - - -
                        - - - - - -
                        - -
                        - - - - - - - - - - - - - - - - - -
                        - - - - -
                        -
                        -
                        -
                        - -

                        Source code for WORC.plotting.plot_SVM

                        -#!/usr/bin/env python
                        -
                        -# Copyright 2016-2019 Biomedical Imaging Group Rotterdam, Departments of
                        -# Medical Informatics and Radiology, Erasmus MC, Rotterdam, The Netherlands
                        -#
                        -# 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 numpy as np
                        -import sys
                        -import WORC.plotting.compute_CI as compute_CI
                        -import pandas as pd
                        -import os
                        -import WORC.processing.label_processing as lp
                        -from WORC.classification import metrics
                        -import WORC.addexceptions as ae
                        -from sklearn.base import is_regressor
                        -
                        -
                        -
                        [docs]def plot_SVM(prediction, label_data, label_type, show_plots=False, - alpha=0.95, ensemble=False, verbose=True, - ensemble_scoring=None, output='stats', - modus='singlelabel'): - ''' - Plot the output of a single binary estimator, e.g. a SVM. - - Parameters - ---------- - prediction: pandas dataframe or string, mandatory - output of trainclassifier function, either a pandas dataframe - or a HDF5 file - - label_data: string, mandatory - Contains the path referring to a .txt file containing the - patient label(s) and value(s) to be used for learning. See - the Github Wiki for the format. - - label_type: string, mandatory - Name of the label to extract from the label data to test the - estimator on. - - show_plots: Boolean, default False - Determine whether matplotlib performance plots are made. - - alpha: float, default 0.95 - Significance of confidence intervals. - - ensemble: False, integer or 'Caruana' - Determine whether an ensemble will be created. If so, - either provide an integer to determine how many of the - top performing classifiers should be in the ensemble, or use - the string "Caruana" to use smart ensembling based on - Caruana et al. 2004. - - verbose: boolean, default True - Plot intermedate messages. - - ensemble_scoring: string, default None - Metric to be used for evaluating the ensemble. If None, - the option set in the prediction object will be used. - - output: string, default stats - Determine which results are put out. If stats, the statistics of the - estimator will be returned. If scores, the scores will be returned. - - Returns - ---------- - Depending on the output parameters, the following outputs are returned: - - If output == 'stats': - stats: dictionary - Contains the confidence intervals of the performance metrics - and the number of times each patient was classifier correctly - or incorrectly. - - If output == 'scores': - y_truths: list - Contains the true label for each object. - - y_scores: list - Contains the score (e.g. posterior) for each object. - - y_predictions: list - Contains the predicted label for each object. - - PIDs: list - Contains the patient ID/name for each object. - ''' - - # Load the prediction object if it's a hdf5 file - if type(prediction) is not pd.core.frame.DataFrame: - if os.path.isfile(prediction): - prediction = pd.read_hdf(prediction) - else: - raise ae.WORCIOError(('{} is not an existing file!').format(str(prediction))) - - # Select the estimator from the pandas dataframe to use - keys = prediction.keys() - SVMs = list() - if label_type is None: - label_type = keys[0] - - # Load the label data - if type(label_data) is not dict: - if os.path.isfile(label_data): - if type(label_type) is not list: - # Singlelabel: convert to list - label_type = [[label_type]] - label_data = lp.load_labels(label_data, label_type) - - patient_IDs = label_data['patient_IDs'] - labels = label_data['label'] - - if type(label_type) is list: - # FIXME: Support for multiple label types not supported yet. - print('[WORC Warning] Support for multiple label types not supported yet. Taking first label for plot_SVM.') - label_type = keys[0] - - # Extract the estimators, features and labels - SVMs = prediction[label_type]['classifiers'] - regression = is_regressor(SVMs[0].best_estimator_) - Y_test = prediction[label_type]['Y_test'] - X_test = prediction[label_type]['X_test'] - X_train = prediction[label_type]['X_train'] - Y_train = prediction[label_type]['Y_train'] - feature_labels = prediction[label_type]['feature_labels'] - - # Create lists for performance measures - sensitivity = list() - specificity = list() - precision = list() - accuracy = list() - auc = list() - f1_score_list = list() - patient_classification_list = dict() - if output in ['scores', 'decision']: - # Keep track of all groundth truths and scores - y_truths = list() - y_scores = list() - y_predictions = list() - PIDs = list() - - # Loop over the test sets, which probably correspond with cross validation - # iterations - for i in range(0, len(Y_test)): - print("\n") - print(("Cross validation {} / {}.").format(str(i + 1), str(len(Y_test)))) - test_patient_IDs = prediction[label_type]['patient_ID_test'][i] - train_patient_IDs = prediction[label_type]['patient_ID_train'][i] - X_test_temp = X_test[i] - X_train_temp = X_train[i] - Y_train_temp = Y_train[i] - Y_test_temp = Y_test[i] - test_indices = list() - - # Check which patients are in the test set. - for i_ID in test_patient_IDs: - test_indices.append(np.where(patient_IDs == i_ID)[0][0]) - - # Initiate counting how many times a patient is classified correctly - if i_ID not in patient_classification_list: - patient_classification_list[i_ID] = dict() - patient_classification_list[i_ID]['N_test'] = 0 - patient_classification_list[i_ID]['N_correct'] = 0 - patient_classification_list[i_ID]['N_wrong'] = 0 - - patient_classification_list[i_ID]['N_test'] += 1 - - # Extract ground truth - y_truth = Y_test_temp - - # If requested, first let the SearchCV object create an ensemble - if ensemble: - # NOTE: Added for backwards compatability - if not hasattr(SVMs[i], 'cv_iter'): - cv_iter = list(SVMs[i].cv.split(X_train_temp, Y_train_temp)) - SVMs[i].cv_iter = cv_iter - - # Create the ensemble - X_train_temp = [(x, feature_labels) for x in X_train_temp] - SVMs[i].create_ensemble(X_train_temp, Y_train_temp, - method=ensemble, verbose=verbose, - scoring=ensemble_scoring) - - # Create prediction - y_prediction = SVMs[i].predict(X_test_temp) - - if regression: - y_score = y_prediction - else: - y_score = SVMs[i].predict_proba(X_test_temp)[:, 1] - - print("Truth: " + str(y_truth)) - print("Prediction: " + str(y_prediction)) - - # Add if patient was classified correctly or not to counting - for i_truth, i_predict, i_test_ID in zip(y_truth, y_prediction, test_patient_IDs): - if modus == 'multilabel': - success = (i_truth == i_predict).all() - else: - success = i_truth == i_predict - - if success: - patient_classification_list[i_test_ID]['N_correct'] += 1 - else: - patient_classification_list[i_test_ID]['N_wrong'] += 1 - - y_score = SVMs[i].predict_proba(X_test_temp)[:, 1] - - if output == 'decision': - # Output the posteriors - y_scores.append(y_score) - y_truths.append(y_truth) - y_predictions.append(y_prediction) - PIDs.append(test_patient_IDs) - - elif output == 'scores': - # Output the posteriors - y_scores.append(y_score) - y_truths.append(y_truth) - y_predictions.append(y_prediction) - PIDs.append(test_patient_IDs) - - elif output == 'stats': - # Compute statistics - # Compute confusion matrix and use for sensitivity/specificity - if modus == 'singlelabel': - # Compute singlelabel performance metrics - if not regression: - accuracy_temp, sensitivity_temp, specificity_temp,\ - precision_temp, f1_score_temp, auc_temp =\ - metrics.performance_singlelabel(y_truth, - y_prediction, - y_score, - regression) - else: - r2score, MSE, coefICC, PearsonC, PearsonP, SpearmanC,\ - SpearmanP =\ - metrics.performance_singlelabel(y_truth, - y_prediction, - y_score, - regression) - - elif modus == 'multilabel': - # Convert class objects to single label per patient - y_truth_temp = list() - y_prediction_temp = list() - for yt, yp in zip(y_truth, y_prediction): - label = np.where(yt == 1) - if len(label) > 1: - raise ae.WORCNotImplementedError('Multiclass classification evaluation is not supported in WORC.') - - y_truth_temp.append(label[0][0]) - label = np.where(yp == 1) - y_prediction_temp.append(label[0][0]) - - y_truth = y_truth_temp - y_prediction = y_prediction_temp - - # Compute multilabel performance metrics - accuracy_temp, sensitivity_temp, specificity_temp,\ - precision_temp, f1_score_temp, auc_temp =\ - metrics.performance_multilabel(y_truth, - y_prediction, - y_score) - - else: - raise ae.WORCKeyError('{} is not a valid modus!').format(modus) - - # Print AUC to keep you up to date - print('AUC: ' + str(auc_temp)) - - # Append performance to lists for all cross validations - accuracy.append(accuracy_temp) - sensitivity.append(sensitivity_temp) - specificity.append(specificity_temp) - auc.append(auc_temp) - f1_score_list.append(f1_score_temp) - precision.append(precision_temp) - - if output in ['scores', 'decision']: - # Return the scores and true values of all patients - return y_truths, y_scores, y_predictions, PIDs - elif output == 'stats': - # Compute statistics - # Extract sample size - N_1 = float(len(train_patient_IDs)) - N_2 = float(len(test_patient_IDs)) - - # Compute alpha confidence intervallen - stats = dict() - stats["Accuracy 95%:"] = str(compute_CI.compute_confidence(accuracy, N_1, N_2, alpha)) - - stats["AUC 95%:"] = str(compute_CI.compute_confidence(auc, N_1, N_2, alpha)) - - stats["F1-score 95%:"] = str(compute_CI.compute_confidence(f1_score_list, N_1, N_2, alpha)) - - stats["Precision 95%:"] = str(compute_CI.compute_confidence(precision, N_1, N_2, alpha)) - - stats["Sensitivity 95%: "] = str(compute_CI.compute_confidence(sensitivity, N_1, N_2, alpha)) - - stats["Specificity 95%:"] = str(compute_CI.compute_confidence(specificity, N_1, N_2, alpha)) - - print("Accuracy 95%:" + str(compute_CI.compute_confidence(accuracy, N_1, N_2, alpha))) - - print("AUC 95%:" + str(compute_CI.compute_confidence(auc, N_1, N_2, alpha))) - - print("F1-score 95%:" + str(compute_CI.compute_confidence(f1_score_list, N_1, N_2, alpha))) - - print("Precision 95%:" + str(compute_CI.compute_confidence(precision, N_1, N_2, alpha))) - - print("Sensitivity 95%: " + str(compute_CI.compute_confidence(sensitivity, N_1, N_2, alpha))) - - print("Specificity 95%:" + str(compute_CI.compute_confidence(specificity, N_1, N_2, alpha))) - - # Extract statistics on how often patients got classified correctly - alwaysright = dict() - alwayswrong = dict() - percentages = dict() - for i_ID in patient_classification_list: - percentage_right = patient_classification_list[i_ID]['N_correct'] / float(patient_classification_list[i_ID]['N_test']) - - if i_ID in patient_IDs: - label = labels[0][np.where(i_ID == patient_IDs)] - else: - # Multiple instance of one patient - label = labels[0][np.where(i_ID.split('_')[0] == patient_IDs)] - - label = label[0][0] - percentages[i_ID] = str(label) + ': ' + str(round(percentage_right, 2) * 100) + '%' - if percentage_right == 1.0: - alwaysright[i_ID] = label - print(("Always Right: {}, label {}").format(i_ID, label)) - - elif percentage_right == 0: - alwayswrong[i_ID] = label - print(("Always Wrong: {}, label {}").format(i_ID, label)) - - stats["Always right"] = alwaysright - stats["Always wrong"] = alwayswrong - stats['Percentages'] = percentages - - if show_plots: - # Plot some characteristics in boxplots - import matplotlib.pyplot as plt - - plt.figure() - plt.boxplot(accuracy) - plt.ylim([-0.05, 1.05]) - plt.ylabel('Accuracy') - plt.tick_params( - axis='x', # changes apply to the x-axis - which='both', # both major and minor ticks are affected - bottom='off', # ticks along the bottom edge are off - top='off', # ticks along the top edge are off - labelbottom='off') # labels along the bottom edge are off - plt.tight_layout() - plt.show() - - plt.figure() - plt.boxplot(auc) - plt.ylim([-0.05, 1.05]) - plt.ylabel('AUC') - plt.tick_params( - axis='x', # changes apply to the x-axis - which='both', # both major and minor ticks are affected - bottom='off', # ticks along the bottom edge are off - top='off', # ticks along the top edge are off - labelbottom='off') # labels along the bottom edge are off - plt.tight_layout() - plt.show() - - plt.figure() - plt.boxplot(precision) - plt.ylim([-0.05, 1.05]) - plt.ylabel('Precision') - plt.tick_params( - axis='x', # changes apply to the x-axis - which='both', # both major and minor ticks are affected - bottom='off', # ticks along the bottom edge are off - top='off', # ticks along the top edge are off - labelbottom='off') # labels along the bottom edge are off - plt.tight_layout() - plt.show() - - plt.figure() - plt.boxplot(sensitivity) - plt.ylim([-0.05, 1.05]) - plt.ylabel('Sensitivity') - plt.tick_params( - axis='x', # changes apply to the x-axis - which='both', # both major and minor ticks are affected - bottom='off', # ticks along the bottom edge are off - top='off', # ticks along the top edge are off - labelbottom='off') # labels along the bottom edge are off - plt.tight_layout() - plt.show() - - plt.figure() - plt.boxplot(specificity) - plt.ylim([-0.05, 1.05]) - plt.ylabel('Specificity') - plt.tick_params( - axis='x', # changes apply to the x-axis - which='both', # both major and minor ticks are affected - bottom='off', # ticks along the bottom edge are off - top='off', # ticks along the top edge are off - labelbottom='off') # labels along the bottom edge are off - plt.tight_layout() - plt.show() - - return stats
                        - - -
                        [docs]def main(): - if len(sys.argv) == 1: - print("TODO: Put in an example") - elif len(sys.argv) != 4: - raise IOError("This function accepts three arguments!") - else: - prediction = sys.argv[1] - patientinfo = sys.argv[2] - label_type = sys.argv[3] - plot_SVM(prediction, patientinfo, label_type)
                        - - -if __name__ == '__main__': - main() -
                        - -
                        - -
                        -
                        - - -
                        - -
                        -

                        - © Copyright 2016 -- 2019, Biomedical Imaging Group Rotterdam, Departments of Medical Informatics and Radiology, Erasmus MC, Rotterdam, The Netherlands - -

                        -
                        - Built with Sphinx using a theme provided by Read the Docs. - -
                        - -
                        -
                        - -
                        - -
                        - - - - - - - - - - - - \ No newline at end of file diff --git a/build/lib/WORC/doc/_build/html/_modules/WORC/plotting/plot_SVR.html b/build/lib/WORC/doc/_build/html/_modules/WORC/plotting/plot_SVR.html deleted file mode 100644 index a11140c8..00000000 --- a/build/lib/WORC/doc/_build/html/_modules/WORC/plotting/plot_SVR.html +++ /dev/null @@ -1,426 +0,0 @@ - - - - - - - - - - - WORC.plotting.plot_SVR — WORC 3.0.0 documentation - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
                        - - - -
                        - - - - - -
                        - -
                        - - - - - - - - - - - - - - - - - -
                        - - - - -
                        -
                        -
                        -
                        - -

                        Source code for WORC.plotting.plot_SVR

                        -#!/usr/bin/env python
                        -
                        -# Copyright 2016-2019 Biomedical Imaging Group Rotterdam, Departments of
                        -# Medical Informatics and Radiology, Erasmus MC, Rotterdam, The Netherlands
                        -#
                        -# 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 numpy as np
                        -from sklearn.metrics import r2_score, mean_squared_error
                        -import sys
                        -import WORC.plotting.compute_CI
                        -import pandas as pd
                        -import os
                        -import lifelines as ll
                        -import WORC.processing.label_processing as lp
                        -from scipy.stats import pearsonr, spearmanr
                        -from WORC.classification.metrics import ICC
                        -
                        -
                        -
                        [docs]def plot_single_SVR(prediction, label_data, label_type, survival=False, - show_plots=False, alpha=0.95): - if type(prediction) is not pd.core.frame.DataFrame: - if os.path.isfile(prediction): - prediction = pd.read_hdf(prediction) - - keys = prediction.keys() - SVRs = list() - label = keys[0] - SVRs = prediction[label]['classifiers'] - - Y_test = prediction[label]['Y_test'] - X_test = prediction[label]['X_test'] - Y_train = prediction[label]['X_train'] - - if survival: - # Also extract time to event and if event occurs from label data - labels = [[label_type], ['E'], ['T']] - else: - labels = [[label_type]] - - if type(label_data) is not dict: - if os.path.isfile(label_data): - label_data = lp.load_labels(label_data, labels) - - patient_IDs = label_data['patient_IDs'] - labels = label_data['label'] - - # Initialize scoring metrics - r2score = list() - MSE = list() - coefICC = list() - PearsonC = list() - PearsonP = list() - SpearmanC = list() - SpearmanP = list() - - if survival: - cindex = list() - coxp = list() - coxcoef = list() - - patient_MSE = dict() - - for i in range(0, len(Y_test)): - test_patient_IDs = prediction[label]['patient_ID_test'][i] - - # FIXME: Put some wrong patient IDs in test files - for num in range(0, len(test_patient_IDs)): - if 'features_' in test_patient_IDs[num]: - test_patient_IDs[num] = test_patient_IDs[num][9::] - - if '__tpl.hdf5' in test_patient_IDs[num]: - test_patient_IDs[num] = test_patient_IDs[num][0:-10] - - test_patient_IDs = np.asarray(test_patient_IDs) - - X_temp = X_test[i] - - test_indices = list() - for i_ID in test_patient_IDs: - # FIXME: Error in specific study - if i_ID == '112_recurrence-preop': - i_ID = '112_recurrence_preop' - test_indices.append(np.where(patient_IDs == i_ID)[0][0]) - - y_truth = [labels[0][k][0] for k in test_indices] - - if type(SVRs) == list or type(SVRs) == tuple: - estimator = SVRs[i] - else: - estimator = SVRs - - scaler = estimator.best_scaler - try: - y_prediction = estimator.predict(scaler.transform(X_temp)) - except ValueError: - y_prediction = estimator.predict(X_temp) - - y_truth = np.asarray(y_truth) - - # if survival: - # # Normalize the scores - # y_prediction = np.subtract(1.01, np.divide(y_prediction, np.max(y_prediction))) - - print("Truth: " + y_truth) - print("Prediction: " + y_prediction) - - # Compute error per patient - for i_truth, i_predict, i_test_ID in zip(y_truth, y_prediction, test_patient_IDs): - if i_test_ID not in patient_MSE.keys(): - patient_MSE[i_test_ID] = list() - patient_MSE[i_test_ID].append((i_truth - i_predict)**2) - - # Compute evaluation metrics - r2score.append(r2_score(y_truth, y_prediction)) - MSE.append(mean_squared_error(y_truth, y_prediction)) - coefICC.append(ICC(np.column_stack((y_prediction, y_truth)))) - C = pearsonr(y_prediction, y_truth) - PearsonC.append(C[0]) - PearsonP.append(C[1]) - C = spearmanr(y_prediction, y_truth) - SpearmanC.append(C.correlation) - SpearmanP.append(C.pvalue) - - if survival: - # Extract time to event and event from label data - E_truth = np.asarray([labels[1][k][0] for k in test_indices]) - T_truth = np.asarray([labels[2][k][0] for k in test_indices]) - - # Concordance index - cindex.append(1 - ll.utils.concordance_index(T_truth, y_prediction, E_truth)) - - # Fit Cox model using SVR output, time to event and event - data = {'predict': y_prediction, 'E': E_truth, 'T': T_truth} - data = pd.DataFrame(data=data, index=test_patient_IDs) - - cph = ll.CoxPHFitter() - cph.fit(data, duration_col='T', event_col='E') - - coxcoef.append(cph.summary['coef']['predict']) - coxp.append(cph.summary['p']['predict']) - - # Compute confidence intervals for given metrics - N_1 = float(len(Y_train[0])) - N_2 = float(len(Y_test[0])) - - if len(r2score) == 1: - # No confidence intevals, just take the scores - stats = dict() - stats["r2_score:"] = str(r2score[0]) - stats["MSE:"] = str(MSE[0]) - stats["ICC:"] = str(coefICC[0]) - stats["PearsonC:"] = str(PearsonC[0]) - stats["SpearmanC: "] = str(SpearmanC[0]) - stats["PearsonP:"] = str(PearsonP[0]) - stats["SpearmanP: "] = str(SpearmanP[0]) - - if survival: - stats["Concordance:"] = str(cindex[0]) - stats["Cox coef.:"] = str(coxcoef[0]) - stats["Cox p:"] = str(coxp[0]) - else: - # Compute confidence intervals from cross validations - stats = dict() - stats["r2_score 95%:"] = str(compute_CI.compute_confidence(r2score, N_1, N_2, alpha)) - stats["MSE 95%:"] = str(compute_CI.compute_confidence(MSE, N_1, N_2, alpha)) - stats["ICC 95%:"] = str(compute_CI.compute_confidence(coefICC, N_1, N_2, alpha)) - stats["PearsonC 95%:"] = str(compute_CI.compute_confidence(PearsonC, N_1, N_2, alpha)) - stats["SpearmanC 95%: "] = str(compute_CI.compute_confidence(SpearmanC, N_1, N_2, alpha)) - stats["PearsonP 95%:"] = str(compute_CI.compute_confidence(PearsonP, N_1, N_2, alpha)) - stats["SpearmanP 95%: "] = str(compute_CI.compute_confidence(SpearmanP, N_1, N_2, alpha)) - - if survival: - stats["Concordance 95%:"] = str(compute_CI.compute_confidence(cindex, N_1, N_2, alpha)) - stats["Cox coef. 95%:"] = str(compute_CI.compute_confidence(coxcoef, N_1, N_2, alpha)) - stats["Cox p 95%:"] = str(compute_CI.compute_confidence(coxp, N_1, N_2, alpha)) - - for k, v in stats.iteritems(): - print(k, v) - - # Calculate and sort individual patient MSE - patient_MSE = {k: np.mean(v) for k, v in patient_MSE.iteritems()} - order = np.argsort(patient_MSE.values()) - sortedkeys = np.asarray(patient_MSE.keys())[order].tolist() - sortedvalues = np.asarray(patient_MSE.values())[order].tolist() - patient_MSE = [(k, v) for k, v in zip(sortedkeys, sortedvalues)] - - for p in patient_MSE: - print(p[0], p[1]) - - stats["Patient_MSE"] = patient_MSE - - if show_plots: - # TODO: Plot metrics, see also plot_SVM - pass - - return stats
                        - - -
                        [docs]def main(): - if len(sys.argv) == 1: - prediction = '/media/martijn/DATA/CLM_MICCAI/Results/classification_all_SVR.hdf5' - label_data = '/home/martijn/git/RadTools/CLM_MICCAI/pinfo_CLM_MICCAI_test_months.txt' - label_type = 'KM' - survival = True - elif len(sys.argv) != 3: - raise IOError("This function accepts two arguments") - else: - prediction = sys.argv[1] - label_data = sys.argv[2] - plot_single_SVR(prediction, label_data, label_type, survival)
                        - - -if __name__ == '__main__': - main() -
                        - -
                        - -
                        -
                        - - -
                        - -
                        -

                        - © Copyright 2016 -- 2019, Biomedical Imaging Group Rotterdam, Departments of Medical Informatics and Radiology, Erasmus MC, Rotterdam, The Netherlands - -

                        -
                        - Built with Sphinx using a theme provided by Read the Docs. - -
                        - -
                        -
                        - -
                        - -
                        - - - - - - - - - - - - \ No newline at end of file diff --git a/build/lib/WORC/doc/_build/html/_modules/WORC/plotting/plot_barchart.html b/build/lib/WORC/doc/_build/html/_modules/WORC/plotting/plot_barchart.html deleted file mode 100644 index 8e62d5f6..00000000 --- a/build/lib/WORC/doc/_build/html/_modules/WORC/plotting/plot_barchart.html +++ /dev/null @@ -1,565 +0,0 @@ - - - - - - - - - - - WORC.plotting.plot_barchart — WORC 3.0.0 documentation - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
                        - - - -
                        - - - - - -
                        - -
                        - - - - - - - - - - - - - - - - - -
                        - -
                          - -
                        • Docs »
                        • - -
                        • Module code »
                        • - -
                        • WORC.plotting.plot_barchart
                        • - - -
                        • - -
                        • - -
                        - - -
                        -
                        -
                        -
                        - -

                        Source code for WORC.plotting.plot_barchart

                        -#!/usr/bin/env python
                        -
                        -# Copyright 2016-2019 Biomedical Imaging Group Rotterdam, Departments of
                        -# Medical Informatics and Radiology, Erasmus MC, Rotterdam, The Netherlands
                        -#
                        -# 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 matplotlib
                        -matplotlib.use('agg')
                        -import matplotlib.pyplot as plt
                        -
                        -from matplotlib2tikz import save as tikz_save
                        -import numpy as np
                        -import pandas as pd
                        -from collections import Counter
                        -import argparse
                        -
                        -
                        -
                        [docs]def plot_barchart(prediction, estimators=10, label_type=None, output_tex=None, - output_png=None): - ''' - Make a barchart of the top X hyperparameters settings of the ranked - estimators in all cross validation iterations. - - Parameters - ---------- - prediction: filepath, mandatory - Path pointing to the .hdf5 file which was is the output of the - trainclassifier function. - - estimators: integer, default 10 - Number of hyperparameter settings/estimators used in each cross - validation. The settings are ranked, so when supplying e.g. 10, - the best 10 settings in each cross validation setting will be used. - - label_type: string, default None - The name of the label predicted by the estimator. If None, - the first label from the prediction file will be used. - - output_tex: filepath, optional - If given, the barchart will be written to this tex file. - - output_png: filepath, optional - If given, the barchart will be written to this png file. - - Returns - ---------- - fig: matplotlib figure - The figure in which the barchart is plotted. - - ''' - # Load input prediction - prediction = pd.read_hdf(prediction) - - # Determine for which label we extract the estimator - keys = prediction.keys() - if label_type is None: - label_type = keys[0] - - prediction = prediction[label_type] - - # Extract the parameter settings: - parameters = dict() - for n_crossval, est in enumerate(prediction.classifiers): - for n_setting in range(0, estimators): - # Extract parameter settings of nth estimator - parameters_all = est.cv_results_['params_all'][n_setting] - - # Stack settings in parameters dictionary - for k in parameters_all.keys(): - if k not in parameters.keys(): - parameters[k] = list() - parameters[k].append(parameters_all[k]) - - # Count for every parameter how many times a setting occurs - counts = count_parameters(parameters) - - # Normalize the values - normalization_factor = len(prediction.classifiers) * estimators - - # Make the barplot - fig = plot_bars(counts, normalization_factor) - - # Save the output - if output_tex is not None: - print('Saving barchart to {}.').format(output_tex) - tikz_save(output_tex) - - if output_png is not None: - print('Saving barchart to {}.').format(output_png) - fig.savefig(output_png, bbox_inches='tight', pad_inches=0, dpi=50)
                        - - -
                        [docs]def plot_bars(params, normalization_factor=None, figwidth=20, fontsize=20): - - # Fixing random state for reproducibility - np.random.seed(19680801) - - # Count how often feature groups are used - if 'texture_features' in params.keys(): - # Old approach: one hyperparameter for all texture featues - groups_temp = ['histogram', 'shape', 'orientation', 'semantic', - 'patient', 'log', 'vessel', 'phase', 'coliage'] - else: - groups_temp = ['histogram', 'shape', 'orientation', 'semantic', - 'patient', 'log', 'vessel', 'phase', 'coliage', - "texture_gabor", "texture_glcm", - "texture_glcmms", "texture_glrlm", - "texture_glszm", "texture_ngtdm", - "texture_lbp"] - ntimes_groups = list() - groups = list() - for key in groups_temp: - key += '_features' - if key in params.keys(): - # only append if the parameter is actually used - if 'True' in params[key].keys(): - ntimes_groups.append(params[key]['True']) - groups.append(key) - - # Count how often feature variance tresholding was used - if 'texture_features' in params.keys(): - # Old approach: one hyperparameter for all texture featues - # For the texture features, we have more options than simply True and False - texture_temp = ['True', 'LBP', 'GLCM', 'GLRLM', 'GLSZM', 'Gabor', 'NGTDM'] - texture = list() - ntimes_texture = list() - for key in texture_temp: - if key in params['texture_features'].keys(): - texture.append(key) - ntimes_texture.append(params['texture_features'][key]) - - # BUG: We did not put a all in the keys but a True, so replace - texture[texture.index('True')] = 'All' - - # # Normalize the values in order to not make figure to large - if normalization_factor is None: - normalization_factor = max(ntimes_groups + ntimes_texture) - normalization_factor = float(normalization_factor) # Needed for percentages - ntimes_groups = [x / normalization_factor for x in ntimes_groups] - if 'texture_features' in params.keys(): - ntimes_texture = [x / normalization_factor for x in ntimes_texture] - - # Create the figure for the barchart - plt.rcdefaults() - fig, ax = plt.subplots() - fig.set_figwidth(figwidth) - fig.set_figheight(figwidth/2) - ax.set_xlim(0, 1) - - # Determine positions of all the labels - y_pos = np.arange(len(groups)) - y_postick = np.arange(len(groups) + 1) - - # Normal features - colors = ['steelblue', 'lightskyblue'] - ax.barh(y_pos, ntimes_groups, align='center', - color=colors[0], ecolor='black') - ax.set_yticks(y_postick) - if 'texture_features' in params.keys(): - ax.set_yticklabels(groups + ['Texture']) - else: - ax.set_yticklabels(groups) - - ax.tick_params(axis='both', labelsize=fontsize) - ax.invert_yaxis() # labels read top-to-bottom - ax.set_xlabel('Percentage', fontsize=fontsize) - - if 'texture_features' in params.keys(): - # Texture features - left = 0 - y_pos = np.max(y_pos) + 1 - - j = 0 - for i in np.arange(len(texture)): - color = colors[j] - if j == 0: - j = 1 - else: - j = 0 - ax.barh(y_pos, ntimes_texture[i], align='center', - color=color, ecolor='black', left=left) - ax.text(left + ntimes_texture[i]/2, y_pos, - texture[i], ha='center', va='center', fontsize=fontsize - 2) - left += ntimes_texture[i] - - return fig
                        - - -
                        [docs]def count_parameters(parameters): - # Count for every parameter how many times a setting occurs - output = dict() - for setting, values in parameters.iteritems(): - output[setting] = dict() - c = Counter(values) - for k, v in zip(c.keys(), c.values()): - output[setting][k] = v - - return output
                        - - -
                        [docs]def paracheck(parameters): - # NOTE: Deprecated - output = dict() - # print parameters - - f = parameters['semantic_features'] - total = float(len(f)) - count_semantic = sum([i == 'True' for i in f]) - ratio_semantic = count_semantic/total - print("Semantic: " + str(ratio_semantic)) - output['semantic_features'] = ratio_semantic - - f = parameters['patient_features'] - count_patient = sum([i == 'True' for i in f]) - ratio_patient = count_patient/total - print("patient: " + str(ratio_patient)) - output['patient_features'] = ratio_patient - - f = parameters['orientation_features'] - count_orientation = sum([i == 'True' for i in f]) - ratio_orientation = count_orientation/total - print("orientation: " + str(ratio_orientation)) - output['orientation_features'] = ratio_orientation - - f = parameters['histogram_features'] - count_histogram = sum([i == 'True' for i in f]) - ratio_histogram = count_histogram/total - print("histogram: " + str(ratio_histogram)) - output['histogram_features'] = ratio_histogram - - f = parameters['shape_features'] - count_shape = sum([i == 'True' for i in f]) - ratio_shape = count_shape/total - print("shape: " + str(ratio_shape)) - output['shape_features'] = ratio_shape - - if 'coliage_features' in parameters.keys(): - f = parameters['coliage_features'] - count_coliage = sum([i == 'True' for i in f]) - ratio_coliage = count_coliage/total - print("coliage: " + str(ratio_coliage)) - output['coliage_features'] = ratio_coliage - - if 'phase_features' in parameters.keys(): - f = parameters['phase_features'] - count_phase = sum([i == 'True' for i in f]) - ratio_phase = count_phase/total - print("phase: " + str(ratio_phase)) - output['phase_features'] = ratio_phase - - if 'vessel_features' in parameters.keys(): - f = parameters['vessel_features'] - count_vessel = sum([i == 'True' for i in f]) - ratio_vessel = count_vessel/total - print("vessel: " + str(ratio_vessel)) - output['vessel_features'] = ratio_vessel - - if 'log_features' in parameters.keys(): - f = parameters['log_features'] - count_log = sum([i == 'True' for i in f]) - ratio_log = count_log/total - print("log: " + str(ratio_log)) - output['log_features'] = ratio_log - - f = parameters['texture_features'] - count_texture_all = sum([i == 'True' for i in f]) - ratio_texture_all = count_texture_all/total - print("texture_all: " + str(ratio_texture_all)) - output['texture_all_features'] = ratio_texture_all - - count_texture_no = sum([i == 'False' for i in f]) - ratio_texture_no = count_texture_no/total - print("texture_no: " + str(ratio_texture_no)) - output['texture_no_features'] = ratio_texture_no - - count_texture_Gabor = sum([i == 'Gabor' for i in f]) - ratio_texture_Gabor = count_texture_Gabor/total - print("texture_Gabor: " + str(ratio_texture_Gabor)) - output['texture_Gabor_features'] = ratio_texture_Gabor - - count_texture_LBP = sum([i == 'LBP' for i in f]) - ratio_texture_LBP = count_texture_LBP/total - print("texture_LBP: " + str(ratio_texture_LBP)) - output['texture_LBP_features'] = ratio_texture_LBP - - count_texture_GLCM = sum([i == 'GLCM' for i in f]) - ratio_texture_GLCM = count_texture_GLCM/total - print("texture_GLCM: " + str(ratio_texture_GLCM)) - output['texture_GLCM_features'] = ratio_texture_GLCM - - count_texture_GLRLM = sum([i == 'GLRLM' for i in f]) - ratio_texture_GLRLM = count_texture_GLRLM/total - print("texture_GLRLM: " + str(ratio_texture_GLRLM)) - output['texture_GLRLM_features'] = ratio_texture_GLRLM - - count_texture_GLSZM = sum([i == 'GLSZM' for i in f]) - ratio_texture_GLSZM = count_texture_GLSZM/total - print("texture_GLSZM: " + str(ratio_texture_GLSZM)) - output['texture_GLSZM_features'] = ratio_texture_GLSZM - - count_texture_NGTDM = sum([i == 'NGTDM' for i in f]) - ratio_texture_NGTDM = count_texture_NGTDM/total - print("texture_NGTDM: " + str(ratio_texture_NGTDM)) - output['texture_NGTDM_features'] = ratio_texture_NGTDM - - if 'degree' in parameters.keys(): - f = parameters['degree'] - print("Polynomial Degree: " + str(np.mean(f))) - output['polynomial_degree'] = np.mean(f) - - return output
                        - - -
                        [docs]def main(): - parser = argparse.ArgumentParser(description='Plot a Barchart.') - parser.add_argument('-prediction', '--prediction', metavar='prediction', - nargs='+', dest='prediction', type=str, required=True, - help='Prediction file (HDF)') - parser.add_argument('-estimators', '--estimators', metavar='estimator', - nargs='+', dest='estimators', type=str, required=False, - help='Number of estimators to evaluate in each cross validation.') - parser.add_argument('-label_type', '--label_type', metavar='label_type', - nargs='+', dest='label_type', type=str, required=False, - help='Key of the label which was predicted.') - parser.add_argument('-output_tex', '--output_tex', metavar='output_tex', - nargs='+', dest='output_tex', type=str, required=True, - help='Output file path (.tex)') - parser.add_argument('-output_png', '--output_png', metavar='output_png', - nargs='+', dest='output_png', type=str, required=True, - help='Output file path (.png)') - args = parser.parse_args() - - # Convert the inputs to the correct format - if type(args.prediction) is list: - args.prediction = ''.join(args.prediction) - - if type(args.output) is list: - args.output = ''.join(args.output) - - if type(args.estimators) is list: - args.estimators = int(args.estimators[0]) - - if type(args.label_type) is list: - args.label_type = ''.join(args.label_type) - - plot_barchart(prediction=args.prediction, - estimators=args.estimators, - label_type=args.label_type, - output_tex=args.output_tex, - output_png=args.output_png)
                        - - -if __name__ == '__main__': - main() -
                        - -
                        - -
                        -
                        - - -
                        - -
                        -

                        - © Copyright 2016 -- 2019, Biomedical Imaging Group Rotterdam, Departments of Medical Informatics and Radiology, Erasmus MC, Rotterdam, The Netherlands - -

                        -
                        - Built with Sphinx using a theme provided by Read the Docs. - -
                        - -
                        -
                        - -
                        - -
                        - - - - - - - - - - - - \ No newline at end of file diff --git a/build/lib/WORC/doc/_build/html/_modules/WORC/plotting/plot_boxplot.html b/build/lib/WORC/doc/_build/html/_modules/WORC/plotting/plot_boxplot.html deleted file mode 100644 index 7cff8a7c..00000000 --- a/build/lib/WORC/doc/_build/html/_modules/WORC/plotting/plot_boxplot.html +++ /dev/null @@ -1,374 +0,0 @@ - - - - - - - - - - - WORC.plotting.plot_boxplot — WORC 3.0.0 documentation - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
                        - - - -
                        - - - - - -
                        - -
                        - - - - - - - - - - - - - - - - - -
                        - -
                          - -
                        • Docs »
                        • - -
                        • Module code »
                        • - -
                        • WORC.plotting.plot_boxplot
                        • - - -
                        • - -
                        • - -
                        - - -
                        -
                        -
                        -
                        - -

                        Source code for WORC.plotting.plot_boxplot

                        -#!/usr/bin/env python
                        -
                        -# Copyright 2016-2019 Biomedical Imaging Group Rotterdam, Departments of
                        -# Medical Informatics and Radiology, Erasmus MC, Rotterdam, The Netherlands
                        -#
                        -# 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 matplotlib
                        -matplotlib.use('agg')
                        -import matplotlib.pyplot as plt
                        -
                        -import pandas as pd
                        -import argparse
                        -import WORC.processing.label_processing as lp
                        -import os
                        -import glob
                        -from natsort import natsorted
                        -import numpy as np
                        -
                        -
                        -
                        [docs]def main(): - parser = argparse.ArgumentParser(description='Radiomics results') - parser.add_argument('-feat', '--feat', metavar='feat', - nargs='+', dest='feat', type=str, required=True, - help='List of patient feature files (HDF)') - parser.add_argument('-class', '--class', metavar='class', - nargs='+', dest='classs', type=str, required=True, - help='Classification of patients (text)') - parser.add_argument('-label_type', '--label_type', metavar='label_type', - nargs='+', dest='label_type', type=str, required=True, - help='Name of the label that was predicted') - parser.add_argument('-out', '--out', metavar='out', - nargs='+', dest='out', type=str, required=True, - help='Output png file') - args = parser.parse_args() - - if type(args.classs) is list: - args.classs = ''.join(args.classs) - - if type(args.label_type) is list: - args.label_type = ''.join(args.label_type) - - if type(args.out) is list: - args.out = ''.join(args.out) - - if type(args.feat) is list and len(args.feat) == 1: - args.feat = ''.join(args.feat) - - if os.path.isdir(args.feat): - args.feat = glob.glob(args.feat + '/features_*.hdf5') - args.feat = natsorted(args.feat) - - # Read and stack the features - print("Reading features.") - image_features_temp = list() - for i_feat in range(len(args.feat)): - feat_temp = pd.read_hdf(args.feat[i_feat]) - feat_values = feat_temp.feature_values - feat_labels = feat_temp.feature_labels - - feat = {k: v for k, v in zip(feat_labels, feat_values)} - - image_features_temp.append(feat) - - # Get the labels and patient IDs - print("Reading class labels.") - label_type = args.label_type - label_data, image_features = lp.findlabeldata(args.classs, - label_type, - args.feat, - image_features_temp) - - generate_boxplots(image_features, label_data, args.out)
                        - - -
                        [docs]def generate_boxplots(image_features, label_data, outputfolder): - ''' - Generate boxplots of the feature values among different objects. - - Parameters - ---------- - features: list, mandatory - List with a dictionary of the feature labels and values for each patient. - - label_data: pandas dataframe, mandatory - Dataframe containing the labels of the objects. - - outputfolder: path, mandatory - Folder to which the output boxplots should be written. - - - ''' - labels = image_features[0].keys() - featvect = dict() - flab = dict() - for l in labels: - featvect[l] = {"all": [], "1": [], "0": []} - flab[l] = {"all": [], "1": [], "0": []} - - # Stack per feature type and class - print("Stacking features.") - label = label_data['label'].tolist()[0] - patient_IDs = label_data['patient_IDs'].tolist() - for imfeat, label, pid in zip(image_features, label, patient_IDs): - for fl in labels: - featvect[fl]['all'].append(imfeat[fl]) - flab[fl]['all'].append(pid) - if label[0] == 0: - featvect[fl]['0'].append(imfeat[fl]) - flab[fl]['0'].append(pid) - else: - featvect[fl]['1'].append(imfeat[fl]) - flab[fl]['1'].append(pid) - - # Create the boxplots - print("Generating boxplots.") - - # Split in 5x5 figures. - nfig = np.ceil(len(labels) / 25.0) - - labels = sorted(labels) - for fi in range(0, int(nfig)): - f = plt.figure() - fignum = 1 - for i in range(fi*25, min((fi+1)*25, len(labels))): - ax = plt.subplot(5, 5, fignum) - lab = labels[i] - plt.subplots_adjust(hspace=0.3, wspace=0.2) - ax.scatter(np.ones(len(featvect[lab]['all'])), - featvect[lab]['all'], - color='blue') - ax.scatter(np.ones(len(featvect[lab]['1']))*2.0, - featvect[lab]['1'], - color='red') - ax.scatter(np.ones(len(featvect[lab]['0']))*3.0, - featvect[lab]['0'], - color='green') - - plt.boxplot([featvect[lab]['all'], featvect[lab]['1'], featvect[lab]['0']]) - - fz = 5 # Works best after saving - ax.set_title(lab, fontsize=fz) - for tick in ax.xaxis.get_major_ticks(): - tick.label.set_fontsize(fz) - - for tick in ax.yaxis.get_major_ticks(): - tick.label.set_fontsize(fz) - - fignum += 1 - - # Maximize figure to get correct spacings - mng = plt.get_current_fig_manager() - mng.resize(*mng.window.maxsize()) - # plt.show() - - # High DTI to make sure we save the maximized image - fname = ('boxplot_{}.png').format(str(fi)) - outputname = os.path.join(outputfolder, fname) - f.savefig(outputname, dpi=600) - print(("Boxplot saved as {} !").format(outputname))
                        - - -if __name__ == '__main__': - main() -
                        - -
                        - -
                        -
                        - - -
                        - -
                        -

                        - © Copyright 2016 -- 2019, Biomedical Imaging Group Rotterdam, Departments of Medical Informatics and Radiology, Erasmus MC, Rotterdam, The Netherlands - -

                        -
                        - Built with Sphinx using a theme provided by Read the Docs. - -
                        - -
                        -
                        - -
                        - -
                        - - - - - - - - - - - - \ No newline at end of file diff --git a/build/lib/WORC/doc/_build/html/_modules/WORC/plotting/plot_images.html b/build/lib/WORC/doc/_build/html/_modules/WORC/plotting/plot_images.html deleted file mode 100644 index 012c9d95..00000000 --- a/build/lib/WORC/doc/_build/html/_modules/WORC/plotting/plot_images.html +++ /dev/null @@ -1,330 +0,0 @@ - - - - - - - - - - - WORC.plotting.plot_images — WORC 3.0.0 documentation - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
                        - - - -
                        - - - - - -
                        - -
                        - - - - - - - - - - - - - - - - - -
                        - -
                          - -
                        • Docs »
                        • - -
                        • Module code »
                        • - -
                        • WORC.plotting.plot_images
                        • - - -
                        • - -
                        • - -
                        - - -
                        -
                        -
                        -
                        - -

                        Source code for WORC.plotting.plot_images

                        -#!/usr/bin/env python
                        -
                        -# Copyright 2016-2019 Biomedical Imaging Group Rotterdam, Departments of
                        -# Medical Informatics and Radiology, Erasmus MC, Rotterdam, The Netherlands
                        -#
                        -# 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 matplotlib
                        -matplotlib.use('agg')
                        -import matplotlib.pyplot as plt
                        -
                        -import numpy as np
                        -from matplotlib.ticker import NullLocator
                        -import matplotlib.colors as colors
                        -import SimpleITK as sitk
                        -
                        -
                        -
                        [docs]def slicer(image, mask, output_name, output_name_zoom, thresholds=[-240, 160], - zoomfactor=4): - ''' - image and mask should both be arrays - ''' - - # Determine figure size by spacing - spacing = float(image.GetSpacing()[0]) - imsize = [float(image.GetSize()[0]), float(image.GetSize()[1])] - figsize = (imsize[0]*spacing/100.0, imsize[1]*spacing/100.0) - # dpi = int(200/spacing) - dpi = 100.0 - - # Convert images to numpy arrays - image = sitk.GetArrayFromImage(image) - mask = sitk.GetArrayFromImage(mask) - - # Determine which axial slice has the largest area - areas = np.sum(mask, axis=1).tolist() - max_ind = areas.index(max(areas)) - imslice = image[max_ind, :, :] - maskslice = mask[max_ind, :, :] - - # Threshold the image if desired - if thresholds: - imslice[imslice < thresholds[0]] = thresholds[0] - imslice[imslice > thresholds[1]] = thresholds[1] - - # Plot the image and overlay the mask - fig = plot_im_and_overlay(imslice, maskslice, figsize=figsize) - - # Save Output - fig.savefig(output_name, bbox_inches='tight', pad_inches=0, dpi=dpi) - - # Save some memory - del fig - - # Create a bounding box and save zoomed image - imslice, maskslice = bbox_2D(imslice, maskslice, padding=[20, 20]) - imsize = [float(imslice.shape[0]), float(imslice.shape[1])] - - # NOTE: As these zoomed images get small, we double the spacing - spacing = spacing * zoomfactor - figsize = (imsize[0]*spacing/100.0, imsize[1]*spacing/100.0) - fig = plot_im_and_overlay(imslice, maskslice, figsize=figsize) - fig.savefig(output_name_zoom, bbox_inches='tight', pad_inches=0, dpi=dpi) - plt.close('all') - - # Save some memory - del fig, image, mask - return imslice, maskslice
                        - - -
                        [docs]def plot_im_and_overlay(image, mask, figsize=(3, 3), alpha=0.15): - ''' - Plot an image in a matplotlib figure and overlay with a mask. - ''' - # Create a normalized colormap for the image and mask - imin = np.min(image) - imax = np.max(image) - norm_im = colors.Normalize(vmin=imin, vmax=imax, clip=False) - - cmap = plt.get_cmap("Reds") - cmap.set_under(color="white", alpha=0) - cmap.set_over(color="r", alpha=1) - normO = colors.Normalize(vmin=0.5, vmax=0.75, clip=False) - - # Plot and save the full image - fig = plt.figure(figsize=figsize) - ax = fig.add_subplot(1, 1, 1) - ax.imshow(image, cmap=plt.cm.gray, norm=norm_im, interpolation="bilinear") - ax.imshow(mask, cmap=cmap, norm=normO, alpha=alpha, interpolation="bilinear") - - # Set locator to zero to make sure padding is removed upon saving - ax.xaxis.set_major_locator(NullLocator()) - ax.yaxis.set_major_locator(NullLocator()) - - # Turn axis grid of - ax.axis('off') - - return fig
                        - - -
                        [docs]def bbox_2D(img, mask, padding=[1, 1], img2=None): - rows = np.any(mask, axis=1) - cols = np.any(mask, axis=0) - - rmin, rmax = np.where(rows)[0][[0, -1]] - cmin, cmax = np.where(cols)[0][[0, -1]] - - # print rmin, rmax, cmin, cmax - rmin = max(0, rmin - padding[0]) - rmax = min(img.shape[0], rmax+padding[0]+1) - cmin = max(0, cmin - padding[1]) - cmax = min(img.shape[1], cmax+padding[1]+1) - - img = img[rmin:rmax, cmin:cmax] - mask = mask[rmin:rmax, cmin:cmax] - if img2 is None: - return img, mask - else: - img2 = img2[rmin:rmax, cmin:cmax] - return img, mask, img2
                        -
                        - -
                        - -
                        -
                        - - -
                        - -
                        -

                        - © Copyright 2016 -- 2019, Biomedical Imaging Group Rotterdam, Departments of Medical Informatics and Radiology, Erasmus MC, Rotterdam, The Netherlands - -

                        -
                        - Built with Sphinx using a theme provided by Read the Docs. - -
                        - -
                        -
                        - -
                        - -
                        - - - - - - - - - - - - \ No newline at end of file diff --git a/build/lib/WORC/doc/_build/html/_modules/WORC/plotting/plot_ranked_scores.html b/build/lib/WORC/doc/_build/html/_modules/WORC/plotting/plot_ranked_scores.html deleted file mode 100644 index 4985a6e2..00000000 --- a/build/lib/WORC/doc/_build/html/_modules/WORC/plotting/plot_ranked_scores.html +++ /dev/null @@ -1,705 +0,0 @@ - - - - - - - - - - - WORC.plotting.plot_ranked_scores — WORC 3.0.0 documentation - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
                        - - - -
                        - - - - - -
                        - -
                        - - - - - - - - - - - - - - - - - -
                        - -
                          - -
                        • Docs »
                        • - -
                        • Module code »
                        • - -
                        • WORC.plotting.plot_ranked_scores
                        • - - -
                        • - -
                        • - -
                        - - -
                        -
                        -
                        -
                        - -

                        Source code for WORC.plotting.plot_ranked_scores

                        -#!/usr/bin/env python
                        -
                        -# Copyright 2016-2019 Biomedical Imaging Group Rotterdam, Departments of
                        -# Medical Informatics and Radiology, Erasmus MC, Rotterdam, The Netherlands
                        -#
                        -# 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 argparse
                        -import pandas as pd
                        -from WORC.plotting.plot_SVM import plot_SVM
                        -import WORC.processing.label_processing as lp
                        -import glob
                        -import numpy as np
                        -import csv
                        -import os
                        -import WORC.plotting.plot_images as pi
                        -import SimpleITK as sitk
                        -from WORC.addexceptions import WORCKeyError
                        -import zipfile
                        -
                        -
                        -# NOTE: Need to add thresholds of plot_ranked_images to arguments
                        -
                        -
                        -
                        [docs]def main(): - parser = argparse.ArgumentParser(description='Plot distances to hyperplane') - parser.add_argument('-estimator', '--estimator', metavar='est', - nargs='+', dest='est', type=str, required=True, - help='Path to HDF5 file containing a fitted estimator.') - parser.add_argument('-pinfo', '--pinfo', metavar='pinfo', - nargs='+', dest='pinfo', type=str, required=True, - help='Patient Info File (txt)') - parser.add_argument('-images', '--images', metavar='images', - nargs='+', dest='ims', type=str, required=True, - help='Images of patients (ITK Image files)') - parser.add_argument('-segmentations', '--segmentations', metavar='segmentations', - nargs='+', dest='segs', type=str, required=True, - help='Segmentations of patients (ITK Image files)') - parser.add_argument('-ensemble', '--ensemble', metavar='ensemble', - nargs='+', dest='ens', type=str, required=True, - help='Either length of ensemble (int) or Caruana (string)') - parser.add_argument('-label_type', '--label_type', metavar='label_type', - nargs='+', dest='label_type', type=str, required=True, - help='Label name that is predicted by estimator (string)') - parser.add_argument('-scores', '--scores', metavar='scores', - nargs='+', dest='scores', type=str, required=True, - help='Type of scoring: percentages or posteriors (string)') - parser.add_argument('-output_csv', '--output_csv', metavar='output_csv', - nargs='+', dest='output_csv', type=str, required=True, - help='Output file for scores (CSV).') - parser.add_argument('-output_zip', '--output_zip', metavar='output_zip', - nargs='+', dest='output_zip', type=str, required=True, - help='Output file for images (zip).') - args = parser.parse_args() - - # convert inputs that should be single arguments to lists - pinfo = args.pinfo - if type(pinfo) is list: - pinfo = ''.join(pinfo) - - estimator = args.est - if type(estimator) is list: - estimator = ''.join(estimator) - - ensemble = args.ens - if type(ensemble) is list: - ensemble = ''.join(ensemble) - - label_type = args.label_type - if type(label_type) is list: - label_type = ''.join(label_type) - - scores = args.scores - if type(scores) is list: - scores = ''.join(scores) - - output_csv = args.output_csv - if type(output_csv) is list: - output_csv = ''.join(output_csv) - - output_zip = args.output_zip - if type(output_zip) is list: - output_zip = ''.join(output_zip) - - plot_ranked_scores(estimator=estimator, - pinfo=pinfo, - label_type=label_type, - scores=scores, - images=args.ims, - segmentations=args.segs, - ensemble=ensemble, - output_csv=output_csv, - output_zip=output_zip)
                        - - -
                        [docs]def plot_ranked_percentages(estimator, pinfo, label_type=None, - ensemble=50, output_csv=None): - - # Read the inputs - prediction = pd.read_hdf(estimator) - label_type = prediction.keys()[0] # NOTE: Assume we want to have the first key - - # Determine the predicted score per patient - print('Determining score per patient.') - stats = plot_SVM(prediction, - pinfo, - label_type, - show_plots=False, - alpha=0.95, - ensemble=ensemble, - output='stats') - - percentages = stats['Percentages'] - ranking = np.argsort(percentages.values()) - ranked_percentages_temp = [percentages.values()[r] for r in ranking] - ranked_PIDs = [percentages.keys()[r] for r in ranking] - - ranked_percentages = list() - ranked_truths = list() - for r in ranked_percentages_temp: - id = r.index(':') - ranked_truths.append(float(r[0:id])) - ranked_percentages.append(float(r[id+2:-1])) - - # Write output to csv - if output_csv is not None: - print("Writing output scores to CSV.") - header = ['PatientID', 'TrueLabel', 'Percentage'] - with open(output_csv, 'wb') as csv_file: - writer = csv.writer(csv_file) - writer.writerow(header) - - for pid, truth, perc in zip(ranked_PIDs, ranked_truths, ranked_percentages): - towrite = [str(pid), str(truth), str(perc)] - writer.writerow(towrite) - - return ranked_percentages, ranked_truths, ranked_PIDs
                        - - -
                        [docs]def plot_ranked_images(pinfo, label_type, images, segmentations, ranked_truths, - ranked_scores, ranked_PIDs, output_zip=None, - output_itk=None, zoomfactor=4): - # Match the images to the label data - print('Matching image and segmentation data to labels.') - print(images) - label_data, images =\ - lp.findlabeldata(pinfo, - [[label_type]], - images, - images) - _, segmentations =\ - lp.findlabeldata(pinfo, - [[label_type]], - segmentations, - segmentations) - - PIDs_images = label_data['patient_IDs'].tolist() - PIDs_images = [i.lower() for i in PIDs_images] - del label_data - - # Order the images and segmentations in the scores ordering - ordering = list() - for pid in ranked_PIDs: - if pid in PIDs_images: - ordering.append(PIDs_images.index(pid)) - else: - print('[WORC Warning] Patient {} not in images list!').format(str(pid)) - - PIDs_images = [PIDs_images[i] for i in ordering] - images = [images[i] for i in ordering] - segmentations = [segmentations[i] for i in ordering] - - # Print the middle segmented slice from each patient based on ranking - print('Print the middle segmented slice from each patient based on ranking.') - if output_zip is not None: - zipf = zipfile.ZipFile(output_zip, - 'w', zipfile.ZIP_DEFLATED, allowZip64=True) - - if output_itk is not None: - # Determine spacing factor - print("Determining spacings factor.") - spacings_x = list() - spacings_y = list() - for idx, im in enumerate(images): - print(('Processing patient {} / {}: {}.').format(str(idx + 1), str(len(images)), PIDs_images[idx])) - im = sitk.ReadImage(im) - spacings_x.append(im.GetSpacing()[0]) - spacings_y.append(im.GetSpacing()[1]) - # NOTE: Used in future feature - resample = [min(spacings_x), min(spacings_y)] - - for idx in range(0, len(images)): - print(('Processing patient {} / {}: {}.').format(str(idx + 1), str(len(images)), PIDs_images[idx])) - im = sitk.ReadImage(images[idx]) - seg = sitk.ReadImage(segmentations[idx]) - pid = PIDs_images[idx] - fname = str(int(ranked_scores[idx])) + '_' + pid + '_TrueLabel_' + str(ranked_truths[idx]) + '_slice.png' - - if output_zip is not None: - output_name = os.path.join(os.path.dirname(output_zip), fname) - output_name_zoom = os.path.join(os.path.dirname(output_zip), 'zoom' + str(zoomfactor) + '_' + fname) - else: - output_name = None - output_name_zoom = None - - imslice, maskslice = pi.slicer(im, seg, output_name, - output_name_zoom, output_itk) - - if output_zip is not None: - # Print PNGs and comine in ZIP - zipf.write(output_name, fname) - zipf.write(output_name_zoom, 'zoom_' + fname) - os.remove(output_name) - os.remove(output_name_zoom) - - if output_itk is not None: - # Combine slices in 3D image - print('WIP') - - del im, seg, imslice, maskslice
                        - - -
                        [docs]def plot_ranked_posteriors(estimator, pinfo, label_type=None, - ensemble=50, output_csv=None): - # Read the inputs - prediction = pd.read_hdf(estimator) - if label_type is None: - # Assume we want to have the first key - label_type = prediction.keys()[0] - - # Determine the predicted score per patient - print('Determining posterior per patient.') - y_truths, y_scores, y_predictions, PIDs_scores =\ - plot_SVM(prediction, - pinfo, - label_type, - show_plots=False, - alpha=0.95, - ensemble=ensemble, - output='scores') - - # Extract all scores for each patient - print('Aggregating scores per patient over all crossval iterations.') - scores = dict() - truths = dict() - y_truths_flat = [item for sublist in y_truths for item in sublist] - y_scores_flat = [item for sublist in y_scores for item in sublist] - PIDs_scores_flat = [item for sublist in PIDs_scores for item in sublist] - for yt, ys, pid in zip(y_truths_flat, y_scores_flat, PIDs_scores_flat): - if pid not in scores.keys(): - # No scores yet for patient, create list - scores[pid] = list() - truths[pid] = yt - scores[pid].append(ys) - - # Take the mean for each patient and rank them - scores_means = dict() - maxlen = 0 - for pid in scores.keys(): - scores_means[pid] = np.mean(scores[pid]) - if len(scores[pid]) > maxlen: - maxlen = len(scores[pid]) - - ranking = np.argsort(scores_means.values()) - ranked_PIDs = [scores_means.keys()[r] for r in ranking] - - ranked_mean_scores = [scores_means[r] for r in ranked_PIDs] - ranked_scores = [scores[r] for r in ranked_PIDs] - ranked_truths = [truths[r] for r in ranked_PIDs] - - # Write output to csv - if output_csv is not None: - print("Writing output scores to CSV.") - header = ['PatientID', 'TrueLabel', 'Probability'] - for i in range(0, maxlen): - header.append('Score' + str(i+1)) - - with open(output_csv, 'wb') as csv_file: - writer = csv.writer(csv_file) - writer.writerow(header) - - for pid, truth, smean, scores in zip(ranked_PIDs, ranked_truths, ranked_mean_scores, ranked_scores): - towrite = [str(pid), str(truth), str(smean)] - for s in scores: - towrite.append(str(s)) - - writer.writerow(towrite) - - return ranked_mean_scores, ranked_truths, ranked_PIDs
                        - - -
                        [docs]def plot_ranked_scores(estimator, pinfo, label_type, scores='percentages', - images=[], segmentations=[], ensemble=50, - output_csv=None, output_zip=None, output_itk=None): - ''' - Rank the patients according to their average score. The score can either - be the average posterior or the percentage of times the patient was - classified correctly in the cross validations. Additionally, - the middle slice of each patient is plot and saved according to the ranking. - - Parameters - ---------- - estimator: filepath, mandatory - Path pointing to the .hdf5 file which was is the output of the - trainclassifier function. - - pinfo: filepath, mandatory - Path pointint to the .txt file which contains the patient label - information. - - label_type: string, default None - The name of the label predicted by the estimator. If None, - the first label from the prediction file will be used. - - scores: string, default percentages - Type of scoring to be used. Either 'posteriors' or 'percentages'. - - images: list, optional - List containing the filepaths to the ITKImage image files of the - patients. - - segmentations: list, optional - List containing the filepaths to the ITKImage segmentation files of - the patients. - - ensemble: integer or string, optional - Method to be used for ensembling. Either an integer for a fixed size - or 'Caruana' for the Caruana method, see the SearchCV function for more - details. - - output_csv: filepath, optional - If given, the scores will be written to this csv file. - - output_zip: filepath, optional - If given, the images will be plotted and the pngs saved to this - zip file. - - output_itk: filepath, optional - WIP - - ''' - prediction = pd.read_hdf(estimator) - if label_type is None: - # Assume we want to have the first key - label_type = prediction.keys()[0] - - if scores == 'posteriors': - ranked_scores, ranked_truths, ranked_PIDs =\ - plot_ranked_posteriors(estimator=estimator, - pinfo=pinfo, - label_type=label_type, - ensemble=ensemble, - output_csv=output_csv) - elif scores == 'percentages': - ranked_scores, ranked_truths, ranked_PIDs =\ - plot_ranked_percentages(estimator=estimator, - pinfo=pinfo, - label_type=label_type, - ensemble=ensemble, - output_csv=output_csv) - else: - message = ('{} is not a valid scoring method!').format(str(scores)) - raise WORCKeyError(message) - - if output_zip is not None or output_itk is not None: - # Rerank the scores split per ground truth class: negative for 0, positive for 1 - ranked_scores_temp = list() - for l, p in zip(ranked_truths, ranked_scores): - if l == 0: - ranked_scores_temp.append(-p) - else: - ranked_scores_temp.append(p) - - ranked_scores = ranked_scores_temp - ranking = np.argsort(ranked_scores) - ranked_scores = [ranked_scores[r] for r in ranking] - ranked_truths = [ranked_truths[r] for r in ranking] - ranked_PIDs = [ranked_PIDs[r] for r in ranking] - - # Convert to lower to later on overcome matching errors - ranked_PIDs = [i.lower() for i in ranked_PIDs] - - plot_ranked_images(pinfo=pinfo, - label_type=label_type, - images=images, - segmentations=segmentations, - ranked_truths=ranked_truths, - ranked_scores=ranked_scores, - ranked_PIDs=ranked_PIDs, - output_zip=output_zip, - output_itk=output_itk)
                        - - -
                        [docs]def example(): - case = 'MESFIB' - if case == 'CLM': - label_type = None - estimator = '/media/martijn/DATA/tmp/classification_0_nonewfeat.hdf5' - ensemble = 50 - scores = 'percentages' - pinfo = '/home/martijn/git/RadTools/CLM/pinfo_CLM_KM.txt' - images_temp = glob.glob('/media/martijn/DATA/CLM/*/*/*/image.nii.gz') - segmentations = list() - images = list() - for i in images_temp: - segs = glob.glob(os.path.dirname(i) + '/seg_*session2*.nii.gz') - if len(segs) == 1: - segmentations.append(segs[0]) - images.append(i) - elif len(segs) > 1: - segmentations.append(segs[0]) - images.append(i) - else: - segs = glob.glob(os.path.dirname(i) + '/seg_*session1*.nii.gz') - if len(segs) == 1: - segmentations.append(segs[0]) - images.append(i) - elif len(segs) > 1: - segmentations.append(segs[0]) - images.append(i) - else: - print(i) - - output_csv = '/media/martijn/DATA/tmp/classification_0_nonewfeat_percentages.csv' - output_zip = '/media/martijn/DATA/tmp/classification_0_nonewfeat_percentages.zip' - elif case == 'MESFIB': - label_type = None - estimator = '/media/martijn/DATA/MESFIB/Results_0704/classification_100crossval_nonewfeat.hdf5' - ensemble = 50 - scores = 'percentages' - pinfo = '/home/martijn/git/RadTools/MESFIB/pinfo_MESFIB.txt' - images_temp = glob.glob('/media/martijn/DATA/MESFIB/*/*/*/image.nii.gz') - segmentations = list() - images = list() - for i in images_temp: - segs = glob.glob(os.path.dirname(i) + '/seg*Mass*.nii.gz') - if len(segs) == 1: - segmentations.append(segs[0]) - images.append(i) - elif len(segs) > 1: - segmentations.append(segs[0]) - images.append(i) - else: - segs = glob.glob(os.path.dirname(i) + '/seg_*mass*.nii.gz') - if len(segs) == 1: - segmentations.append(segs[0]) - images.append(i) - elif len(segs) > 1: - segmentations.append(segs[0]) - images.append(i) - else: - print(i) - - output_csv = '/media/martijn/DATA/MESFIB/Results_0704/classification_100crossval_nonewfeat_percentages.csv' - output_zip = '/media/martijn/DATA/MESFIB/Results_0704/classification_100crossval_nonewfeat_percentages.zip' - - prediction = pd.read_hdf(estimator) - if label_type is None: - # Assume we want to have the first key - label_type = prediction.keys()[0] - - if scores == 'posteriors': - ranked_scores, ranked_truths, ranked_PIDs =\ - plot_ranked_posteriors(estimator=estimator, - pinfo=pinfo, - label_type=label_type, - ensemble=ensemble, - output_csv=output_csv) - elif scores == 'percentages': - ranked_scores, ranked_truths, ranked_PIDs =\ - plot_ranked_percentages(estimator=estimator, - pinfo=pinfo, - label_type=label_type, - ensemble=ensemble, - output_csv=output_csv) - else: - message = ('{} is not a valid scoring method!').format(str(scores)) - raise WORCKeyError(message) - - if output_zip is not None: - # Convert to lower to later on overcome matching errors - ranked_PIDs = [i.lower() for i in ranked_PIDs] - - plot_ranked_images(pinfo=pinfo, - label_type=label_type, - images=images, - segmentations=segmentations, - ranked_truths=ranked_truths, - ranked_scores=ranked_scores, - ranked_PIDs=ranked_PIDs, - output_zip=output_zip)
                        - - -if __name__ == '__main__': - main() -
                        - -
                        - -
                        -
                        - - -
                        - -
                        -

                        - © Copyright 2016 -- 2019, Biomedical Imaging Group Rotterdam, Departments of Medical Informatics and Radiology, Erasmus MC, Rotterdam, The Netherlands - -

                        -
                        - Built with Sphinx using a theme provided by Read the Docs. - -
                        - -
                        -
                        - -
                        - -
                        - - - - - - - - - - - - \ No newline at end of file diff --git a/build/lib/WORC/doc/_build/html/_modules/WORC/processing/ExtractNLargestBlobsn.html b/build/lib/WORC/doc/_build/html/_modules/WORC/processing/ExtractNLargestBlobsn.html deleted file mode 100644 index 7fa9e83f..00000000 --- a/build/lib/WORC/doc/_build/html/_modules/WORC/processing/ExtractNLargestBlobsn.html +++ /dev/null @@ -1,270 +0,0 @@ - - - - - - - - - - - WORC.processing.ExtractNLargestBlobsn — WORC 3.0.0 documentation - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
                        - - - -
                        - - - - - -
                        - -
                        - - - - - - - - - - - - - - - - - -
                        - -
                          - -
                        • Docs »
                        • - -
                        • Module code »
                        • - -
                        • WORC.processing.ExtractNLargestBlobsn
                        • - - -
                        • - -
                        • - -
                        - - -
                        -
                        -
                        -
                        - -

                        Source code for WORC.processing.ExtractNLargestBlobsn

                        -#!/usr/bin/env python
                        -
                        -# Copyright 2016-2019 Biomedical Imaging Group Rotterdam, Departments of
                        -# Medical Informatics and Radiology, Erasmus MC, Rotterdam, The Netherlands
                        -#
                        -# 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.
                        -
                        -
                        -from skimage.measure import label, regionprops
                        -import numpy as np
                        -
                        -
                        -
                        [docs]def ExtractNLargestBlobsn(binaryImage, numberToExtract=1): - """Extract N largest blobs from binary image. - - Arguments: - binaryImage: boolean numpy array one or several contours. - numberToExtract: number of blobs to extract (integer). - - Returns: - binaryImage: boolean numpy are containing only the N - extracted blobs. - """ - - # Get all the blob properties. - labeledImage = label(binaryImage, connectivity=3) - blobMeasurements = regionprops(labeledImage) - - if len(blobMeasurements) == 1: - # Single blob, return input - binaryImage = binaryImage - else: - # Get all the areas - allAreas = list() - allCoords = list() - for blob in blobMeasurements: - allAreas.append(blob.area) - allCoords.append(blob.coords) - - allAreas = np.asarray(allAreas) - if numberToExtract > 0: - # For positive numbers, sort in order of largest to smallest. - # Sort them. - indices = np.argsort(-allAreas) - elif numberToExtract < 0: - # For negative numbers, sort in order of smallest to largest. - # Sort them. - indices = np.argsort(allAreas) - else: - raise ValueError("Number of blobs to extract should not be zero!") - - binaryImage = np.zeros(binaryImage.shape) - # NOTE: There must be a more efficient way to do this - for nblob in range(0, numberToExtract): - nblob = abs(nblob) - coords = allCoords[indices[nblob]] - for coord in coords: - binaryImage[coord[0], coord[1], coord[2]] = 1 - - return binaryImage
                        -
                        - -
                        - -
                        -
                        - - -
                        - -
                        -

                        - © Copyright 2016 -- 2019, Biomedical Imaging Group Rotterdam, Departments of Medical Informatics and Radiology, Erasmus MC, Rotterdam, The Netherlands - -

                        -
                        - Built with Sphinx using a theme provided by Read the Docs. - -
                        - -
                        -
                        - -
                        - -
                        - - - - - - - - - - - - \ No newline at end of file diff --git a/build/lib/WORC/doc/_build/html/_modules/WORC/processing/classes.html b/build/lib/WORC/doc/_build/html/_modules/WORC/processing/classes.html deleted file mode 100644 index 0cf4b11d..00000000 --- a/build/lib/WORC/doc/_build/html/_modules/WORC/processing/classes.html +++ /dev/null @@ -1,238 +0,0 @@ - - - - - - - - - - - WORC.processing.classes — WORC 3.0.0 documentation - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
                        - - - -
                        - - - - - -
                        - -
                        - - - - - - - - - - - - - - - - - -
                        - - - - -
                        -
                        -
                        -
                        - -

                        Source code for WORC.processing.classes

                        -#!/usr/bin/env python
                        -
                        -# Copyright 2016-2019 Biomedical Imaging Group Rotterdam, Departments of
                        -# Medical Informatics and Radiology, Erasmus MC, Rotterdam, The Netherlands
                        -#
                        -# 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.
                        -
                        -
                        -
                        [docs]class switch(object): - """ Object to mimic the MATLAB switch - case statement.""" -
                        [docs] def __init__(self, value): - self.value = value - self.fall = False
                        - -
                        [docs] def __iter__(self): - """Return the match method once, then stop""" - yield self.match - raise StopIteration
                        - -
                        [docs] def match(self, *args): - """Indicate whether or not to enter a case suite""" - if self.fall or not args: - return True - elif self.value in args: - self.fall = True - return True - else: - return False
                        -
                        - -
                        - -
                        -
                        - - -
                        - -
                        -

                        - © Copyright 2016 -- 2019, Biomedical Imaging Group Rotterdam, Departments of Medical Informatics and Radiology, Erasmus MC, Rotterdam, The Netherlands - -

                        -
                        - Built with Sphinx using a theme provided by Read the Docs. - -
                        - -
                        -
                        - -
                        - -
                        - - - - - - - - - - - - \ No newline at end of file diff --git a/build/lib/WORC/doc/_build/html/_modules/WORC/processing/label_processing.html b/build/lib/WORC/doc/_build/html/_modules/WORC/processing/label_processing.html deleted file mode 100644 index ccc4d2bb..00000000 --- a/build/lib/WORC/doc/_build/html/_modules/WORC/processing/label_processing.html +++ /dev/null @@ -1,485 +0,0 @@ - - - - - - - - - - - WORC.processing.label_processing — WORC 3.0.0 documentation - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
                        - - - -
                        - - - - - -
                        - -
                        - - - - - - - - - - - - - - - - - -
                        - -
                          - -
                        • Docs »
                        • - -
                        • Module code »
                        • - -
                        • WORC.processing.label_processing
                        • - - -
                        • - -
                        • - -
                        - - -
                        -
                        -
                        -
                        - -

                        Source code for WORC.processing.label_processing

                        -#!/usr/bin/env python
                        -
                        -# Copyright 2016-2019 Biomedical Imaging Group Rotterdam, Departments of
                        -# Medical Informatics and Radiology, Erasmus MC, Rotterdam, The Netherlands
                        -#
                        -# 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 xnat
                        -import requests
                        -from requests.packages.urllib3.exceptions import InsecureRequestWarning
                        -import numpy as np
                        -import os
                        -import configparser
                        -import WORC.addexceptions as ae
                        -import pandas as pd
                        -
                        -
                        -
                        [docs]def load_labels(label_file, label_type): - """Loads the label data from a label file - - Args: - label_file (string): The path to the label file - label_type (list): List of the names of the labels to load - - Returns: - dict: A dict containing 'patient_IDs', 'label' and - 'label_type' - """ - _, extension = os.path.splitext(label_file) - if extension == '.txt': - label_names, patient_IDs, label_status = load_label_txt( - label_file) - elif extension == '.csv': - label_names, patient_IDs, label_status = load_label_csv( - label_file) - elif extension == '.ini': - label_names, patient_IDs, label_status = load_label_XNAT( - label_file) - else: - raise ae.WORCIOError(extension + ' is not valid label file extension.') - - print("Label names to extract: " + str(label_type)) - labels = list() - for i_label in label_type: - label_index = np.where(label_names == i_label)[0] - if label_index.size == 0: - raise ae.WORCValueError('Could not find label: ' + str(i_label)) - else: - labels.append(label_status[:, label_index]) - - label_data = dict() - label_data['patient_IDs'] = patient_IDs - label_data['label'] = labels - label_data['label_name'] = label_type - - return label_data
                        - - -
                        [docs]def load_label_txt(input_file): - """ - Load the patient IDs and label data from the label file - - Args: - input_file (string): Path of the label file - - Returns: - label_names (numpy array): Names of the different labels - patient_ID (numpy array): IDs of patients for which label data is - loaded - label_status (numpy array): The status of the different labels - for each patient - """ - data = np.loadtxt(input_file, np.str) - - # Load and check the header - header = data[0, :] - if header[0] != 'Patient': - raise ae.WORCAssertionError('First column should be patient ID!') - else: - # cut out the first header, only keep label header - label_names = header[1::] - - # Patient IDs are stored in the first column - patient_ID = data[1:, 0] - - # label status is stored in all remaining columns - label_status = data[1:, 1:] - label_status = label_status.astype(np.float) - - return label_names, patient_ID, label_status
                        - - -
                        [docs]def load_label_csv(input_file): - """ - Load the patient IDs and label data from the label file - - Args: - input_file (string): Path of the label file - - Returns: - label_names (numpy array): Names of the different labels - patient_ID (numpy array): IDs of patients for which label data is - loaded - label_status (numpy array): The status of the different labels - for each patient - """ - data = pd.read_csv(input_file, header=0) - - # Load and check the header - header = data.keys() - if header[0] != 'Patient': - raise ae.WORCAssertionError('First column should be patient ID!') - else: - # cut out the first header, only keep label header - label_names = header[1::] - - # Patient IDs are stored in the first column - patient_ID = data['Patient'].values - - # label status is stored in all remaining columns - label_status = data.values[:, 1:] - label_status = label_status.astype(np.float) - - return label_names, patient_ID, label_status
                        - - -
                        [docs]def load_label_XNAT(label_info): - """ - Load the patient IDs and label data from XNAT, Only works if you have a - file /resources/GENETICS/files/genetics.json for each patient containing - a single dictionary of all labels. - - Args: - url (string): XNAT URL - project: XNAT project ID - - Returns: - label_names (numpy array): Names of the different labels - patient_ID (numpy array): IDs of patients for which label data is - loaded - label_status (numpy array): The status of the different labels - for each patient - """ - requests.packages.urllib3.disable_warnings(InsecureRequestWarning) - - config = load_config_XNAT(label_info) - url = config['XNAT']['url'] - projectID = config['XNAT']['projectID'] - - # Example - # url = "http://bigr-rad-xnat.erasmusmc.nl" - # projectID = 'LGG-Radiogenom' - # url = label_info['url'] - # projectID = label_info['projectID'] - - session = xnat.connect(url, verify=False) - - subkeys = session.projects[projectID].subjects.keys() - subkeys.sort() - session.disconnect() - - baseurl = url + '/data/archive/projects/' + projectID + '/subjects/' - patient_ID = list() - label_names = None - label_status = list() - for i_patient in subkeys: - # Extra check as there are bound to be some fake patients - if projectID in i_patient: - patient_ID.append(i_patient) - - data = requests.get(baseurl + i_patient + - '/resources/GENETICS/files/genetics.json') - datadict = data.json() - - # Load and check the header - if label_names is None: - label_names = list() - label_names_temp = datadict.keys() - for i_name in label_names_temp: - # convert u_str to str - label_names.append(str(i_name)) - - label_status_temp = datadict.values() - label_status.append(label_status_temp) - - label_names = np.asarray(label_names) - label_status = np.asarray(label_status) - - return label_names, patient_ID, label_status
                        - - -
                        [docs]def findlabeldata(patientinfo, label_type, filenames, - image_features_temp=None): - """ - Load the label data and match to the unage features. - - Args: - patientinfo (string): file with patient label data - label_type (string): name of the label read out from patientinfo - filenames (list): names of the patient feature files, used for matching - image_features (np.array or list): array of the features - - Returns: - label_data (dict): contains patient ids, their labels and the label name - """ - # Get the labels and patient IDs - label_data_temp = load_labels(patientinfo, label_type) - label_data = dict() - patient_IDs = list() - label_value = list() - for i_len in range(len(label_data_temp['label_name'])): - label_value.append(list()) - - # Check per feature file if there is a match in the label data - image_features = list() - for i_feat, feat in enumerate(filenames): - ifound = 0 - matches = list() - for i_num, i_patient in enumerate(label_data_temp['patient_IDs']): - if i_patient in str(feat): - - # Match: add the patient ID to the ID's and to the matches - patient_IDs.append(i_patient) - matches.append(i_patient) - - # If there are feature files given, add it to the list - if image_features_temp is not None: - image_features.append(image_features_temp[i_feat]) - - # For each label that we have, add the value to the label list - for i_len in range(len(label_data_temp['label_name'])): - label_value[i_len].append(label_data_temp['label'][i_len][i_num]) - - # Calculate how many matches we found for this (feature) file: should be one - ifound += 1 - - if ifound > 1: - message = ('Multiple matches ({}) found in labeling for feature file {}.').format(str(matches), str(feat)) - raise ae.WORCIOError(message) - - elif ifound == 0: - message = ('No entry found in labeling for feature file {}.').format(str(feat)) - raise ae.WORCIOError(message) - - # if image_features_temp is not None: - # image_features = np.asarray(image_features) - - # Convert to arrays - for i_len in range(len(label_value)): - label_value[i_len] = np.asarray(label_value[i_len]) - - label_data['patient_IDs'] = np.asarray(patient_IDs) - label_data['label'] = np.asarray(label_value) - label_data['label_name'] = label_data_temp['label_name'] - - return label_data, image_features
                        - - -
                        [docs]def load_config_XNAT(config_file_path): - ''' - Configparser for retreiving patient data from XNAT. - ''' - settings = configparser.ConfigParser() - settings.read(config_file_path) - - settings_dict = {'XNAT': dict()} - - settings_dict['XNAT']['url'] =\ - str(settings['Genetics']['url']) - - settings_dict['XNAT']['projectID'] =\ - str(settings['Genetics']['projectID']) - - return settings_dict
                        -
                        - -
                        - -
                        -
                        - - -
                        - -
                        -

                        - © Copyright 2016 -- 2019, Biomedical Imaging Group Rotterdam, Departments of Medical Informatics and Radiology, Erasmus MC, Rotterdam, The Netherlands - -

                        -
                        - Built with Sphinx using a theme provided by Read the Docs. - -
                        - -
                        -
                        - -
                        - -
                        - - - - - - - - - - - - \ No newline at end of file diff --git a/build/lib/WORC/doc/_build/html/_modules/WORC/resources/fastr_tests/CalcFeatures_test.html b/build/lib/WORC/doc/_build/html/_modules/WORC/resources/fastr_tests/CalcFeatures_test.html deleted file mode 100644 index 3c5f455b..00000000 --- a/build/lib/WORC/doc/_build/html/_modules/WORC/resources/fastr_tests/CalcFeatures_test.html +++ /dev/null @@ -1,272 +0,0 @@ - - - - - - - - - - - WORC.resources.fastr_tests.CalcFeatures_test — WORC 3.0.0 documentation - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
                        - - - -
                        - - - - - -
                        - -
                        - - - - - - - - - - - - - - - - - -
                        - -
                          - -
                        • Docs »
                        • - -
                        • Module code »
                        • - -
                        • WORC.resources.fastr_tests.CalcFeatures_test
                        • - - -
                        • - -
                        • - -
                        - - -
                        -
                        -
                        -
                        - -

                        Source code for WORC.resources.fastr_tests.CalcFeatures_test

                        -#!/usr/bin/env python
                        -
                        -# Copyright 2017-2018 Biomedical Imaging Group Rotterdam, Departments of
                        -# Medical Informatics and Radiology, Erasmus MC, Rotterdam, The Netherlands
                        -#
                        -# 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.
                        -
                        -IS_TEST = True
                        -
                        -
                        -
                        [docs]def create_network(): - # Import the faster environment and set it up - import fastr - - # Create a new network - network = fastr.Network(id_='CalcFeatures_test') - - # Create a source node in the network - source_segmentation = network.create_source('ITKImageFile', id_='segmentation') - source_image = network.create_source('ITKImageFile', id_='image') - source_metadata = network.create_source('DicomImageFile', id_='metadata') - source_parameters = network.create_source('ParameterFile', id_='parameters') - - # Create a new node in the network using toollist - node_calfeatures = network.create_node('CalcFeatures', id_="calcfeatures") - - # Create a link between the source output and an input of the addint node - node_calfeatures.inputs['segmentation'] = source_segmentation.output - node_calfeatures.inputs['image'] = source_image.output - node_calfeatures.inputs['metadata'] = source_metadata.output - node_calfeatures.inputs['parameters'] = source_parameters.output - - # Create a sink to save the data - sink_features = network.create_sink('HDF5', id_='features') - - # Link the addint node to the sink - sink_features.input = node_calfeatures.outputs['features'] - - return network
                        - - -
                        [docs]def source_data(network): - return {'segmentation': 'vfs://worc_example_data/CLM/seg_tumor_c.nii.gz', - 'image': 'vfs://worc_example_data/CLM/image.nii.gz', - 'metadata': 'vfs://worc_example_data/CLM/00000.dcm', - 'parameters': 'vfs://worc_example_data/CLM/parameters.ini'}
                        - - -
                        [docs]def sink_data(network): - return {'features': 'vfs://tmp/results/{}/calcfeatures_{{sample_id}}_{{cardinality}}{{ext}}'.format(network.id)}
                        - - -
                        [docs]def main(): - network = create_network() - - # Execute - # network.draw_network() - network.execute(source_data(network), sink_data(network), execution_plugin="ProcessPoolExecution")
                        - - -if __name__ == '__main__': - main() -
                        - -
                        - -
                        -
                        - - -
                        - -
                        -

                        - © Copyright 2016 -- 2019, Biomedical Imaging Group Rotterdam, Departments of Medical Informatics and Radiology, Erasmus MC, Rotterdam, The Netherlands - -

                        -
                        - Built with Sphinx using a theme provided by Read the Docs. - -
                        - -
                        -
                        - -
                        - -
                        - - - - - - - - - - - - \ No newline at end of file diff --git a/build/lib/WORC/doc/_build/html/_modules/WORC/resources/fastr_tests/elastix_test.html b/build/lib/WORC/doc/_build/html/_modules/WORC/resources/fastr_tests/elastix_test.html deleted file mode 100644 index 346940f6..00000000 --- a/build/lib/WORC/doc/_build/html/_modules/WORC/resources/fastr_tests/elastix_test.html +++ /dev/null @@ -1,273 +0,0 @@ - - - - - - - - - - - WORC.resources.fastr_tests.elastix_test — WORC 3.0.0 documentation - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
                        - - - -
                        - - - - - -
                        - -
                        - - - - - - - - - - - - - - - - - -
                        - -
                          - -
                        • Docs »
                        • - -
                        • Module code »
                        • - -
                        • WORC.resources.fastr_tests.elastix_test
                        • - - -
                        • - -
                        • - -
                        - - -
                        -
                        -
                        -
                        - -

                        Source code for WORC.resources.fastr_tests.elastix_test

                        -#!/usr/bin/env python
                        -
                        -# Copyright 2017-2018 Biomedical Imaging Group Rotterdam, Departments of
                        -# Medical Informatics and Radiology, Erasmus MC, Rotterdam, The Netherlands
                        -#
                        -# 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.
                        -
                        -IS_TEST = True
                        -
                        -
                        -
                        [docs]def create_network(): - # Import the faster environment and set it up - import fastr - - network = fastr.Network(id_="elastix_test") - - source1 = network.create_source('ITKImageFile', id_='fixed_img') - source2 = network.create_source('ITKImageFile', id_='moving_img') - param1 = network.create_source('ElastixParameterFile', id_='param_file') - - elastix_node = network.create_node('elastix_dev', id_='elastix') - elastix_node.inputs['fixed_image'] = source1.output - elastix_node.inputs['moving_image'] = source2.output - link_param = network.create_link(param1.output, elastix_node.inputs['parameters']) - link_param.converge = 0 - - outtrans = network.create_sink('ElastixTransformFile', id_='sink_trans') - outtrans.inputs['input'] = elastix_node.outputs['transform'] - - transformix_node = network.create_node('transformix_dev', id_='transformix') - transformix_node.inputs['image'] = source2.output - transformix_node.inputs['transform'] = elastix_node.outputs['transform'][-1] - - outimage = network.create_sink('ITKImageFile', id_='sink_image') - outimage.inputs['input'] = transformix_node.outputs['image'] - - network.draw_network(img_format='svg') - network.dumpf('{}.json'.format(network.id), indent=2) - - return network
                        - - -
                        [docs]def source_data(network): - return {'fixed_img': {'s1': 'vfs://worc_example_data/elastix/img0/slice047.mhd'}, - 'moving_img': {'s1': 'vfs://worc_example_data/elastix/img1/slice091.mhd'}, - 'param_file': ['vfs://worc_example_data/elastix/parAslice.txt', 'vfs://worc_example_data/elastix/parBslice.txt']}
                        - - -
                        [docs]def sink_data(network): - return {'sink_trans': 'vfs://tmp/results/{}/elastix_output_trans_{{sample_id}}_{{cardinality}}{{ext}}'.format(network.id), - 'sink_image': 'vfs://tmp/results/{}/elastix_output_image_{{sample_id}}_{{cardinality}}{{ext}}'.format(network.id)}
                        - - -
                        [docs]def main(): - network = create_network() - - # Execute - # network.draw_network() - network.execute(source_data(network), sink_data(network), execution_plugin="ProcessPoolExecution")
                        - - -if __name__ == '__main__': - main() -
                        - -
                        - -
                        -
                        - - -
                        - -
                        -

                        - © Copyright 2016 -- 2019, Biomedical Imaging Group Rotterdam, Departments of Medical Informatics and Radiology, Erasmus MC, Rotterdam, The Netherlands - -

                        -
                        - Built with Sphinx using a theme provided by Read the Docs. - -
                        - -
                        -
                        - -
                        - -
                        - - - - - - - - - - - - \ No newline at end of file diff --git a/build/lib/WORC/doc/_build/html/_modules/WORC/resources/fastr_tests/segmentix_test.html b/build/lib/WORC/doc/_build/html/_modules/WORC/resources/fastr_tests/segmentix_test.html deleted file mode 100644 index 02048499..00000000 --- a/build/lib/WORC/doc/_build/html/_modules/WORC/resources/fastr_tests/segmentix_test.html +++ /dev/null @@ -1,268 +0,0 @@ - - - - - - - - - - - WORC.resources.fastr_tests.segmentix_test — WORC 3.0.0 documentation - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
                        - - - -
                        - - - - - -
                        - -
                        - - - - - - - - - - - - - - - - - -
                        - -
                          - -
                        • Docs »
                        • - -
                        • Module code »
                        • - -
                        • WORC.resources.fastr_tests.segmentix_test
                        • - - -
                        • - -
                        • - -
                        - - -
                        -
                        -
                        -
                        - -

                        Source code for WORC.resources.fastr_tests.segmentix_test

                        -#!/usr/bin/env python
                        -
                        -# Copyright 2017-2018 Biomedical Imaging Group Rotterdam, Departments of
                        -# Medical Informatics and Radiology, Erasmus MC, Rotterdam, The Netherlands
                        -#
                        -# 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.
                        -
                        -IS_TEST = True
                        -
                        -
                        -
                        [docs]def create_network(): - # Import the faster environment and set it up - import fastr - # Create a new network - network = fastr.Network(id_='Segmentix_test') - - # Create a source node in the network - source_segmentation = network.create_source('ITKImageFile', id_='segmentation_in') - source_mask = network.create_source('ITKImageFile', id_='mask') - source_parameters = network.create_source('ParameterFile', id_='parameters') - - # Create a new node in the network using toollist - node_segmentix = network.create_node('Segmentix', id_="segmentix") - - # Create a link between the source output and an input of the addint node - node_segmentix.inputs['segmentation_in'] = source_segmentation.output - node_segmentix.inputs['mask'] = source_mask.output - node_segmentix.inputs['parameters'] = source_parameters.output - - # Create a sink to save the data - sink_segmentation = network.create_sink('ITKImageFile', id_='segmentation_out') - - # Link the addint node to the sink - sink_segmentation.input = node_segmentix.outputs['segmentation_out'] - - return network
                        - - -
                        [docs]def source_data(network): - return {'segmentation_in': 'vfs://worc_example_data/CLM/seg_liver.nii.gz', - 'mask': 'vfs://worc_example_data/CLM/seg_tumor.nii.gz', - 'parameters': 'vfs://worc_example_data/CLM/parameters.ini'}
                        - - -
                        [docs]def sink_data(network): - return {'segmentation_out': 'vfs://tmp/results/{}/segmentix_{{sample_id}}_{{cardinality}}{{ext}}'.format(network.id)}
                        - - -
                        [docs]def main(): - network = create_network() - - # Execute - # network.draw_network() - network.execute(source_data(network), sink_data(network), execution_plugin="ProcessPoolExecution")
                        - - -if __name__ == '__main__': - main() -
                        - -
                        - -
                        -
                        - - -
                        - -
                        -

                        - © Copyright 2016 -- 2019, Biomedical Imaging Group Rotterdam, Departments of Medical Informatics and Radiology, Erasmus MC, Rotterdam, The Netherlands - -

                        -
                        - Built with Sphinx using a theme provided by Read the Docs. - -
                        - -
                        -
                        - -
                        - -
                        - - - - - - - - - - - - \ No newline at end of file diff --git a/build/lib/WORC/doc/_build/html/_modules/WORC/tools/Elastix.html b/build/lib/WORC/doc/_build/html/_modules/WORC/tools/Elastix.html deleted file mode 100644 index c17742a1..00000000 --- a/build/lib/WORC/doc/_build/html/_modules/WORC/tools/Elastix.html +++ /dev/null @@ -1,512 +0,0 @@ - - - - - - - - - - - WORC.tools.Elastix — WORC 3.0.0 documentation - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
                        - - - -
                        - - - - - -
                        - -
                        - - - - - - - - - - - - - - - - - -
                        - - - - -
                        -
                        -
                        -
                        - -

                        Source code for WORC.tools.Elastix

                        -#!/usr/bin/env python
                        -
                        -# Copyright 2017-2018 Biomedical Imaging Group Rotterdam, Departments of
                        -# Medical Informatics and Radiology, Erasmus MC, Rotterdam, The Netherlands
                        -#
                        -# 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 SimpleITK as sitk
                        -import fastr
                        -import numpy as np
                        -import os
                        -import WORC.addexceptions as WORCexceptions
                        -
                        -
                        -
                        [docs]class Elastix(object): -
                        [docs] def __init__(self): - # Which version of elastix and transformix tools should be used - self.elastix_toolname = 'Elastix' - self.transformix_toolname = 'Transformix' - - # self.Elastix = sitk.SimpleElastix() - self.create_network('pairwise') - self.FixedImage = [] - self.MovingImage = [] - self.FixedMask = [] - self.MovingMask = [] - self.ToTransform = [] - self.ParameterMaps = [] # sitk.VectorOfParameterMap() - - self.TransformedImage = 'vfs://tmp/WORC_Elastix/results/elastix_output_image_{sample_id}_{cardinality}.nii.gz' - self.TransformedSeg = 'vfs://tmp/WORC_Elastix/results/elastix_output_seg_{sample_id}_{cardinality}.nii.gz' - self.TransformParameters = 'vfs://tmp/WORC_Elastix/results/elastix_output_trans_{sample_id}_{cardinality}.txt' - self.fastr_tmpdir = os.path.join(fastr.config.mounts['tmp'], 'WORC_Elastix')
                        - # TODO: Add initial transformation - -
                        [docs] def getparametermap(self, model='affine', size=(512, 512, 128)): - nvoxels = size[0]*size[1]*size[2] - if model == 'rigid': - parameter_map = sitk.GetDefaultParameterMap("rigid") - parameter_map["AutomaticTransformInitialization"] = ["true"] - parameter_map["Metric"] = ["AdvancedMattesMutualInformation"] - parameter_map["NumberOfResolutions"] = ["4"] # save time/memory - parameter_map["NumberOfSpatialSamples"] = [str(nvoxels*0.0001)] # save time/memory - parameter_map["MaximumNumberOfIterations"] = ["1000"] # save time/memory - parameter_map["WriteResultImage"] = ["true"] # save time/memory - parameter_map["ErodeMask"] = ["true"] - - elif model == 'affine': - parameter_map = sitk.GetDefaultParameterMap("affine") - parameter_map["AutomaticTransformInitialization"] = ["false"] - parameter_map["Metric"] = ["AdvancedMattesMutualInformation"] - parameter_map["NumberOfResolutions"] = ["4"] # save time/memory - parameter_map["NumberOfSpatialSamples"] = [str(nvoxels*0.0001)] # save time/memory - parameter_map["MaximumNumberOfIterations"] = ["1000"] # save time/memory - parameter_map["WriteResultImage"] = ["true"] # save time/memory - parameter_map["ErodeMask"] = ["true"] - - elif model == 'bspline': - parameter_map = sitk.GetDefaultParameterMap("bspline") - parameter_map["AutomaticTransformInitialization"] = ["false"] - # parameter_map["Metric"] = ["AdvancedMattesMutualInformation"] - parameter_map["Metric"] = ["AdvancedMattesMutualInformation", "TransformBendingEnergyPenalty"] - parameter_map["Metric0Weight"] = ["1.0"] - parameter_map["Metric1Weight"] = ["750.0"] # *100 is about 5 percent - parameter_map["NumberOfResolutions"] = ["4"] # save time/memory - parameter_map["NumberOfSpatialSamples"] = [str(nvoxels*0.0001)] # save time/memory - parameter_map["WriteResultImage"] = ["true"] # save time/memory - parameter_map["MaximumNumberOfIterations"] = ["1000"] # save time/memory - # parameter_map["ImageSampler"] = ["RandomSamplerSparseMask"] - parameter_map["ErodeMask"] = ["true"] - - else: - raise KeyError("Model {} cannot be found!").format(model) - - return parameter_map
                        - -
                        [docs] def create_network(self, nettype): - if nettype == 'pairwise': - # Create the network - self.network = fastr.Network(id_="elastix_pair") - - # Create Sources - self.FixedImageSource = self.network.create_source('ITKImageFile', id_='FixedImage') - self.FixedMaskSource = self.network.create_source('ITKImageFile', id_='FixedMask') - self.MovingImageSource = self.network.create_source('ITKImageFile', id_='MovingImage') - self.MovingMaskSource = self.network.create_source('ITKImageFile', id_='MovingMask') - self.ToTransformSource = self.network.create_source('ITKImageFile', id_='ToTransform') - self.ParameterMapSource = self.network.create_source('ElastixParameterFile', id_='ParameterMaps', nodegroup='par') - # Elastix requires the output folder as a sink - # self.OutputFolderSource = self.network.create_sink('Directory', id_='Out') - - # Create Elastix node and links - self.elastix_node = self.network.create_node(self.elastix_toolname, id_='elastix') - self.elastix_node.inputs['fixed_image'] = self.FixedImageSource.output - self.elastix_node.inputs['fixed_mask'] = self.FixedMaskSource.output - self.elastix_node.inputs['moving_image'] = self.MovingImageSource.output - self.elastix_node.inputs['moving_mask'] = self.MovingMaskSource.output - # self.OutputFolderSource.input = self.elastix_node.outputs['directory'] - self.link_param = self.network.create_link(self.ParameterMapSource.output, self.elastix_node.inputs['parameters']) - self.link_param.collapse = 'par' - - # Create Sinks - self.outtrans = self.network.create_sink('ElastixTransformFile', id_='sink_trans') - self.outimage = self.network.create_sink('ITKImageFile', id_='sink_image') - self.outseg = self.network.create_sink('ITKImageFile', id_='sink_seg') - self.outtrans.inputs['input'] = self.elastix_node.outputs['transform'] - - # Transform output image - self.transformix_node = self.network.create_node(self.transformix_toolname, id_='transformix') - self.transformix_node.inputs['image'] = self.MovingImageSource.output - self.transformix_node.inputs['transform'] = self.elastix_node.outputs['transform'][-1] - self.outimage.inputs['input'] = self.transformix_node.outputs['image'] - - # First change the FinalBSplineInterpolationOrder to 0 for the segmentation - self.changeorder_node = self.network.create_node('EditElastixTransformFile', id_='editelpara') - self.link_trans = self.network.create_link(self.elastix_node.outputs['transform'][-1], self.changeorder_node.inputs['transform']) - # self.link_trans.converge = 0 - # self.link_trans.collapse = 'FixedImage' - # self.link_trans.expand = True - - # Co[y metadata from image to segmentation as Elastix uses this - self.copymetadata_node = self.network.create_node('CopyMetadata', id_='copymetadata') - self.copymetadata_node.inputs['source'] = self.MovingImageSource.output - self.copymetadata_node.inputs['destination'] = self.ToTransformSource.output - - # Then transform the segmentation - self.transformix_node_seg = self.network.create_node(self.transformix_toolname, id_='transformix_seg') - self.transformix_node_seg.inputs['image'] = self.copymetadata_node.outputs['output'] - self.transformix_node_seg.inputs['transform'] = self.changeorder_node.outputs['transform'][-1] - self.outseg.inputs['input'] = self.transformix_node_seg.outputs['image'] - else: - # Create the network - self.network = fastr.Network(id_="elastix_group") - - # Create Sources - self.FixedImageSource = self.network.create_source('ITKImageFile', id_='FixedImage') - self.FixedMaskSource = self.network.create_source('ITKImageFile', id_='FixedMask') - self.ToTransformSource = self.network.create_source('ITKImageFile', id_='ToTransform') - self.ParameterMapSource = self.network.create_source('ElastixParameterFile', id_='ParameterMaps', nodegroup='par') - # Elastix requires the output folder as a sink - # self.OutputFolderSource = self.network.create_sink('Directory', id_='Out') - - # Create Elastix node and links - self.elastix_node = self.network.create_node(self.elastix_toolname, id_='elastix') - self.elastix_node.inputs['fixed_image'] = self.FixedImageSource.output - self.elastix_node.inputs['fixed_mask'] = self.FixedMaskSource.output - self.elastix_node.inputs['moving_image'] = self.FixedImageSource.output - self.elastix_node.inputs['moving_mask'] = self.FixedMaskSource.output - # self.OutputFolderSource.input = self.elastix_node.outputs['directory'] - self.link_param = self.network.create_link(self.ParameterMapSource.output, self.elastix_node.inputs['parameters']) - self.link_param.collapse = 'par' - - # Create Sinks - self.outtrans = self.network.create_sink('ElastixTransformFile', id_='sink_trans') - self.outimage = self.network.create_sink('ITKImageFile', id_='sink_image') - self.outseg = self.network.create_sink('ITKImageFile', id_='sink_seg') - self.outtrans.inputs['input'] = self.elastix_node.outputs['transform'] - - # Transform output image - self.transformix_node = self.network.create_node(self.transformix_toolname, id_='transformix') - self.transformix_node.inputs['image'] = self.MovingImageSource.output - self.transformix_node.inputs['transform'] = self.elastix_node.outputs['transform'][-1] - self.outimage.inputs['input'] = self.transformix_node.outputs['image'] - - # First change the FinalBSplineInterpolationOrder to 0 for the segmentation - self.changeorder_node = self.network.create_node('EditElastixTransformFile', id_='editelpara') - self.changeorder_node.inputs['set'] = ["FinalBSplineInterpolationOrder=0"] - self.link_trans = self.network.create_link(self.elastix_node.outputs['transform'], self.changeorder_node.inputs['transform'][-1]) - # self.link_trans.converge = 0 - # self.link_trans.collapse = 'FixedImage' - # self.link_trans.expand = True - - # Co[y metadata from image to segmentation as Elastix uses this - self.copymetadata_node = self.network.create_node('CopyMetadata', id_='copymetadata') - self.copymetadata_node.inputs['source'] = self.MovingImageSource.output - self.copymetadata_node.inputs['destination'] = self.ToTransformSource.output - - # Then transform the segmentation - self.transformix_node_seg = self.network.create_node(self.transformix_toolname, id_='transformix_seg') - self.transformix_node_seg.inputs['image'] = self.copymetadata_node.outputs['output'] - self.transformix_node_seg.inputs['transform'] = self.changeorder_node.outputs['transform'][-1] - self.outseg.inputs['input'] = self.transformix_node_seg.outputs['image']
                        - -
                        [docs] def addchangeorder(self): - # For the last file, change also the dependence on the previous files - N_parameterfiles = 1 - sources = list() - for num in range(0, N_parameterfiles): - if num != 0: - # We also need to refer to the correct initial transform files - intrans = 'InitialTransformParametersFileName=' +\ - os.path.join(self.fastr_tmpdir, 'editelpara', 'transform_' + str(num - 1) + '.txt') - sources.append("FinalBSplineInterpolationOrder=0" + intrans) - else: - sources.append("FinalBSplineInterpolationOrder=0") - - # self.set = self.network.create_source("AnyType", id_='setorder') - # self.source_data['setorder'] = sources - # self.changeorder_node.inputs['set'] = self.set.output - self.changeorder_node.inputs['set'] = sources
                        - -
                        [docs] def create_bbox(self, seg, pad=[2, 25, 25]): - ''' - Create a bounding box around an input segmentation - with a certain padding - ''' - segim = sitk.ReadImage(seg) - segim = sitk.GetArrayFromImage(segim) - segim[segim != 0] = 1 - - nonzero_x = np.nonzero(np.sum(segim, (1, 2)))[0] - nonzero_y = np.nonzero(np.sum(segim, (0, 2)))[0] - nonzero_z = np.nonzero(np.sum(segim, (0, 1)))[0] - - x1, x2 = nonzero_x[0], nonzero_x[-1] - y1, y2 = nonzero_y[0], nonzero_y[-1] - z1, z2 = nonzero_z[0], nonzero_z[-1] - mask = np.zeros(segim.shape) - x1 = max(0, x1 - pad[0]) - x2 = min(segim.shape[0], x2 + pad[0]) - y1 = max(0, y1 - pad[1]) - y2 = min(segim.shape[1], y2 + pad[1]) - z1 = max(0, z1 - pad[2]) - z2 = min(segim.shape[2], z2 + pad[2]) - mask[x1:x2, y1:y2, z1:z2] = 1 - mask = sitk.GetImageFromArray(mask) - - return mask
                        - -
                        [docs] def execute(self): - # Check if minimal input is supplied - if not self.FixedImage: - message = "You need to supply a fixed image for registration." - raise WORCexceptions.WORCNotImplementedError(message) - - if not self.MovingImage: - message = "You need to supply a moving image for registration." - raise WORCexceptions.WORCNotImplementedError(message) - - if len(self.ParameterMaps) == 0: - message = "You need to supply at leat one parameter map for registration." - raise WORCexceptions.WORCNotImplementedError(message) - - # Set moving and fixed image sources - self.source_data = dict() - self.source_data['FixedImage'] = self.FixedImage - self.source_data['MovingImage'] = self.MovingImage - - # Create a temporary directory to use - tempdir = os.path.join(fastr.config.mounts['tmp'], 'WORC_Elastix') - if not os.path.exists(tempdir): - os.makedirs(tempdir) - - # Set the parameter map sources - if type(self.ParameterMaps) is list: - # Files, thus just provide them to the elastix node - self.source_data['ParameterMaps'] = self.ParameterMaps - else: - # Use SimpleTransformix to save the maps and add them - SimpleElastix = sitk.SimpleElastix() - self.source_data['ParameterMaps'] = list() - for num, f in enumerate(self.ParameterMaps): - filename = ('ParameterMap{}.txt').format(str(num)) - fname = os.path.join(tempdir, filename) - SimpleElastix.WriteParameterFile(f, fname) - sourcename = 'vfs://tmp/WORC_Elastix/' + filename - self.source_data['ParameterMaps'].append(sourcename) - - # Based on number of parameterfiles, add nodes to train FinalBSplineInterpolationOrder - self.addchangeorder() - - # Set the mask sources if provided - # if self.FixedMask is not None: - self.source_data['FixedMask'] = self.FixedMask - - # if self.MovingMask is not None: - self.source_data['MovingMask'] = self.MovingMask - - # Add other images to transform if given - # if self.ToTransform is not None: - self.source_data['ToTransform'] = self.ToTransform - - # Set the network sinks - self.sink_data = dict() - self.sink_data['sink_trans'] = self.TransformParameters - self.sink_data['sink_image'] = self.TransformedImage - self.sink_data['sink_seg'] = self.TransformedSeg - - # Set outputfolder if given - # if self.OutputFolder: - # self.sink_data['Out'] = self.OutputFolder - # else: - # self.sink_data['Out'] = 'vfs://tmp/WORC_Elastix/output' - - # print self.sink_data['Out'] - - # Execute the network - self.network.draw_network('WORC_Elastix', img_format='svg', draw_dimension=True) - self.network.dumpf('{}.json'.format(self.network.id), indent=2) - self.network.execute(self.source_data, self.sink_data, tmpdir=self.fastr_tmpdir)
                        - - # Automatically read in the images (and parameter maps if requested?) -
                        - -
                        - -
                        -
                        - - -
                        - -
                        -

                        - © Copyright 2016 -- 2019, Biomedical Imaging Group Rotterdam, Departments of Medical Informatics and Radiology, Erasmus MC, Rotterdam, The Netherlands - -

                        -
                        - Built with Sphinx using a theme provided by Read the Docs. - -
                        - -
                        -
                        - -
                        - -
                        - - - - - - - - - - - - \ No newline at end of file diff --git a/build/lib/WORC/doc/_build/html/_modules/WORC/tools/Evaluate.html b/build/lib/WORC/doc/_build/html/_modules/WORC/tools/Evaluate.html deleted file mode 100644 index c50036b2..00000000 --- a/build/lib/WORC/doc/_build/html/_modules/WORC/tools/Evaluate.html +++ /dev/null @@ -1,459 +0,0 @@ - - - - - - - - - - - WORC.tools.Evaluate — WORC 3.0.0 documentation - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
                        - - - -
                        - - - - - -
                        - -
                        - - - - - - - - - - - - - - - - - -
                        - - - - -
                        -
                        -
                        -
                        - -

                        Source code for WORC.tools.Evaluate

                        -#!/usr/bin/env python
                        -
                        -# Copyright 2016-2019 Biomedical Imaging Group Rotterdam, Departments of
                        -# Medical Informatics and Radiology, Erasmus MC, Rotterdam, The Netherlands
                        -#
                        -# 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 WORC.addexceptions as WORCexceptions
                        -import fastr
                        -import os
                        -
                        -# NOTE: Very important to give images and segmentations as dict with patient names!
                        -
                        -
                        -
                        [docs]class Evaluate(object): -
                        [docs] def __init__(self, label_type, ensemble=50, scores='percentages', - network=None, features=None, - fastr_plugin='ProcessPoolExecution', - name='Example'): - ''' - Build a network that evaluates the performance of an estimator. - - Parameters - ---------- - - network: fastr network, default None - If you input a network, the evaluate network is added - to the existing network. - - ''' - if network is not None: - self.network = network - self.mode = 'WORC' - else: - self.mode = 'StandAlone' - self.fastr_plugin = fastr_plugin - self.name = 'WORC_Evaluate_' + name - self.network = fastr.Network(id_=self.name) - self.fastr_tmpdir = os.path.join(fastr.config.mounts['tmp'], self.name) - - if features is None and self.mode == 'StandAlone': - raise WORCexceptions.IOError('Either features as input or a WORC network is required for the Evaluate network.') - - self.features = features - - self.label_type = label_type - self.ensemble = ensemble - - self.create_network()
                        - -
                        [docs] def create_network(self): - ''' - Add evaluate components to network. - ''' - - # Create all nodes - self.network.node_ROC =\ - self.network.create_node('PlotROC', memory='20G', id_='plot_ROC') - self.network.node_SVM =\ - self.network.create_node('PlotSVM', memory='20G', id_='plot_SVM') - self.network.node_Barchart =\ - self.network.create_node('PlotBarchart', memory='4G', id_='plot_Barchart') - self.network.node_STest =\ - self.network.create_node('StatisticalTestFeatures', memory='4G', id_='statistical_test_features') - self.network.node_Ranked_Percentages =\ - self.network.create_node('PlotRankedScores', memory='20G', id_='plot_ranked_percentages') - self.network.node_Ranked_Posteriors =\ - self.network.create_node('PlotRankedScores', memory='20G', id_='plot_ranked_posteriors') - - # Create sinks - self.network.sink_ROC_PNG =\ - self.network.create_sink('PNGFile', id_='ROC_PNG') - self.network.sink_ROC_Tex =\ - self.network.create_sink('TexFile', id_='ROC_Tex') - self.network.sink_ROC_CSV =\ - self.network.create_sink('CSVFile', id_='ROC_CSV') - - self.network.sink_SVM_Json =\ - self.network.create_sink('JsonFile', id_='SVM_Json') - - self.network.sink_Barchart_PNG =\ - self.network.create_sink('PNGFile', id_='Barchart_PNG') - self.network.sink_Barchart_Tex =\ - self.network.create_sink('TexFile', id_='Barchart_Tex') - - self.network.sink_STest_CSV =\ - self.network.create_sink('CSVFile', id_='StatisticalTestFeatures_CSV') - - self.network.sink_Ranked_Percentages_Zip =\ - self.network.create_sink('ZipFile', id_='RankedPercentages_Zip') - self.network.sink_Ranked_Percentages_CSV =\ - self.network.create_sink('CSVFile', id_='RankedPercentages_CSV') - - self.network.sink_Ranked_Posteriors_Zip =\ - self.network.create_sink('ZipFile', id_='RankedPosteriors_Zip') - self.network.sink_Ranked_Posteriors_CSV =\ - self.network.create_sink('CSVFile', id_='RankedPosteriors_CSV') - - # Create links to sinks - self.network.sink_ROC_PNG.input = self.network.node_ROC.outputs['output_png'] - self.network.sink_ROC_Tex.input = self.network.node_ROC.outputs['output_tex'] - self.network.sink_ROC_CSV.input = self.network.node_ROC.outputs['output_csv'] - - self.network.sink_SVM_Json.input = self.network.node_SVM.outputs['output_json'] - - self.network.sink_Barchart_PNG.input = self.network.node_Barchart.outputs['output_png'] - self.network.sink_Barchart_Tex.input = self.network.node_Barchart.outputs['output_tex'] - - self.network.sink_STest_CSV.input = self.network.node_STest.outputs['performance'] - - self.network.sink_Ranked_Percentages_Zip.input = self.network.node_Ranked_Percentages.outputs['output_zip'] - self.network.sink_Ranked_Percentages_CSV.input = self.network.node_Ranked_Percentages.outputs['output_csv'] - - self.network.sink_Ranked_Posteriors_Zip.input = self.network.node_Ranked_Posteriors.outputs['output_zip'] - self.network.sink_Ranked_Posteriors_CSV.input = self.network.node_Ranked_Posteriors.outputs['output_csv'] - - # Create two constant nodes - self.network.node_Ranked_Percentages.inputs['scores'] = ['percentages'] - self.network.node_Ranked_Posteriors.inputs['scores'] = ['posteriors'] - - # Create sources that are not in WORC and set them - self.network.source_LabelType = self.network.create_source('String', id_='LabelType') - self.network.source_Ensemble = self.network.create_source('String', id_='Ensemble') - self.network.source_LabelType.input = [self.label_type] - self.network.source_Ensemble.input = [self.ensemble] - - # Create sources if not supplied by a WORC network - if self.mode == 'StandAlone': - self.network.source_Estimator = self.network.create_source('HDF5', id_='Estimator') - self.network.source_PatientInfo = self.network.create_source('PatientInfoFile', id_='PatientInfo') - self.network.source_Images = self.network.create_source('ITKImageFile', id_='Images', nodegroup='patients') - self.network.source_Segmentations = self.network.create_source('ITKImageFile', id_='Segmentations', nodegroup='patients') - self.network.source_Config = self.network.create_source('ParameterFile', id_='Config') - - self.labels = list() - self.network.source_Features = list() - for idx in range(0, len(self.features)): - label = 'Features_' + str(idx) - self.labels.append(label) - self.network.source_Features.append(self.network.create_source('HDF5', id_=label, nodegroup='features')) - - # Create links to sources that are not supplied by a WORC network - self.network.node_ROC.inputs['ensemble'] = self.network.source_Ensemble.output - self.network.node_ROC.inputs['label_type'] = self.network.source_LabelType.output - - self.network.node_SVM.inputs['ensemble'] = self.network.source_Ensemble.output - self.network.node_SVM.inputs['label_type'] = self.network.source_LabelType.output - - self.network.node_Barchart.inputs['estimators'] = self.network.source_Ensemble.output - self.network.node_Barchart.inputs['label_type'] = self.network.source_LabelType.output - - self.network.node_Ranked_Percentages.inputs['ensemble'] = self.network.source_Ensemble.output - self.network.node_Ranked_Percentages.inputs['label_type'] = self.network.source_LabelType.output - - self.network.node_Ranked_Posteriors.inputs['ensemble'] = self.network.source_Ensemble.output - self.network.node_Ranked_Posteriors.inputs['label_type'] = self.network.source_LabelType.output - - # Create links to the sources that could be in a WORC network - if self.mode == 'StandAlone': - # Sources from the Evaluate network are used - self.network.node_ROC.inputs['prediction'] = self.network.source_Estimator.output - self.network.node_ROC.inputs['pinfo'] = self.network.source_PatientInfo.output - - self.network.node_SVM.inputs['prediction'] = self.network.source_Estimator.output - self.network.node_SVM.inputs['pinfo'] = self.network.source_PatientInfo.output - - self.network.node_Barchart.inputs['prediction'] = self.network.source_Estimator.output - - self.network.links_STest_Features = list() - for idx, label in enumerate(self.labels): - self.network.links_STest_Features.append(self.network.node_STest.inputs['features'][str(label)] << self.network.source_Features[idx].output) - self.network.links_STest_Features[idx].collapse = 'features' - self.network.node_STest.inputs['patientclass'] = self.network.source_PatientInfo.output - self.network.node_STest.inputs['config'] = self.network.source_Config.output - - self.network.node_Ranked_Percentages.inputs['estimator'] = self.network.source_Estimator.output - self.network.node_Ranked_Percentages.inputs['pinfo'] = self.network.source_PatientInfo.output - self.network.link_images_perc = self.network.create_link(self.network.source_Images.output, self.network.node_Ranked_Percentages.inputs['images']) - self.network.link_images_perc.collapse = 'patients' - self.network.link_segmentations_perc = self.network.create_link(self.network.source_Segmentations.output, self.network.node_Ranked_Percentages.inputs['segmentations']) - self.network.link_segmentations_perc.collapse = 'patients' - - self.network.node_Ranked_Posteriors.inputs['estimator'] = self.network.source_Estimator.output - self.network.node_Ranked_Posteriors.inputs['pinfo'] = self.network.source_PatientInfo.output - self.network.link_images_post = self.network.create_link(self.network.source_Images.output, self.network.node_Ranked_Posteriors.inputs['images']) - self.network.link_images_post.collapse = 'patients' - self.network.link_segmentations_post = self.network.create_link(self.network.source_Segmentations.output, self.network.node_Ranked_Posteriors.inputs['segmentations']) - self.network.link_segmentations_post.collapse = 'patients' - else: - # Sources from the WORC network are used - print('WIP')
                        - -
                        [docs] def set(self, estimator=None, pinfo=None, images=None, - segmentations=None, config=None, features=None, - sink_data={}): - ''' - Set the sources and sinks based on the provided attributes. - ''' - if self.mode == 'StandAlone': - self.source_data = dict() - self.sink_data = dict() - - self.source_data['Estimator'] = estimator - self.source_data['PatientInfo'] = pinfo - self.source_data['Images'] = images - self.source_data['Segmentations'] = segmentations - self.source_data['Config'] = config - self.source_data['LabelType'] = self.label_type - self.source_data['Ensemble'] = self.ensemble - - for feature, label in zip(features, self.labels): - self.source_data[label] = feature - - if 'ROC_PNG' not in sink_data.keys(): - self.sink_data['ROC_PNG'] = ("vfs://output/{}/ROC_{{sample_id}}_{{cardinality}}{{ext}}").format(self.name) - if 'ROC_Tex' not in sink_data.keys(): - self.sink_data['ROC_Tex'] = ("vfs://output/{}/ROC_{{sample_id}}_{{cardinality}}{{ext}}").format(self.name) - if 'ROC_CSV' not in sink_data.keys(): - self.sink_data['ROC_CSV'] = ("vfs://output/{}/ROC_{{sample_id}}_{{cardinality}}{{ext}}").format(self.name) - - if 'SVM_Json' not in sink_data.keys(): - self.sink_data['SVM_Json'] = ("vfs://output/{}/performance_{{sample_id}}_{{cardinality}}{{ext}}").format(self.name) - - if 'Barchart_PNG' not in sink_data.keys(): - self.sink_data['Barchart_PNG'] = ("vfs://output/{}/Barchart_{{sample_id}}_{{cardinality}}{{ext}}").format(self.name) - if 'Barchart_Tex' not in sink_data.keys(): - self.sink_data['Barchart_Tex'] = ("vfs://output/{}/Barchart_{{sample_id}}_{{cardinality}}{{ext}}").format(self.name) - - if 'StatisticalTestFeatures_CSV' not in sink_data.keys(): - self.sink_data['StatisticalTestFeatures_CSV'] = ("vfs://output/{}/StatisticalTestFeatures_{{sample_id}}_{{cardinality}}{{ext}}").format(self.name) - - if 'RankedPercentages_Zip' not in sink_data.keys(): - self.sink_data['RankedPercentages_Zip'] = ("vfs://output/{}/RankedPercentages_{{sample_id}}_{{cardinality}}{{ext}}").format(self.name) - if 'RankedPercentages_CSV' not in sink_data.keys(): - self.sink_data['RankedPercentages_CSV'] = ("vfs://output/{}/RankedPercentages_{{sample_id}}_{{cardinality}}{{ext}}").format(self.name) - - if 'RankedPosteriors_Zip' not in sink_data.keys(): - self.sink_data['RankedPosteriors_Zip'] = ("vfs://output/{}/RankedPosteriors_{{sample_id}}_{{cardinality}}{{ext}}").format(self.name) - if 'RankedPosteriors_CSV' not in sink_data.keys(): - self.sink_data['RankedPosteriors_CSV'] = ("vfs://output/{}/RankedPosteriors_{{sample_id}}_{{cardinality}}{{ext}}").format(self.name) - - else: - print('[WORC Warning] Evaluate set attribute not needed when WORC network is provided!')
                        - -
                        [docs] def execute(self): - """ Execute the network through the fastr.network.execute command. """ - # Draw and execute nwtwork - self.network.draw_network(self.network.id, draw_dimension=True) - self.network.execute(self.source_data, self.sink_data, execution_plugin=self.fastr_plugin, tmpdir=self.fastr_tmpdir)
                        -
                        - -
                        - -
                        -
                        - - -
                        - -
                        -

                        - © Copyright 2016 -- 2019, Biomedical Imaging Group Rotterdam, Departments of Medical Informatics and Radiology, Erasmus MC, Rotterdam, The Netherlands - -

                        -
                        - Built with Sphinx using a theme provided by Read the Docs. - -
                        - -
                        -
                        - -
                        - -
                        - - - - - - - - - - - - \ No newline at end of file diff --git a/build/lib/WORC/doc/_build/html/_modules/WORC/tools/Slicer.html b/build/lib/WORC/doc/_build/html/_modules/WORC/tools/Slicer.html deleted file mode 100644 index 16ce175e..00000000 --- a/build/lib/WORC/doc/_build/html/_modules/WORC/tools/Slicer.html +++ /dev/null @@ -1,318 +0,0 @@ - - - - - - - - - - - WORC.tools.Slicer — WORC 3.0.0 documentation - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
                        - - - -
                        - - - - - -
                        - -
                        - - - - - - - - - - - - - - - - - -
                        - - - - -
                        -
                        -
                        -
                        - -

                        Source code for WORC.tools.Slicer

                        -#!/usr/bin/env python
                        -
                        -# Copyright 2016-2019 Biomedical Imaging Group Rotterdam, Departments of
                        -# Medical Informatics and Radiology, Erasmus MC, Rotterdam, The Netherlands
                        -#
                        -# 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 WORC.addexceptions as WORCexceptions
                        -import fastr
                        -import os
                        -
                        -
                        -
                        [docs]class Slicer(object): -
                        [docs] def __init__(self, images=None, segmentations=None, - network=None, - fastr_plugin='ProcessPoolExecution', - name='Example'): - ''' - Build a network that evaluates the performance of an estimator. - - Parameters - ---------- - - network: fastr network, default None - If you input a network, the evaluate network is added - to the existing network. - - ''' - if network is not None: - self.network = network - self.mode = 'WORC' - else: - self.mode = 'StandAlone' - self.fastr_plugin = fastr_plugin - self.name = 'WORC_Slicer_' + name - self.network = fastr.Network(id_=self.name) - self.fastr_tmpdir = os.path.join(fastr.config.mounts['tmp'], self.name) - - if images is None and self.mode == 'StandAlone': - message = 'Either images and segmentations as input or a WORC' +\ - 'network is required for the Evaluate network.' - raise WORCexceptions.IOError(message) - - self.image = images - self.segmentations = segmentations - - self.create_network()
                        - -
                        [docs] def create_network(self): - ''' - Add evaluate components to network. - ''' - - # Create all nodes - self.network.node_slicer =\ - self.network.create_node('Slicer', memory='20G', id_='Slicer') - - # Create sinks - self.network.sink_PNG =\ - self.network.create_sink('PNGFile', id_='PNG') - self.network.sink_PNGZoomed =\ - self.network.create_sink('PNGFile', id_='PNGZoomed') - - # Create links to sinks - self.network.sink_PNG.input = self.network.node_slicer.outputs['out'] - self.network.sink_PNGZoomed.input = self.network.node_slicer.outputs['outzoom'] - - # Create sources if not supplied by a WORC network - if self.mode == 'StandAlone': - self.network.source_images = self.network.create_source('ITKImage', id_='Images') - self.network.source_segmentations = self.network.create_source('ITKImage', id_='Segmentations') - - # Create links to sources that are not supplied by a WORC network - # Not needed in this network - - # Create links to the sources that could be in a WORC network - if self.mode == 'StandAlone': - # Sources from the Evaluate network are used - self.network.node_slicer.inputs['image'] = self.network.source_images.output - self.network.node_slicer.inputs['segmentation'] = self.network.source_segmentations.output - else: - # Sources from the WORC network are used - print('WIP')
                        - -
                        [docs] def set(self, images=None, segmentations=None, sink_data={}): - ''' - Set the sources and sinks based on the provided attributes. - ''' - if self.mode == 'StandAlone': - self.source_data = dict() - self.sink_data = dict() - - self.source_data['Images'] = images - self.source_data['Segmentations'] = segmentations - - if 'PNG' not in sink_data.keys(): - self.sink_data['PNG'] = ("vfs://output/{}/Slice_{{sample_id}}_{{cardinality}}{{ext}}").format(self.name) - if 'PNGZoomed' not in sink_data.keys(): - self.sink_data['PNGZoomed'] = ("vfs://output/{}/Slice_{{sample_id}}_{{cardinality}}_zoomed{{ext}}").format(self.name) - - else: - print('[WORC Warning] Slicer set attribute not needed when WORC network is provided!')
                        - -
                        [docs] def execute(self): - """ Execute the network through the fastr.network.execute command. """ - # Draw and execute nwtwork - self.network.draw_network(self.network.id, draw_dimension=True) - self.network.execute(self.source_data, self.sink_data, execution_plugin=self.fastr_plugin, tmpdir=self.fastr_tmpdir)
                        -
                        - -
                        - -
                        -
                        - - -
                        - -
                        -

                        - © Copyright 2016 -- 2019, Biomedical Imaging Group Rotterdam, Departments of Medical Informatics and Radiology, Erasmus MC, Rotterdam, The Netherlands - -

                        -
                        - Built with Sphinx using a theme provided by Read the Docs. - -
                        - -
                        -
                        - -
                        - -
                        - - - - - - - - - - - - \ No newline at end of file diff --git a/build/lib/WORC/doc/_build/html/_modules/WORC/tools/Transformix.html b/build/lib/WORC/doc/_build/html/_modules/WORC/tools/Transformix.html deleted file mode 100644 index 012fb4e9..00000000 --- a/build/lib/WORC/doc/_build/html/_modules/WORC/tools/Transformix.html +++ /dev/null @@ -1,249 +0,0 @@ - - - - - - - - - - - WORC.tools.Transformix — WORC 3.0.0 documentation - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
                        - - - -
                        - - - - - -
                        - -
                        - - - - - - - - - - - - - - - - - -
                        - - - - -
                        -
                        -
                        -
                        - -

                        Source code for WORC.tools.Transformix

                        -#!/usr/bin/env python
                        -
                        -# Copyright 2017-2018 Biomedical Imaging Group Rotterdam, Departments of
                        -# Medical Informatics and Radiology, Erasmus MC, Rotterdam, The Netherlands
                        -#
                        -# 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 SimpleITK as sitk
                        -import fastr
                        -import numpy as np
                        -import os
                        -import WORC.addexceptions as WORCexceptions
                        -
                        -#WIP
                        -
                        -
                        [docs]class Transformix(object): -
                        [docs] def __init__(self): - self.network = self.create_network() - self.MovingImage = None - self.TransformParameterMap = None
                        - -
                        [docs] def create_network(self): - self.network = fastr.Network(id_="transformix") - - self.MovingImageSource = self.network.create_source('ITKImageFile', id_='MovingImage') - self.ParameterMapSource = self.network.create_source('ElastixTransformFile', id_='ParameterFile') - - self.transformix_node = self.network.create_node('transformix_dev', id_='transformix') - self.transformix_node.inputs['image'] = self.MovingImageSource.output - self.transformix_node.inputs['transform'] = self.ParameterMapSource.output - - self.outimage = self.network.create_sink('ITKImageFile', id_='sink_image') - self.outimage.inputs['input'] = self.transformix_node.outputs['image'] - - self.network.draw_network(img_format='svg') - self.network.dumpf('{}.json'.format(self.network.id), indent=2)
                        - -
                        [docs] def execute(self): - SimpleTransformix = sitk.SimpleTransformix()
                        -
                        - -
                        - -
                        -
                        - - -
                        - -
                        -

                        - © Copyright 2016 -- 2019, Biomedical Imaging Group Rotterdam, Departments of Medical Informatics and Radiology, Erasmus MC, Rotterdam, The Netherlands - -

                        -
                        - Built with Sphinx using a theme provided by Read the Docs. - -
                        - -
                        -
                        - -
                        - -
                        - - - - - - - - - - - - \ No newline at end of file diff --git a/build/lib/WORC/doc/_build/html/_modules/fastr/api.html b/build/lib/WORC/doc/_build/html/_modules/fastr/api.html deleted file mode 100644 index b1adf136..00000000 --- a/build/lib/WORC/doc/_build/html/_modules/fastr/api.html +++ /dev/null @@ -1,947 +0,0 @@ - - - - - - - - - - - fastr.api — WORC 3.0.0 documentation - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
                        - - - -
                        - - - - - -
                        - -
                        - - - - - - - - - - - - - - - - - -
                        - - - - -
                        -
                        -
                        -
                        - -

                        Source code for fastr.api

                        -# Copyright 2011-2014 Biomedical Imaging Group Rotterdam, Departments of
                        -# Medical Informatics and Radiology, Erasmus MC, Rotterdam, The Netherlands
                        -#
                        -# 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.
                        -
                        -"""
                        -This module provides the API for fastr that users should use. This API will be
                        -considered stable between major versions. If users only interact via this API
                        -(and refrain from operating on ``parent`` attributes), their code should be
                        -compatible within major version of fastr.
                        -"""
                        -
                        -import datetime
                        -from typing import Any, Dict, Generic, Iterator, List, Mapping, Optional, Tuple, TypeVar, Union
                        -import os
                        -
                        -from .. import exceptions
                        -from ..planning.network import Network as CoreNetwork
                        -from ..planning.inputoutput import BaseInput, BaseOutput
                        -from ..core.resourcelimit import ResourceLimit
                        -from ..core.tool import Tool
                        -from ..core.version import Version
                        -from ..datatypes import BaseDataType
                        -from ..execution.networkrun import NetworkRun
                        -
                        -
                        -# Expose only the main functions to users, rest will follow from there
                        -__all__ = [
                        -    'create_network',
                        -    'create_network_copy',
                        -    'ResourceLimit',
                        -]
                        -
                        -
                        -CollapseType = Tuple[Union[int, str], ...]
                        -
                        -VersionType = Union[Version, str]
                        -
                        -DataTypeType = Union[BaseDataType, str]
                        -ToolType = Union[
                        -    Tool,
                        -    str,
                        -]
                        -
                        -# The data structure used for source data, base structure can be dict of list or dict
                        -SourceDataType = Dict[str, Union[
                        -    # List of values (str or tuple)
                        -    List[Union[str, Tuple[str, ...]]],
                        -
                        -    # Dict of str (id) -> value (str or tuple)
                        -    Dict[str, Union[str, Tuple[str, ...]]]
                        -]]
                        -
                        -# The data structure used for sink data
                        -SinkDataType = Union[str, Dict[str, str]]
                        -
                        -# Different data structures that describe a state
                        -NetworkStateType = Union['Network', CoreNetwork, dict]
                        -
                        -
                        -T = TypeVar("T")
                        -
                        -
                        -class SubObjectMap(Mapping[str, T], Generic[T]):
                        -    """
                        -    Generic object to retrieve wrapped objects from a collection
                        -    """
                        -    __slots__ = ('_parent', '_attribute', '_type')
                        -
                        -    def __init__(self, parent: Any, attribute: str, type_: type):
                        -        self._parent = parent
                        -        self._attribute = attribute
                        -        self._type = type_
                        -
                        -    def __repr__(self) -> str:
                        -        return '<{} map, items: {}>'.format(
                        -            self._type.__name__,
                        -            list(self.collection.keys())
                        -        )
                        -
                        -    def __iter__(self) -> Iterator[T]:
                        -        for key in self.collection.__iter__():
                        -            yield key
                        -
                        -    def __len__(self) -> int:
                        -        return len(self.collection)
                        -
                        -    def __getitem__(self, item) -> T:
                        -        return self._type(self.collection[item])
                        -
                        -    @property
                        -    def collection(self) -> Mapping[str, T]:
                        -        return getattr(self._parent.parent, self._attribute)
                        -
                        -
                        -class BaseWrapper:
                        -    """
                        -    Generic base class for wrapping fastr internal objects in a user-exposed
                        -    API objects.
                        -    """
                        -    __slots__ = ('_parent',)
                        -
                        -    def __init__(self, parent: Any):
                        -        self._parent = parent
                        -
                        -    def __repr__(self) -> str:
                        -        return repr(self.parent)
                        -
                        -    def __str__(self) -> str:
                        -        return str(self.parent)
                        -
                        -    @property
                        -    def id(self) -> str:
                        -        """
                        -        The unique id describing this resource
                        -        """
                        -        return self.parent.id
                        -
                        -    @property
                        -    def parent(self) -> Any:
                        -        """
                        -        The parent object for this wrapper. This point to a non-api object
                        -        in the internals of fastr and should not be used by normal users.
                        -        """
                        -        return self._parent
                        -
                        -
                        -def cast_basewrapper(value):
                        -    """
                        -    Cast a value to non have BaseWrappers. BaseWrappers will be replaced by their parent.
                        -    In Tuples each element is cast if needed.
                        -    """
                        -    if isinstance(value, BaseWrapper):
                        -        value = value.parent
                        -    elif isinstance(value, tuple):
                        -        value = tuple(x.parent if isinstance(x, BaseWrapper) else x for x in value)
                        -    return value
                        -
                        -
                        -
                        [docs]class Output(BaseWrapper): - """ - Representation of an Output of a Node - """ -
                        [docs] def __getitem__(self, item: Union[int, slice]) -> 'Output': - """ - Get a SubOuput of this Ouput. The SubOutput selects some data from the - parent Output based on an index or slice of the cardinalty. - - :param key: the key of the requested item, can be an index or slice - :return: the requested SubOutput with a view of the data in this Output - """ - return Output(self.parent.__getitem__(item))
                        - - -# The data structure that can be used for the source of linking -LinkSourceType = Union[Output, BaseOutput, list, dict, tuple] - - - - - -
                        [docs]class Input(BaseWrapper): - """ - Representation of an Input of a Node - """ - - def __getitem__(self, key: str) -> 'NamedSubInput': - if not isinstance(key, str): - raise ValueError('Can only manipulate named sub inputs directly') - - return NamedSubInput(self.parent[key]) - - def __setitem__(self, key: str, value): - if not isinstance(key, str): - raise ValueError('Can only manipulate named sub inputs directly') - - self.parent[key] = cast_basewrapper(value) - -
                        [docs] def append(self, value: LinkSourceType) -> Link: - """ - Create a link from give resource to a new SubInput. - - :param value: The source for the link to be created - :return: The newly created link - """ - return self.parent.append(cast_basewrapper(value))
                        - - @property - def input_group(self) -> str: - """ - The input group of this Input. This property can be read and changed. - Changing the input group of an Input will influence the data flow in - a Node (see :ref:`advanced-flow-node` for details). - """ - return self.parent.input_group - - @input_group.setter - def input_group(self, value: str): - self.parent.input_group = value - -
                        [docs] def __lshift__(self, other: LinkSourceType) -> Union[Link, Tuple[Link, ...]]: - """ - This operator allows the easy creation of Links to this Input using the ``<<`` operator. - Creating links can be done by: - - .. code-block:: python - - # Generic form - >> link = input << output - >> link = input << ['some', 'data'] # Create a constant node - - # Examples - >> link1 = addint.inputs['left_hand'] << source1.input - >> link2 = addint.inputs['right_hand'] << [1, 2, 3] - - # Mutliple links - >> links = addints.inputs['left_hand'] << (source1.output, source2.output, source3.output) - - The last example would return a tuple with three links. - - :param other: the target to create the link from, this can be an Output, a tuple of Outputs, or a data - structure that can be used as the data for a ConstantNode - :return: Newly created link(s) - """ - # Make sure wrappers are cast to non-wrappers - other = cast_basewrapper(other) - - return self.parent << other
                        - -
                        [docs] def __rrshift__(self, other: LinkSourceType) -> Union[Link, Tuple[Link, ...]]: - """ - This operator allows to use the ``>>`` operator as alternative to using the ``<<`` operator. - See the :py:meth:`__lshift__ operator <fastr.api.Input.__lshift__>` for details. - - :param other: the target to create the link from - :return: Newly created link(s) - """ - # Make sure wrappers are cast to non-wrappers - other = cast_basewrapper(other) - - return other >> self.parent
                        - - -class NamedSubInput(BaseWrapper): - """ - A named sub-input. This is only used in cases where a tool accepts a mapping - as an input. For example, if a command-line tool would accept:: - - --set key1=value1 key2=value2 - - Or something similar, where key1 and key2 are arbitrary strings. This can - be translated in fastr to:: - - tool.inputs['set']['key1'] << value1 - tool.inputs['set']['key2'] << value2 - - """ - def __lshift__(self, other: LinkSourceType) -> Union[Link, Tuple[Link, ...]]: - """ - This operator allows the easy creation of Links to this Input using the ``<<`` operator. - Creating links can be done by: - - .. code-block:: python - - # Generic form - >> link = input << output - >> link = input << ['some', 'data'] # Create a constant node - - # Examples - >> link1 = addint.inputs['left_hand'] << source1.input - >> link2 = addint.inputs['right_hand'] << [1, 2, 3] - - # Mutliple links - >> links = addints.inputs['left_hand'] << (source1.output, source2.output, source3.output) - - The last example would return a tuple with three links. - - :param other: the target to create the link from, this can be an Output, a tuple of Outputs, or a data - structure that can be used as the data for a ConstantNode - :return: Newly created link(s) - """ - # Make sure wrappers are cast to non-wrappers - other = cast_basewrapper(other) - - return self.parent << other - - def __rrshift__(self, other: LinkSourceType) -> Union[Link, Tuple[Link, ...]]: - """ - This operator allows to use the ``>>`` operator as alternative to using the ``<<`` operator. - See the :py:meth:`__lshift__ operator <fastr.api.Input.__lshift__>` for details. - - :param other: the target to create the link from - :return: Newly created link(s) - """ - # Make sure wrappers are cast to non-wrappers - other = cast_basewrapper(other) - - return other >> self.parent - - def append(self, value: LinkSourceType) -> Link: - """ - Create a link from give resource to a new SubInput. - - :param value: The source for the link to be created - :return: The newly created link - """ - return self.parent.append(cast_basewrapper(value)) - - - -
                        [docs]class Node(BaseWrapper): - """ - Representation of Node for editing the Network - """ - __slots__ = ('_inputs', '_outputs') - - def __init__(self, parent): - super().__init__(parent) - self._inputs = InputMap(self, 'inputs', Input) - self._outputs = SubObjectMap(self, 'outputs', Output) - - @property - def inputs(self) -> 'InputMap': - """ - Mapping object containing all Inputs of a Node - """ - return self._inputs - - @property - def outputs(self) -> SubObjectMap[Output]: - """ - Mapping object containing all Outputs of a Node - """ - return self._outputs - - @property - def input(self) -> Input: - """ - In case there is only a single Inputs in a Node, this can be used as a short hand. - In that case it is basically the same as ``list(node.inputs.values()[0])``. - """ - if len(self.inputs) == 1: - return next(iter(self.inputs.values())) - else: - raise KeyError('There is not 1 unique input, cannot use short-cut!') - - @input.setter - def input(self, value): - if len(self.inputs) == 1: - input = next(iter(self.inputs.values())) - input << value - else: - raise KeyError('There is not 1 unique input, cannot use short-cut!') - - @property - def output(self) -> Output: - """ - In case there is only a single Outputs in a Node, this can be used as a short hand. - In that case it is basically the same as ``list(node.outputs.values()[0])``. - """ - if len(self.outputs) == 1: - return next(iter(self.outputs.values())) - else: - raise KeyError('There is not 1 unique outputs, cannot use short-cut!') - - @property - def merge_dimensions(self) -> Union[str, Tuple[str, ...]]: - return self._parent.merge_dimensions - - @merge_dimensions.setter - def merge_dimensions(self, value: Union[str, Tuple[str, ...]]): - self._parent.merge_dimensions = value
                        - - -class InputMap(SubObjectMap[Input]): - def __setitem__(self, key, value): - # Make sure wrappers are cast to non-wrappers - value = cast_basewrapper(value) - self.collection[key] = value - - -
                        [docs]class Network(BaseWrapper): - """ - Representation of a Network for the creating and adapting Networks - """ - __slots__ = ('_node_map',) - - def __init__(self, id, version=None): - self._parent = CoreNetwork(id_=id, version=version) - self._node_map = SubObjectMap(self, 'nodelist', Node) - - @property - def nodes(self) -> SubObjectMap[Node]: - return self._node_map - - @property - def version(self) -> Version: - """ - Version of the Network (so users can keep track of their version) - """ - return self.parent.version - -
                        [docs] def create_node(self, - tool: ToolType, - tool_version: str, - id: str = None, - step_id: str = None, - resources: ResourceLimit = None, - node_group: str = None) -> Node: - """ - Create a Node in this Network. The Node will be automatically added to - the Network. - - :param tool: The Tool to base the Node on in the form: ``name/space/toolname:version`` - :param tool_version: The version of the tool wrapper to use - :param id: The id of the node to be created - :param step_id: The step to add the created node to - :param resources: The resources required to run this node - :param node_group: The group the node belongs to, this can be - important for FlowNodes and such, as they - will have matching dimension names. - :return: the newly created node - """ - - if not isinstance(tool, (str, Tool)): - raise exceptions.FastrTypeError('The tool argument should be either a Tool or a str') - - resources = resources or ResourceLimit() - return Node(self.parent.create_node( - tool=tool, - tool_version=tool_version, - id_=id, - stepid=step_id, - resources=resources.copy(), - nodegroup=node_group - ))
                        - -
                        [docs] def create_macro(self, - network: Union[NetworkStateType, Tool, str], - id: str = None) -> Node: - """ - Create macro node (a node which actually contains a network used as node - inside another network). - - :param network: The network to use, this can be a network (state), a - macro tool, or the path to a python file that contains - a function create_network which returns the desired - network. - :param id: The id of the node to be created - :return: the newly created node - """ - return Node(self.parent.create_macro(network=network, id_=id))
                        - -
                        [docs] def create_constant(self, - datatype: DataTypeType, - data: SourceDataType, - id: str = None, - step_id: str = None, - resources: ResourceLimit = None, - node_group: str = None) -> Node: - """ - Create a ConstantNode in this Network. The Node will be automatically added to - the Network. - - :param datatype: The DataType of the constant node - :param data: The data to hold in the constant node - :param id: The id of the constant node to be created - :param step_id: The step to add the created constant node to - :param resources: The resources required to run this node - :param node_group: The group the node belongs to, this can be - important for FlowNodes and such, as they - will have matching dimension names. - :return: the newly created constant node - """ - resources = resources or ResourceLimit() - return Node(self.parent.create_constant( - datatype=datatype, - data=data, - id_=id, - stepid=step_id, - resources=resources.copy(), - nodegroup=node_group - ))
                        - - - -
                        [docs] def create_source(self, - datatype: DataTypeType, - id: str = None, - step_id: str = None, - resources: ResourceLimit = None, - node_group: str = None) -> Node: - """ - Create a SourceNode in this Network. The Node will be automatically added to - the Network. - - :param datatype: The DataType of the source source_node - :type datatype: :py:class:`BaseDataType <fastr.plugins.managers.datatypemanager.BaseDataType>` - :param str id: The id of the source source_node to be created - :param str step_id: The step to add the created source source_node to - :param resources: The resources required to run this node - :param str node_group: The group the node belongs to, this can be - important for FlowNodes and such, as they - will have matching dimension names. - :return: the newly created source source_node - :rtype: :py:class:`SourceNode <fastr.core.source_node.SourceNode>` - """ - resources = resources or ResourceLimit() - return Node(self.parent.create_source( - datatype=datatype, - id_=id, - stepid=step_id, - resources=resources.copy(), - nodegroup=node_group - ))
                        - -
                        [docs] def create_sink(self, - datatype: DataTypeType, - id: str = None, - step_id: str = None, - resources: ResourceLimit = None, - node_group: str = None) -> Node: - """ - Create a SinkNode in this Network. The Node will be automatically added to - the Network. - - :param datatype: The DataType of the sink node - :param id: The id of the sink node to be created - :param step_id: The step to add the created sink node to - :param resources: The resources required to run this node - :param str node_group: The group the node belongs to, this can be - important for FlowNodes and such, as they - will have matching dimension names. - :return: the newly created sink node - """ - resources = resources or ResourceLimit() - return Node(self.parent.create_sink( - datatype=datatype, - id_=id, - stepid=step_id, - resources=resources.copy(), - nodegroup=node_group, - ))
                        - - def create_reference(self, - source_data: SourceDataType, - output_directory: str, - ): - """ - Create reference data to test a Network against - - :param source_data: The source data to use for the reference - :param output_directory: The directory to store the reference - """ - self._parent.create_reference(source_data=source_data, - output_directory=output_directory) - -
                        [docs] def draw(self, - file_path: str = None, - draw_dimensions: bool = True, - hide_unconnected: bool = True, - expand_macros: Union[bool, int] = 1, - font_size: int = 14) -> Optional[str]: - """ - Draw a graphical representation of the Network - - :param str file_path: The path of the file to create, the extension will control the image type - :param bool draw_dimensions: Flag to control if the dimension sizes should be drawn - in the figure, default is true - :param bool expand_macros: Flag to control if and how macro nodes should be expanded, - by default 1 level is expanded - :return: path of the image created or None if failed - """ - if file_path is not None: - file_path, ext = os.path.splitext(file_path) - else: - file_path = self.id - ext = 'svg' - - if not ext: - ext = 'svg' - - return self.parent.draw_network(name=file_path, - img_format=ext.lstrip('.'), - draw_dimension=draw_dimensions, - hide_unconnected=hide_unconnected, - expand_macro=expand_macros, - font_size=font_size)
                        - -
                        [docs] def execute(self, - source_data: SourceDataType, - sink_data: SinkDataType, - tmpdir: str = None, - timestamp: Union[datetime.datetime, str] = None, - blocking: bool = True, - execution_plugin: Optional[str] = None) -> NetworkRun: - """ - Execute the network with the given source and sink data. - - :param source_data: Source data to use as an input - :param sink_data: Sink rules to use for determining the outputs - :param tmpdir: The scratch directory to use for this network run, if - an existing directory is given, fastr will try to resume - a network run (see :ref:`continuing-network`) - :param timestamp: The timestamp of the network run (useful for retrying - or continuing previous runs) - :param blocking: Flag to indicate if the execution should be blocking - or launched in a background thread - :param execution_plugin: The execution plugin to use for this run - :return: The network run object for the started execution - """ - return self.parent.execute( - sourcedata=source_data, - sinkdata=sink_data, - tmpdir=tmpdir, - timestamp=timestamp, - blocking=blocking, - execution_plugin=execution_plugin, - )
                        - -
                        [docs] @classmethod - def load(cls, filename: str) -> 'Network': - """ - Load Network froma file - - :param str filename: - :return: loaded network - :rtype: Network - """ - result = BaseWrapper.__new__(Network) - - # Load Network and create correct node map - result._parent = CoreNetwork.loadf(filename) - result._node_map = SubObjectMap(result.parent, 'nodelist', Node) - - return result
                        - -
                        [docs] def save(self, - filename: str, - indent: int = 2): - """ - Save the Network to a JSON file - - :param filename: Path of the file to save to - :param indent: Indentation to use (None for no indentation) - """ - self.parent.dumpf(filename, method='json', indent=indent)
                        - - def is_valid(self): - return self._parent.is_valid()
                        - - -def create_network(id: str, - version: VersionType = None) -> Network: - """ - Create a new Network object - - :param id: id of the network - :param version: version of the network - :return: - """ - return Network(id=id, version=version) - - -def create_network_copy(network_state: NetworkStateType) -> Network: - """ - Create a network based on another Network state. The network state can be a Network - or the state gotten from a Network with __getstate__. - - :param network_state: Network (state) to create a copy of - :return: The rebuilt network - """ - if isinstance(network_state, Network): - network_state = network_state.parent - - if isinstance(network_state, CoreNetwork): - network_state = network_state.__getstate__() - - # Create the copy of the Network - result = BaseWrapper.__new__(Network) - result._parent = CoreNetwork.createobj(network_state) - result._node_map = SubObjectMap(result.parent, 'nodelist', Node) - - return result -
                        - -
                        - -
                        -
                        - - -
                        - -
                        -

                        - © Copyright 2016 -- 2019, Biomedical Imaging Group Rotterdam, Departments of Medical Informatics and Radiology, Erasmus MC, Rotterdam, The Netherlands - -

                        -
                        - Built with Sphinx using a theme provided by Read the Docs. - -
                        - -
                        -
                        - -
                        - -
                        - - - - - - - - - - - - \ No newline at end of file diff --git a/build/lib/WORC/doc/_build/html/_sources/autogen/WORC.IOparser.rst.txt b/build/lib/WORC/doc/_build/html/_sources/autogen/WORC.IOparser.rst.txt deleted file mode 100644 index a6744112..00000000 --- a/build/lib/WORC/doc/_build/html/_sources/autogen/WORC.IOparser.rst.txt +++ /dev/null @@ -1,48 +0,0 @@ -IOparser Package -================ - -:mod:`config_WORC` Module -------------------------- - -.. automodule:: WORC.IOparser.config_WORC - :members: - :undoc-members: - :show-inheritance: - :special-members: - -:mod:`config_io_classifier` Module ----------------------------------- - -.. automodule:: WORC.IOparser.config_io_classifier - :members: - :undoc-members: - :show-inheritance: - :special-members: - -:mod:`config_preprocessing` Module ----------------------------------- - -.. automodule:: WORC.IOparser.config_preprocessing - :members: - :undoc-members: - :show-inheritance: - :special-members: - -:mod:`config_segmentix` Module ------------------------------- - -.. automodule:: WORC.IOparser.config_segmentix - :members: - :undoc-members: - :show-inheritance: - :special-members: - -:mod:`file_io` Module ---------------------- - -.. automodule:: WORC.IOparser.file_io - :members: - :undoc-members: - :show-inheritance: - :special-members: - diff --git a/build/lib/WORC/doc/_build/html/_sources/autogen/WORC.classification.rst.txt b/build/lib/WORC/doc/_build/html/_sources/autogen/WORC.classification.rst.txt deleted file mode 100644 index 3e0ac848..00000000 --- a/build/lib/WORC/doc/_build/html/_sources/autogen/WORC.classification.rst.txt +++ /dev/null @@ -1,93 +0,0 @@ -classification Package -====================== - -:mod:`AdvancedSampler` Module ------------------------------ - -.. automodule:: WORC.classification.AdvancedSampler - :members: - :undoc-members: - :show-inheritance: - :special-members: - -:mod:`RankedSVM` Module ------------------------ - -.. automodule:: WORC.classification.RankedSVM - :members: - :undoc-members: - :show-inheritance: - :special-members: - -:mod:`SearchCV` Module ----------------------- - -.. automodule:: WORC.classification.SearchCV - :members: - :undoc-members: - :show-inheritance: - :special-members: - -:mod:`construct_classifier` Module ----------------------------------- - -.. automodule:: WORC.classification.construct_classifier - :members: - :undoc-members: - :show-inheritance: - :special-members: - -:mod:`crossval` Module ----------------------- - -.. automodule:: WORC.classification.crossval - :members: - :undoc-members: - :show-inheritance: - :special-members: - -:mod:`estimators` Module ------------------------- - -.. automodule:: WORC.classification.estimators - :members: - :undoc-members: - :show-inheritance: - :special-members: - -:mod:`fitandscore` Module -------------------------- - -.. automodule:: WORC.classification.fitandscore - :members: - :undoc-members: - :show-inheritance: - :special-members: - -:mod:`metrics` Module ---------------------- - -.. automodule:: WORC.classification.metrics - :members: - :undoc-members: - :show-inheritance: - :special-members: - -:mod:`parameter_optimization` Module ------------------------------------- - -.. automodule:: WORC.classification.parameter_optimization - :members: - :undoc-members: - :show-inheritance: - :special-members: - -:mod:`trainclassifier` Module ------------------------------ - -.. automodule:: WORC.classification.trainclassifier - :members: - :undoc-members: - :show-inheritance: - :special-members: - diff --git a/build/lib/WORC/doc/_build/html/_sources/autogen/WORC.featureprocessing.rst.txt b/build/lib/WORC/doc/_build/html/_sources/autogen/WORC.featureprocessing.rst.txt deleted file mode 100644 index 29ce3960..00000000 --- a/build/lib/WORC/doc/_build/html/_sources/autogen/WORC.featureprocessing.rst.txt +++ /dev/null @@ -1,75 +0,0 @@ -featureprocessing Package -========================= - -:mod:`featureprocessing` Package --------------------------------- - -.. automodule:: WORC.featureprocessing - :members: - :undoc-members: - :show-inheritance: - :special-members: - -:mod:`Imputer` Module ---------------------- - -.. automodule:: WORC.featureprocessing.Imputer - :members: - :undoc-members: - :show-inheritance: - :special-members: - -:mod:`Relief` Module --------------------- - -.. automodule:: WORC.featureprocessing.Relief - :members: - :undoc-members: - :show-inheritance: - :special-members: - -:mod:`SelectGroups` Module --------------------------- - -.. automodule:: WORC.featureprocessing.SelectGroups - :members: - :undoc-members: - :show-inheritance: - :special-members: - -:mod:`SelectIndividuals` Module -------------------------------- - -.. automodule:: WORC.featureprocessing.SelectIndividuals - :members: - :undoc-members: - :show-inheritance: - :special-members: - -:mod:`StatisticalTestFeatures` Module -------------------------------------- - -.. automodule:: WORC.featureprocessing.StatisticalTestFeatures - :members: - :undoc-members: - :show-inheritance: - :special-members: - -:mod:`StatisticalTestThreshold` Module --------------------------------------- - -.. automodule:: WORC.featureprocessing.StatisticalTestThreshold - :members: - :undoc-members: - :show-inheritance: - :special-members: - -:mod:`VarianceThreshold` Module -------------------------------- - -.. automodule:: WORC.featureprocessing.VarianceThreshold - :members: - :undoc-members: - :show-inheritance: - :special-members: - diff --git a/build/lib/WORC/doc/_build/html/_sources/autogen/WORC.plotting.rst.txt b/build/lib/WORC/doc/_build/html/_sources/autogen/WORC.plotting.rst.txt deleted file mode 100644 index 8cec5656..00000000 --- a/build/lib/WORC/doc/_build/html/_sources/autogen/WORC.plotting.rst.txt +++ /dev/null @@ -1,102 +0,0 @@ -plotting Package -================ - -:mod:`compute_CI` Module ------------------------- - -.. automodule:: WORC.plotting.compute_CI - :members: - :undoc-members: - :show-inheritance: - :special-members: - -:mod:`linstretch` Module ------------------------- - -.. automodule:: WORC.plotting.linstretch - :members: - :undoc-members: - :show-inheritance: - :special-members: - -:mod:`plot_ROC` Module ----------------------- - -.. automodule:: WORC.plotting.plot_ROC - :members: - :undoc-members: - :show-inheritance: - :special-members: - -:mod:`plot_SVM` Module ----------------------- - -.. automodule:: WORC.plotting.plot_SVM - :members: - :undoc-members: - :show-inheritance: - :special-members: - -:mod:`plot_SVR` Module ----------------------- - -.. automodule:: WORC.plotting.plot_SVR - :members: - :undoc-members: - :show-inheritance: - :special-members: - -:mod:`plot_barchart` Module ---------------------------- - -.. automodule:: WORC.plotting.plot_barchart - :members: - :undoc-members: - :show-inheritance: - :special-members: - -:mod:`plot_boxplot` Module --------------------------- - -.. automodule:: WORC.plotting.plot_boxplot - :members: - :undoc-members: - :show-inheritance: - :special-members: - -:mod:`plot_images` Module -------------------------- - -.. automodule:: WORC.plotting.plot_images - :members: - :undoc-members: - :show-inheritance: - :special-members: - -:mod:`plot_ranked_scores` Module --------------------------------- - -.. automodule:: WORC.plotting.plot_ranked_scores - :members: - :undoc-members: - :show-inheritance: - :special-members: - -:mod:`plotminmaxresponse` Module --------------------------------- - -.. automodule:: WORC.plotting.plotminmaxresponse - :members: - :undoc-members: - :show-inheritance: - :special-members: - -:mod:`scatterplot` Module -------------------------- - -.. automodule:: WORC.plotting.scatterplot - :members: - :undoc-members: - :show-inheritance: - :special-members: - diff --git a/build/lib/WORC/doc/_build/html/_sources/autogen/WORC.processing.rst.txt b/build/lib/WORC/doc/_build/html/_sources/autogen/WORC.processing.rst.txt deleted file mode 100644 index 3aa1f2c8..00000000 --- a/build/lib/WORC/doc/_build/html/_sources/autogen/WORC.processing.rst.txt +++ /dev/null @@ -1,39 +0,0 @@ -processing Package -================== - -:mod:`ExtractNLargestBlobsn` Module ------------------------------------ - -.. automodule:: WORC.processing.ExtractNLargestBlobsn - :members: - :undoc-members: - :show-inheritance: - :special-members: - -:mod:`RTStructReader` Module ----------------------------- - -.. automodule:: WORC.processing.RTStructReader - :members: - :undoc-members: - :show-inheritance: - :special-members: - -:mod:`classes` Module ---------------------- - -.. automodule:: WORC.processing.classes - :members: - :undoc-members: - :show-inheritance: - :special-members: - -:mod:`label_processing` Module ------------------------------- - -.. automodule:: WORC.processing.label_processing - :members: - :undoc-members: - :show-inheritance: - :special-members: - diff --git a/build/lib/WORC/doc/_build/html/_sources/autogen/WORC.resources.fastr_tests.rst.txt b/build/lib/WORC/doc/_build/html/_sources/autogen/WORC.resources.fastr_tests.rst.txt deleted file mode 100644 index 3832d1f8..00000000 --- a/build/lib/WORC/doc/_build/html/_sources/autogen/WORC.resources.fastr_tests.rst.txt +++ /dev/null @@ -1,30 +0,0 @@ -fastr_tests Package -=================== - -:mod:`CalcFeatures_test` Module -------------------------------- - -.. automodule:: WORC.resources.fastr_tests.CalcFeatures_test - :members: - :undoc-members: - :show-inheritance: - :special-members: - -:mod:`elastix_test` Module --------------------------- - -.. automodule:: WORC.resources.fastr_tests.elastix_test - :members: - :undoc-members: - :show-inheritance: - :special-members: - -:mod:`segmentix_test` Module ----------------------------- - -.. automodule:: WORC.resources.fastr_tests.segmentix_test - :members: - :undoc-members: - :show-inheritance: - :special-members: - diff --git a/build/lib/WORC/doc/_build/html/_sources/autogen/WORC.rst.txt b/build/lib/WORC/doc/_build/html/_sources/autogen/WORC.rst.txt deleted file mode 100644 index 7a6d477b..00000000 --- a/build/lib/WORC/doc/_build/html/_sources/autogen/WORC.rst.txt +++ /dev/null @@ -1,42 +0,0 @@ -WORC Package -============ - -:mod:`WORC` Package -------------------- - -.. automodule:: WORC.__init__ - :members: - :undoc-members: - :show-inheritance: - :special-members: - -:mod:`WORC` Module ------------------- - -.. automodule:: WORC.WORC - :members: - :undoc-members: - :show-inheritance: - :special-members: - -:mod:`addexceptions` Module ---------------------------- - -.. automodule:: WORC.addexceptions - :members: - :undoc-members: - :show-inheritance: - :special-members: - -Subpackages ------------ - -.. toctree:: - - WORC.IOparser - WORC.classification - WORC.featureprocessing - WORC.plotting - WORC.processing - WORC.tools - diff --git a/build/lib/WORC/doc/_build/html/_sources/autogen/WORC.tools.rst.txt b/build/lib/WORC/doc/_build/html/_sources/autogen/WORC.tools.rst.txt deleted file mode 100644 index 7649a737..00000000 --- a/build/lib/WORC/doc/_build/html/_sources/autogen/WORC.tools.rst.txt +++ /dev/null @@ -1,39 +0,0 @@ -tools Package -============= - -:mod:`Elastix` Module ---------------------- - -.. automodule:: WORC.tools.Elastix - :members: - :undoc-members: - :show-inheritance: - :special-members: - -:mod:`Evaluate` Module ----------------------- - -.. automodule:: WORC.tools.Evaluate - :members: - :undoc-members: - :show-inheritance: - :special-members: - -:mod:`Slicer` Module --------------------- - -.. automodule:: WORC.tools.Slicer - :members: - :undoc-members: - :show-inheritance: - :special-members: - -:mod:`Transformix` Module -------------------------- - -.. automodule:: WORC.tools.Transformix - :members: - :undoc-members: - :show-inheritance: - :special-members: - diff --git a/build/lib/WORC/doc/_build/html/_sources/index.rst.txt b/build/lib/WORC/doc/_build/html/_sources/index.rst.txt deleted file mode 100644 index 155c3206..00000000 --- a/build/lib/WORC/doc/_build/html/_sources/index.rst.txt +++ /dev/null @@ -1,95 +0,0 @@ -***** -WORC -***** - -Workflow for Optimal Radiomics Classification ---------------------------------------------- - -WORC is an open-source python package for the easy execution of end-to-end -radiomics pipelines. - -We aim to establish a general radiomics platform supporting easy -integration of other tools. With our modular build and support of -different software languages (Python, MATLAB, R, executables etc.), we want -to facilitate and stimulate collaboration, standardisation and -comparison of different radiomics approaches. By combining this in a -single framework, we hope to find an universal radiomics strategy that -can address various problems. - -WORC is open-source (licensed under the Apache 2.0 license) and hosted on Github at `https://github.com/MStarmans91/WORC `_ - -For support, go to the issues on the Gibhub page: `https://github.com/MStarmans91/WORC/issues `_ - -To get yourself a copy, see the :ref:`installation-chapter` - -The official documentation can be found at `WORC.readthedocs.io `_ - -For Tutorials on WORC, both for beginner and advanced WORCflows, please - -see our Tutorial repository https://github.com/MStarmans91/WORCTutorial. - - -The article on WORC is currently in press. WORC has been presented in the following: - - `M. P. A. Starmans, S. R. van der Voort, M. Vos, F. Incekara, J. J. Visser, M. Smits, M. G. Thomeer, W. J. Niessen and S. Klein. "Fully automatic construction of optimal radiomics workflows." European Conference of Radiology (ECR) 2019. `_ - - `Martijn P. A. Starmans, Sebastian R. van der Voort, Razvan L. Miclea, Melissa Vos, Fatih Incekara, Milea J.M. Timbergen, Maarten M.J. Wijnenga, Guillaume A. Padmos, G.H.J. van Leenders, George Kapsas, Martin J. van den Bent, Arnaud J.P.E. Vincent, Dirk J. Grünhagen, Cornelis Verhoef, Stefan Sleijfer, Jacob J. Visser, Marion Smits, Maarten, G. Thomeer, Wiro J. Niessen, and Stefan Klein. "Harmonizing radiomics among applications through adaptive workflow optimization." European Society of Medical Imaging Informatics (EuSoMII) Annual Meeting 2019. `_ - -WORC has been used in the following studies: - - `M. P. A. Starmans, R. Miclea, S. R. van der Voort, W. J. Niessen, M. G. Thomeer and S. Klein. "Classification of malignant and benign liver tumors using a radiomics approach." Proceedings Volume 10574, Medical Imaging 2018: Image Processing; 105741D (2018) . `_ - - `Milea J.M. Timbergen*, Martijn P. A. Starmans*, Melissa Vos, Sebastian R. van der Voort, Guillaume A. Padmos, Wouter Kessels, Wiro J. Niessen, Geert J.L.H. van Leenders, Dirk J. Grünhagen, Stefan Sleijfer, Cornelis Verhoef, Stefan Klein and Jacob J. Visser. "Mutation stratification of desmoid-type fibromatosis using a Radiomics approach." Desmoid Tumor Research Foundation (DTRF) 2018. `_ - - `Melissa Vos*, Martijn P. A. Starmans*, Milea J.M. Timbergen, Sebastian R. van der Voort, Guillaume A. Padmos, Wouter Kessels, Wiro J. Niessen, Geert J.L.H. van Leenders, Dirk J. Grünhagen, Stefan Sleijfer, Cornelis Verhoef, Stefan Klein and Jacob J. Visser. "Differentiating well-differentiated liposarcomas from lipomas using a Radiomics approach." ConnectiveTissueOncologySociety (CTOS) 2018.`_ - - `Milea J.M. Timbergen*, Martijn P. A. Starmans*, Melissa Vos, Sebastian R. van der Voort, Guillaume A. Padmos, Wouter Kessels, Wiro J. Niessen, Geert J.L.H. van Leenders, Dirk J. Grünhagen, Stefan Sleijfer, Cornelis Verhoef, Stefan Klein and Jacob J. Visser. "Mutation stratification of desmoid-type fibromatosis using a Radiomics approach." ConnectiveTissueOncologySociety (CTOS) 2018.`_ - - `Martijn P. A. Starmans, Sebastian R. van der Voort, Razvan L. Miclea, Melissa Vos, Fatih Incekara, Milea J.M. Timbergen, Maarten M.J. Wijnenga, Guillaume A. Padmos, Wouter Kessels, G.H.J. van Leenders, George Kapsas, Martin J. van den Bent, Arnaud J.P.E. Vincent, Dirk J. Grünhagen, Cornelis Verhoef, Stefan Sleijfer, Jacob J. Visser, Marion Smits, Maarten, G. Thomeer, Wiro J. Niessen, and Stefan Klein. "Fully Automatic Construction of Optimal Radiomics Workflows ." Bio-Medical Engineering (BME) Conference 2019. `_ - - `M. P. A. Starmans, R. Miclea, S. R. van der Voort, W. J. Niessen, S. Klein and M. G. Thomeer. "Classification of malignant and benign liver tumours using a radiomics approach." European Conference of Radiology (ECR) 2019. `_ - - `M. P. A. Starmans, A. Blazevic, S. R. van der Voort, T. Brabander, J. Hofland, W. J. Niessen, W. W. de Herder and S. Klein. "Prediction of surgery requirement in mesenteric fibrosis on CT using a radiomics approach." European Conference of Radiology (ECR) 2019. `_ - - `Jose M. Castillo T., Martijn P. A. Starmans, Ivo Schoots, Wiro J. Niessen, Stefan Klein, Jifke F. Veenland. "CLASSIFICATION OF PROSTATE CANCER: HIGH GRADE VERSUS LOW GRADE USING A RADIOMICS APPROACH." IEEE International Symposium on Biomedical Imaging (ISBI) 2019. `_ - -WORC is made possible by contributions from the following people: Martijn Starmans, and Stefan Klein - - -WORC Documentation -=================== -.. toctree:: - :maxdepth: 3 - :glob: - - static/introduction.rst - static/quick_start.rst - static/user_manual.rst - static/configuration.rst - static/file_description.rst - static/changelog.rst - -WORC User reference -==================== - -.. toctree:: - :maxdepth: 3 - :glob: - - user_reference/* - -WORC Developer Module reference -================================ -.. toctree:: - :maxdepth: 4 - - autogen/WORC - - - -Indices and tables -================== - -* :ref:`genindex` -* :ref:`modindex` -* :ref:`search` diff --git a/build/lib/WORC/doc/_build/html/_sources/static/changelog.rst.txt b/build/lib/WORC/doc/_build/html/_sources/static/changelog.rst.txt deleted file mode 100644 index c0fa1d43..00000000 --- a/build/lib/WORC/doc/_build/html/_sources/static/changelog.rst.txt +++ /dev/null @@ -1 +0,0 @@ -.. include:: ../../../CHANGELOG diff --git a/build/lib/WORC/doc/_build/html/_sources/static/configuration.rst.txt b/build/lib/WORC/doc/_build/html/_sources/static/configuration.rst.txt deleted file mode 100644 index a46085ab..00000000 --- a/build/lib/WORC/doc/_build/html/_sources/static/configuration.rst.txt +++ /dev/null @@ -1,216 +0,0 @@ -.. _config-chapter: - -Configuration -============= - - -As ``WORC`` and the default tools used are mostly Python based, we've chosen -to put our configuration in a ``configparser`` object. This has several -advantages: - -1. The object can be treated as a python dictionary and thus is easily adjusted. -2. Second, each tool can be set to parse only specific parts of the configuration, - enabling us to supply one file to all tools instead of needing many parameter files. - -The default configuration is generated through the -:py:meth:`WORC.defaultconfig() ` -function. You can then change things as you would in a dictionary and -then append it to the configs source: - - -.. code-block:: python - - >>> network = WORC.WORC('somename') - >>> config = network.defaultconfig() - >>> config['Classification']['classifier'] = 'RF' - >>> network.configs.append(config) - -When executing the :py:meth:`WORC.set() ` command, the config objects are saved as -.ini files in the ``WORC.fastr_tempdir`` folder and added to the -:py:meth:`WORC.fastrconfigs() ` source. - -Below are some details on several of the fields in the configuration. -Note that for many of the fields, we currently only provide one default -value. However, when adding your own tools, these fields can be adjusted -to your specific settings. - -WORC performs Combined Algorithm Selection and Hyperparameter (CASH) -optimization. The configuration determines how the optimization is -performed and which hyperparameters and models will be included. -Repeating specific models/parameters in the config will make them more -likely to be used, e.g. - -.. code-block:: python - - >>> config['Classification']['classifiers'] = 'SVM, SVM, LR' - -means that the SVM is 2x more likely to be tested in the model selection than LR. - -.. note:: - - All fields in the config must either be supplied as strings. A - list can be created by using commas for separation, e.g. - :py:meth:`Network.create_source <'value1, value2, ... ')>`. - - -General -------- - - -PREDICTGeneral --------------- - -These fields contain general settings for when using PREDICT. -For more info on the Joblib settings, which are used in the Joblib -Parallel function, see `here `__. When you run -WORC on a cluster with nodes supporting only a single core to be used -per node, e.g. the BIGR cluster, use only 1 core and threading as a -backend. - - - -Segmentix ---------- -These fields are only important if you specified using the segmentix -tool in the general configuration. - - -Preprocessing -------------- -The preprocessing node acts before the feature extraction on the image. -Currently, only normalization is included: hence the dictionary name is -*Normalize*. Additionally, scans with image type CT (see later in the -tutorial) provided as DICOM are scaled to Hounsfield Units. - - -Imagefeatures -------------- - -If using the PREDICT toolbox, you can specify some settings for the -feature computation here. Also, you can select if the certain features -are computed or not. - - -Featsel -------- - -When using the PREDICT toolbox for classification, these settings can be -used for feature selection methods. Note that these settings are -actually used in the hyperparameter optimization. Hence you can provide -multiple values per field, of which random samples will be drawn of -which finally the best setting in combination with the other -hyperparameters is selected. Again, these should be formatted as string -containing the actual values, e.g. value1, value2. - - -SelectFeatGroup ---------------- -If the PREDICT feature computation and classification tools are used, -then you can do a gridsearch among the various feature groups for the -optimal combination. If you do not want this, set all fields to a single -value. - -Previously, there was a single parameter for the texture features, -selecting all, none or a single group. This is still supported, but not -recommended, and looks as follows: - -Imputation ----------------- -When using the PREDICT toolbox for classification, these settings are -used for feature imputation.Note that these settings are actually used -in the hyperparameter optimization. Hence you can provide multiple -values per field, of which random samples will be drawn of which finally -the best setting in combination with the other hyperparameters is -selected. - - -Classification --------------- -When using the PREDICT toolbox for classification, you can specify the -following settings. Almost all of these are used in CASH. Most of the -classifiers are implemented using sklearn; hence descriptions of the -hyperparameters can also be found there. - - -CrossValidation ---------------- -When using the PREDICT toolbox for classification and you specified -using cross validation, specify the following settings. - -Labels --------- -When using the PREDICT toolbox for classification, you have to set the -label used for classification. - - -This part is really important, as it should match your label file. -Suppose your patientclass.txt file you supplied as source for labels -looks like this: - - -+----------+--------+--------+ -| Patient | Label1 | Label2 | -+==========+========+========+ -| patient1 | 1 | 0 | -+----------+--------+--------+ -| patient2 | 2 | 1 | -+----------+--------+--------+ -| patient3 | 1 | 5 | -+----------+--------+--------+ - -You can supply a single label or multiple labels split by commas, for -each of which an estimator will be fit. For example, suppose you simply -want to use Label1 for classification, then set: - - - -.. code-block:: python - - config['Labels']['label_names'] = 'Label1' - - -If you want to first train a classifier on Label1 and then Label2, -set: ``config[Genetics][label_names] = Label1, Label2`` - - - - -Hyperoptimization ------------------ -When using the PREDICT toolbox for classification, you have to supply -your hyperparameter optimization procedure here. - - -FeatureScaling --------------- -Determines which method is applied to scale each feature. - - - -SampleProcessing ----------------- -Before performing the hyperoptimization, you can use SMOTE: Synthetic -Minority Over-sampling Technique to oversample your data. - - - - - -Ensemble --------- -WORC supports ensembling of workflows. This is not a default approach in -radiomics, hence the default is to not use it and select only the best -performing workflow. - - - - -FASTR_bugs ----------- -Currently, when using XNAT as a source, FASTR can only retrieve DICOM -directories. We made a workaround for this for the images and -segmentations, but this only works if all your files have the same name -and extension. These are provided in this configuration part. - - -.. include:: ../autogen/WORC.config.rst \ No newline at end of file diff --git a/build/lib/WORC/doc/_build/html/_sources/static/development.rst.txt b/build/lib/WORC/doc/_build/html/_sources/static/development.rst.txt deleted file mode 100644 index 9d54eddd..00000000 --- a/build/lib/WORC/doc/_build/html/_sources/static/development.rst.txt +++ /dev/null @@ -1,361 +0,0 @@ -Development and Design Documentation -==================================== - -In this chapter we will discuss the design of Fastr in more detail. We give -pointers for development and add the design documents as we currently envision -Fastr. This is both for people who are interested in the Fastr develop and for -current developers to have an archive of the design decision agreed upon. - -Sample flow in Fastr --------------------- - -The current Sample flow is the following: - -.. graphviz:: - - digraph sampleflow { - Output [ - shape=plaintext - label=< - - - - - - -
                        OutputContainsSamples
                        - > - ]; - SubOutput [ - shape=plaintext - label=< - - - - - - -
                        SubOutputForwardsSamplesselects cardinality
                        - > - ]; - Link [ - shape=plaintext - label=< - - - - - - -
                        LinkForwardsSamplescollapse + expand (changes cardinality and dimensions)
                        - > - ]; - SubInput [ - shape=plaintext - label=< - - - - - - -
                        SubInputForwardsSamplesdirect forward
                        - > - ]; - Input [ - shape=plaintext - label=< - - - - - - -
                        InputForwardsSamplesbroadcast matching (combine samples in cardinality)
                        - > - ]; - InputGroup [ - shape=plaintext - label=< - - - - - - -
                        InputGroupForwardsSamplesbroadcast matching (combine samples in payload)
                        - > - ]; - NodeC [ - shape=plaintext - label=< - - - - - - -
                        NodeRunForwardsSamplescombines payloads (plugin based, e.g. cross product)
                        - > - ]; - - Output:port -> SubOutput:port [weight=25]; - Output:port -> Link:port [weight=10]; - SubOutput:port -> SubOutput:port [weight=0]; - SubOutput:port -> Link:port [weight=25]; - Link:port -> SubInput:port; - SubInput:port -> Input:port; - Input:port -> InputGroup:port; - InputGroup:port -> NodeC:port; - } - -The idea is that we make a common interface for all classes that are related -to the flow of Samples. For this we propose the following mixin classes that -provide the interface and allow for better code sharing. The basic structure -of the classes is given in the following diagram: - -.. graphviz:: - - digraph mixins { - node [ - fontname = "Bitstream Vera Sans" - fontsize = 9 - shape = "record" - ] - - edge [ - arrowtail = "empty" - ] - - HasDimensions [ - shape = record - label = "{HasDimensions|dimensions|+ size\l+ dimnames\l}" - ]; - HasSamples [ - shape = record - label = "{HasSamples|__getitem__()|+ __contains__\l+ __iter__\l+ iteritems()\l+ items()\l+ indexes\l+ ids \l}" - ]; - ContainsSamples [ - shape = record - label = "{ContainsSamples|samples|+ __getitem__()\l+ __setitem__()\l+ dimensions\l}" - ]; - ForwardsSamples [ - shape = record - label = "{ForwardsSamples|source\lindex_to_target\lindex_to_source\lcombine_samples\lcombine_dimensions|+ __getitem__\l+ dimensions\l}" - ]; - - HasDimensions -> HasSamples [dir=back]; - HasSamples -> ContainsSamples [dir=back]; - HasSamples -> ForwardsSamples [dir=back]; - } - -The abstract and mixin methods are as follows: - -=================== ================= ======================== =================== -ABC Inherits from Abstract Methods Mixin methods -=================== ================= ======================== =================== -``HasDimensions`` | ``dimensions`` | ``size`` - | ``dimnames`` -``HasSamples`` ``HasDimensions`` | ``__getitem__`` | ``__contains__`` - | ``__iter__`` - | ``iteritems`` - | ``items`` - | ``indexes`` - | ``ids`` -``ContainsSamples`` ``HasSamples`` | ``samples`` | ``__getitem__`` - | ``__setitem__`` - | ``dimensions`` -``ForwardsSamples`` ``HasSamples`` | ``source`` | ``__getitem__`` - | ``index_to_target`` | ``dimensions`` - | ``index_to_source`` - | ``combine_samples`` - | ``combine_dimensions`` -=================== ================= ======================== =================== - -.. note:: - Though the flow is currently working like this, the mixins are not yet created. - -Network Execution ------------------ - -The network execution should contain a number of steps: - -* ``Network`` - - * Creates a ``NetworkRun`` based on the current layout - -* ``NetworkRun`` - - * Transform the ``Network`` (possibly joining Nodes of certain interface into a combined NodeRun etc) - * Start generation of the Job Direct Acyclic Graph (DAG) - -* ``SchedulingPlugin`` - - * Prioritize Jobs based on some predefined rules - * Combine certain ``Jobs`` to improve efficiency (e.g. minimize i/o on a grid) - -* ``ExecutionPlugin`` - - * Run a (list of) ``Jobs``. If there is more than one jobs, run them sequentially on - same execution host using a local temp for intermediate files. - * On finished callback: Updated DAG with newly ready jobs, or remove cancelled jobs - -This could be visualized as the following loop: - -.. graphviz:: - - digraph execution { - node [ - fontname = "Bitstream Vera Sans" - fontsize = 11 - shape = "box" - ] - - Network; - NetworkRun; - NodeRun; - JobDAG; - SchedulingPlugin; - ExecutionPlugin; - - Network -> NetworkRun [label=creates]; - NetworkRun -> JobDAG [label=creates]; - NetworkRun -> NodeRun [label=executes]; - NodeRun -> JobDAG [label="adds jobs"]; - JobDAG -> SchedulingPlugin [label="analyzes and selects jobs"]; - SchedulingPlugin -> ExecutionPlugin [label="(list of) Jobs to execute"]; - ExecutionPlugin -> NetworkRun [label=callback]; - } - -The callback of the ``ExecutionPlugin`` to the ``NetworkRun`` would trigger -the execution of the relevant ``NodeRuns`` and the addition of more ``Jobs`` -to the ``JobDAG``. - -.. note:: The Job DAG should be thread-safe as it could be both read and - extended at the same time. - -.. note:: If a list of jobs is send to the ``ExecutionPlugin`` to be run as - on Job on an external execution platform, the resources should be - combined as follows: memory=max, cores=max, runtime=sum - -.. note:: If there are execution hosts that have mutliple cores the - ``ExecutionPlugin`` should manage this (for example by using pilot - jobs). The ``SchedulingPlugin`` creates units that should be run - sequentially on the resources noted and will not attempt - parallelization - -A ``NetworkRun`` would be contain similar information as the ``Network`` but -not have functionality for editting/changing it. It would contain the -functionality to execute the Network and track the status and samples. This -would allow ``Network.execute`` to create multiple concurent runs that operate -indepent of each other. Also editting a ``Network`` after the run started would -have no effect on that run. - -.. note:: This is a plan, not yet implemented - -.. note:: For this to work, it would be important for a Jobs to have forward - and backward dependency links. - -SchedulingPlugins -~~~~~~~~~~~~~~~~~ - -The idea of the plugin is that it would give a priority on Jobs created by a -``Network``. This could be done based on different strategies: - -* Based on (sorted) sample id's, so that one sample is always prioritized over - others. The idea is that samples are process as much as possible in order, - finishing the first sample first. Only processing other samples if there is - left-over capacity. -* Based on distance to a (particular) ``Sink``. This is to generate specific - results as quick as possible. It would not focus on specific samples, but - give priority to whatever sample is closest to being finished. -* Based on the distance to from a ``Souce``. Based on the sign of the weight - it would either keep all samples on the same stage as much as possible, only - progressing to a new ``NodeRun`` when all samples are done with the previous - ``NodeRun``, or it would push samples with accelerated rates. - -Additionally it will group ``Jobs`` to be executed on a single host. This could -reduce i/o and limited the number of jobs an external scheduler has to track. - -.. note:: - The interface for such a plugin has not yet been established. - - -Secrets --------------------- -"Something that is kept or meant to be kept unknown or unseen by others." - -Using secrets -~~~~~~~~~~~~~~~~~~~~ -Fastr IOPlugins that need authentication data should use the Fastr SecretService for retrieving such data. The SecretService can be used as follows. - -.. code-block:: python - - from fastr.utils.secrets import SecretService - from fastr.utils.secrets.exceptions import CouldNotRetrieveCredentials - - secret_service = SecretService() - - try: - password = secret_service.find_password_for_user('testserver.lan:9000', 'john-doe') - except CouldNotRetrieveCredentials: - # the password was not found - pass - - -Implementing a SecretProvider -~~~~~~~~~~~~~~~~~~~~ -A SecretProvider is implemented as follows: - -1. Create a file in fastr/utils/secrets/providers/.py -2. Use the template below to write your SecretProvider -3. Add the secret provider to fastr/utils/secrets/providers/__init__.py -4. Add the secret provider to fastr/utils/secrets/secretservice.py: import it and add it to the array in function _init_providers - -.. code-block:: python - - from fastr.utils.secrets.secretprovider import SecretProvider - from fastr.utils.secrets.exceptions import CouldNotRetrieveCredentials, CouldNotSetCredentials, CouldNotDeleteCredentials, NotImplemented - - - try: - # this is where libraries can be imported - # we don't want fastr to crash if a specific - # library is unavailable - # import my-libary - except (ImportError, ValueError) as e: - pass - - class KeyringProvider(SecretProvider): - def __init__(self): - # if libraries are imported in the code above - # we need to check if import was succesfull - # if it was not, raise a RuntimeError - # so that FASTR ignores this SecretProvider - # if 'my-library' not in globals(): - # raise RuntimeError("my-library module required") - pass - - def get_password_for_user(self, machine, username): - # This function should return the password as a string - # or raise a CouldNotRetrieveCredentials error if the password - # is not found. - # In the event that this function is unsupported a - # NotImplemented exception should be thrown - raise NotImplemented() - - def set_password_for_user(self, machine, username, password): - # This function should set the password for a specified - # machine + user. If anything goes wrong while setting - # the password a CouldNotSetCredentials error should be raised. - # In the event that this function is unsupported a - # NotImplemented exception should be thrown - raise NotImplemented() - - def del_password_for_user(self, machine, username): - # This function should delete the password for a specified - # machine + user. If anything goes wrong while setting - # the password a CouldNotDeleteCredentials error should be raised. - # In the event that this function is unsupported a - # NotImplemented exception should be thrown - raise NotImplemented() diff --git a/build/lib/WORC/doc/_build/html/_sources/static/file_description.rst.txt b/build/lib/WORC/doc/_build/html/_sources/static/file_description.rst.txt deleted file mode 100644 index 79e6216d..00000000 --- a/build/lib/WORC/doc/_build/html/_sources/static/file_description.rst.txt +++ /dev/null @@ -1,6 +0,0 @@ -Resource File Formats -===================== - -This chapter describes the various files WORC uses. The function and format -of the files is described allowing the user to configure WORC and add -DataTypes and Tools. diff --git a/build/lib/WORC/doc/_build/html/_sources/static/introduction.rst.txt b/build/lib/WORC/doc/_build/html/_sources/static/introduction.rst.txt deleted file mode 100644 index 8807c55e..00000000 --- a/build/lib/WORC/doc/_build/html/_sources/static/introduction.rst.txt +++ /dev/null @@ -1,102 +0,0 @@ -Introduction -============ - -When I started my PhD at the Erasmus MC in 2016 on radiomics, the idea was to start with a straight-forward radiomics study to get familiar with the field. -Both the field of radiomics and my group at the Erasmus MC had existed for quite some time. -Therefore, I naively expected that all previously created methods and software were nicely organized and would be straight forward to apply and compare. -However, I found that of all the radiomics studies, only a few actually released their software open-source. -Moreover, the software that was available was very diverse in terms of programming language and often difficult to understand. -Each developer used its own ontology, workflow and implementation. - -Hence I wondered which method would work best for my specific application. -It seemed that many of my fellow PhD students started out with the same question. -I did not like the foresight to start out my PhD by tediously working on finding a decent baseline and trying out all kinds of methods. -Moreover, it felt inefficient that every time a new study is started, someone like me had to go through the whole process over and over again. - -I therefore decided to create one radiomics platform in which multiple approaches could easily be integrated. -I tried to make it as flexible as possible and modular, such that researcher can easily integrate their own components into the workflow. - -Including all these methods brought along many choices in terms of both the methods to use and their parameters. -Similar to the above, I also did not like the foresight of manual tuning, which both feels inefficient and a non-optimal approach. -Hence, I decided to create an automatic optimization routine for the platform which includes all the choices in the workflow that have to be made. - -The result is WORC, which has made my research a lot easier and more fun, as I can very easily create a decent radiomics baseline for any study with little effort. - -Radiomics Terminology ---------------------- - -Radiomics concerns the use of quantitative medical image features to predict clinically relevant outcomes. -In WORC, the computational radiomics workflow is divided in five steps: - -.. figure:: images/RadiomicsSteps.* - -1. Image Acquisition, which we assume has already been done. -2. Preprocessing -3. Segmentation -4. Feature Extraction -5. Data Mining - -Preprocessing is defined as anything that is done to the image before the feature extraction. -This may include normalization, cropping, masking, and registration. Filtering may be included as well, although several features may already implicitly use a filter. - -Data mining is defined as anything that is used to go from features to the actual label or outcome. -This may include feature selection, feature imputation, feature scaling, dimensionality reduction, and oversampling. -Note that we always define the last step in data mining as a machine learning approach. -Although several radiomics studies do not use machine learning but directly correlate features with outcome, -we feel that in clinical practice a prediction model is most of the time required. - -Due to the shear amount of tools available in the data mining node, this node in itself is another fastr (micro)network. - -Modularity and standardization: fastr -------------------------------------- - -The first step of building WORC was to standardize radiomics in components to create a modular workflow. -The available radiomics methods were all in different software languages, hence my framework had to support this as well. -Luckily, some of my colleagues had the same issues and decided to create a new workflow engine: `fastr http://journal.frontiersin.org/article/10.3389/fict.2016.00015/full/>`_. -I highly recommend to read at least `the introductory page of the manual `_ in order to get familiar with the basic concept of fastr . - -To illustrate the principles of fastr, one of the simpler workflows created by WORC using fastr is shown in the figure below. - -.. figure:: images/WORC_small.* - -The radiomics workflow is split in nodes. We define four types of nodes: -* Sources, which serve as the input for the workflow. -* Nodes, which is where the actual algorithms run. -* Sinks, which serve as the output for the workflow. -* Constants - -In each node, the inputs, outputs and thereby the task is fixed. However, the actual algorithm that is used within a node is node. -For example, in a feature extraction node, the inputs are an image, possibly a segmentation and parameters, from which features are extracted, which are thereby the output. -Which methods is actually used to extract the features and the features extracted may vary. - -Using fastr in WORC gives us several benefits: -* You can use any tool that can be run on the command line: thus languages or interpreters like MATLAB, Python, R, but also executables. -* As the workflow is standardized, the outputs are as well. Hence workflows can be easily compared. -* fastr automatic keeps a history of how an output was created, or the provenance, and extensive logging. This facilitates high reproducability. -* Wrapping a tool in fastr is easy: you only need to determine the inputs, outputs, interpreter and script. -* fastr supports various execution plugins, thus execution of a pipeline on a cluster or a simple laptop can be adapted to the resources at hand. -* Data can be imported and exported to various sources, also online! - - -Optimization ------------- - -When starting a new radiomics study, e.g. trying to find a imaging biomarker on a new dataset, you would normally have to design a workflow yourself from all methods available in WORC. -Not only would you have to determine which methods you are going to use, but also which parameters for all methods. Many studies have shown that these are often not independent: -the performance of many methods highly depends on the parameters used. Thus, we need to simultanously look for the best combination of these. - -As these parameters are set before the actual learning step in the machine learning part, we refer to these as hyperparameters. -As the performance of the machine learning algorithm may depend on the previous steps -(e.g. preprocessing, feature extraction, and all other steps in the data mining node), -we decided to include all parameters from all nodes as hyperparameters. - -Optimization is done through a variant of combined algorithm selection and hyperparameter (CASH) optimization problem. -Currently, WORC solves the problem as following: - -.. figure:: images/CASH.* - -1. Generate a large number of different pipelines. -2. Execute them and rank them. -3. Create and ensemble of the X best performing pipelines. - -More information on this can be found in X. diff --git a/build/lib/WORC/doc/_build/html/_sources/static/quick_start.rst.txt b/build/lib/WORC/doc/_build/html/_sources/static/quick_start.rst.txt deleted file mode 100644 index 47be8c5a..00000000 --- a/build/lib/WORC/doc/_build/html/_sources/static/quick_start.rst.txt +++ /dev/null @@ -1,81 +0,0 @@ -Quick start guide -================= - -This manual will show users how to install WORC, configure WORC and construct and run simple networks. - -.. _installation-chapter: - -Installation ------------- - -You can install WORC either using pip, or from the source code. - -Installing via pip -`````````````````` - -You can simply install WORC using ``pip``: - -.. code-block:: bash - - pip install WORC - -.. note:: You might want to consider installing ``WORC`` in a `virtualenv `_ - - -Installing from source code -``````````````````````````` - -To install from source code, use git via the command-line: - -.. code-block:: bash - - git clone https://github.com/MStarmans91/WORC.git # for http - git clone ssh://git@github.com:MStarmans91/WORC.git # for ssh - -.. _subsec-installing: - -To install to your current Python environment, run: - -.. code-block:: bash - - cd WORC/ - pip install . - -This installs the scripts and packages in the default system folders. For -Windows this is the python ``site-packages`` directory for the WORC python -library. For Ubuntu this is in the ``/usr/local/lib/python3.x/dist-packages/`` folder. - -.. note:: If you want to develop WORC, you might want to use ``pip install -e .`` to get an editable install - -.. note:: You might want to consider installing ``WORC`` in a `virtualenv `_ - - -Configuration -------------- - -WORC has defaults for all settings so it can be run out of the box to test the examples. -However, you may want to alter the fastr configuration to your system settings, e.g. -to locate your input and output folders and how much you want to parallelize the execution. - -Fastr will search for a config file named ``config.py`` in the ``$FASTRHOME`` directory -(which defaults to ``~/.fastr/`` if it is not set). So if ``$FASTRHOME`` is set the ``~/.fastr/`` -will be ignored. Additionally, .py files from the ``$FASTRHOME/config.d`` folder will be parsed -as well. You will see that upon installation, WORC has already put a ``WORC_config.py`` file in the -``config.d`` folder. - -For a sample configuration file and a complete overview of the options in ``config.py`` see -the :ref:`Config file ` section. - - -Tutorial --------- - -To start out using WORC, we recommend you to follow the tutorial located in the -[WORCTutorial Github](https://github.com/MStarmans91/WORCTutorial). Besides some more advanced tutorials, -the main tutorial can be found in the WORCTutorial.ipynb Jupyter notebook. Instructions on how -to use the notebook can be found in the Github. - -If you run into any issue, you can first debug your network using -`the fastr trace tool `_. -If you're stuck, feel free to post an issue on the `WORC Github `_. - diff --git a/build/lib/WORC/doc/_build/html/_sources/static/reference.rst.txt b/build/lib/WORC/doc/_build/html/_sources/static/reference.rst.txt deleted file mode 100644 index 956c1e61..00000000 --- a/build/lib/WORC/doc/_build/html/_sources/static/reference.rst.txt +++ /dev/null @@ -1,9 +0,0 @@ -.. _resource-ref: - -Resource Reference -================== - -In this chapter we describe the different plugins bundled with Fastr (e.g. -IOPlugins, ExecutionPlugins). The reference is build automatically from code, -so after installing a new plugin the documentation has to be rebuild for it to -be included in the docs. diff --git a/build/lib/WORC/doc/_build/html/_sources/static/tools.rst.txt b/build/lib/WORC/doc/_build/html/_sources/static/tools.rst.txt deleted file mode 100644 index 49a0898e..00000000 --- a/build/lib/WORC/doc/_build/html/_sources/static/tools.rst.txt +++ /dev/null @@ -1,42 +0,0 @@ -Guidlines on using and creating Fastr tools -=========================================== - - -Fastr pulls its tools definitions from a repository called FastrHub. Optionally tool definitions can also be pulled from a -local folder or a private repository. - -.. figure:: images/tools/tooldefresolveflowchart.png - :alt: A flowchart of the Fastr tool loading order. Priority is as follows: 1 load from cache, 2 load from local disk, 3 load from FastrHub repository, 4 raise Fastr Cannot Find Tool Definition Exception. - - Fastr tool definition loading order. - - -Creating a tool definition --------------------------- - -The tool definition (xml file) is a wrapper. We should version these wrappers. Use the version property in the tool element to do this. - - -Uploading a tool definition to FastrHub ---------------------------------------- - -Tool definitions in FastrHub can not be overwritten. This is to improve reproducability. A tool definition can be changed to 'deprecated' which hides it from search but it will still be downloadable. -The example below pushes the FSLMaths tool into the fsl namespace. It uses definition v1.0. This is the version property in the tool-element of your tool-wrapper xml. - -.. code-block:: - - $ fastr tools push fsl/FSLMaths 1.0 - Username: demo - Password: ***** - Uploading [########--] 80% - - - -Code examples -------------- -Instantiate a node that uses the FSLMaths tool. - -.. code-block:: python - - # network.create_node('/:', tool_version='', repositoy='') - node = network.create_node('fsl/FSLMaths:5.0.9', tool_version='1.0') diff --git a/build/lib/WORC/doc/_build/html/_sources/static/user_manual.rst.txt b/build/lib/WORC/doc/_build/html/_sources/static/user_manual.rst.txt deleted file mode 100644 index 1a5494bc..00000000 --- a/build/lib/WORC/doc/_build/html/_sources/static/user_manual.rst.txt +++ /dev/null @@ -1,275 +0,0 @@ -User Manual -=========== - -In this chapter we will discuss the parts of Fastr in more detail. We will give a more complete overview of the system -and describe the more advanced features. - -.. _tools: - -The WORC object ---------------- - -The WORC toolbox consists of one main object, the WORC object: - - - -.. code-block:: python - - import WORC - network = WORC.WORC('somename') - - - -It's attributes are split in a couple of categories. We will not discuss -the WORC.defaultconfig() function here, which generates the default -configuration, as it is listed in a separate page, see the :ref:`config file section `. - - - -Attributes: Sources -------------------- - - - -There are numerous WORC attributes which serve as source nodes for the -FASTR network. These are: - - -- images_train and images_test -- segmentations_train and segmentations_test -- semantics_train and semantics_test -- labels_train and labels_test -- masks_train and masks_test -- features_train and features_test -- metadata_train and metadata_test -- Elastix_Para -- fastrconfigs - - -When using a single dataset for both training and evaluation, you should -supply all sources in train objects. You can use several kinds of -validation methods (e.g.cross validation) to compute the performance on -this dataset. Optionally, you can supply a separate training and test -set. - - -Each source should be given as a dictionary of strings corresponding to -the source files. Each element should correspond to a single object, -e.g. tumor, or patient. The keys are used to match the features to the -label and semantics sources, so make sure these correspond to the label -file. The values should refer to the actual source files corresponding -to the FASTR formats, see -http://fastr.readthedocs.io/en/stable/fastr.reference.html#ioplugin-reference. - - -You can off course have multiple images or ROIs per object, e.g. a liver -ROI and a tumor ROI. This can be easily done by appending to the -sources. For example: - -.. code-block:: python - - images1 = {'patient1': vfs://example/MR.nii, 'patient2': vfs://example/MR.nii} - segmentations1 = {'patient1': vfs://example/tumor.nii, 'patient2': vfs://example/tumor.nii} - segmentations2 = {'patient1': vfs://example/liver.nii, 'patient2': vfs://example/liver.nii} - - network.images_train.append(images1) - network.images_train.append(images1) - - network.segmentations_train.append(segmentations1) - network.segmentations_train.append(segmentations2) - - - -When using multiple sequences per patients (e.g. T1 and T2), the same -appending procedure can be used. - - -.. note:: You have to make sure the images and segmentation sources match in size. - -.. note:: You have to supply a configuration file for each image or feature source you append. - Thus, in above example, you need to append two configurations! -.. note:: When you use - multiple image sequences, you can supply a ROI for each sequence by - appending to to segmentations object. Alternatively, when you do not - supply a segmentation for a specific sequence, WORC will use Elastix to - align this sequence to another through image registration. It will then - warp the segmentation from this sequence to the sequence for which you - did not supply a segmentation. **WORC will always align these sequences with no segmentations to the first sequence, i.e. the first object in the images_train list.** - Hence make sure you supply the sequence for which you have a ROI as the first object. - - - -Attributes: Settings --------------------- - - -There are several attributes in WORC which define how your pipeline is -executed: - - - -- fastr_plugin -- fastr_tmpdir -- Tools: additional workflows are stored here. Currently only includes - a pipeline for image registration without any Radiomics. -- CopyMetadata: Whether to automatically copy the metadata info - (e.g. direction of cosines) from the images to the segmentations - before applying transformix. - -An explanation of the FASTR settings is given below. - - - -Attributes: Functions ---------------------- - -The WORC.configs() attribute contains the configparser files, which you -can easily edit. The WORC.set() function saves these objects in a -temporary folder and converts the filename into as FASTR source, which -is then put in the WORC.fastrconfigs() objects. Hence you do not need to -edit the fastrconfigs object manually. - - - -Images and segmentations -~~~~~~~~~~~~~~~~~~~~~~~~ - - - -The minimal input for a Radiomics pipeline consists of either images -(plus a segmentation if you have not implemented an automatic -segmentation tool) or features plus a label file (and a configuration, -but you can just use the default one. - -If you supply these, features will be computed within the segmentations -on the images. They are read out using SimpleITK, which supports various -image formats such as DICOM, NIFTI, TIFF, NRRD and MHD. - - - -Semantics -~~~~~~~~~ - -Semantic features are used in the PREDICT CalcFeatures tool. You can -supply these as a .csv listing your features per patient. The first -column should always be named ``Patient`` and contain the Patient ID. The -other columns should contain a label for the feature and their values. -For example: - - - -+----------+--------+--------+ -| Patient | Label1 | Label2 | -+==========+========+========+ -| patient1 | 1 | 0 | -+----------+--------+--------+ -| patient2 | 2 | 1 | -+----------+--------+--------+ -| patient3 | 1 | 5 | -+----------+--------+--------+ - - -Similar to the patient labels, the semantic features are matched to the -correct image/features by the name of the image/features. So in this -case, your sources should look as following: - - - -.. code-block:: python - - images_train = {'patient1': 'source1.nii.gz', 'patient2': 'source2.nii.gz', ...} - segmentations_train = {'patient1': 'seg1.nii.gz', 'patient2': 'seg2.nii.gz', ...} - - - -Labels -~~~~~~ - -The labels are used in classification. For PREDICT, these should be -supplied as a .txt file. Similar to the semantics, the first column -should head ``Patient`` and contain the patient ID. The next columns can -contain things you want to predict. Hence the format is similar to the -semantics file. - - -Masks ------------ - -WORC contains a segmentation preprocessing tool, called segmentix. This -tool is still under development. The idea is that you can manipulate -your segmentation, e.g. using dilation, then use a mask to make sure it -is still valid. Currently, you can only let it take a ring of a certain -radius around your ROI and mask it. - - - -Features --------- - -If you already computed your features, e.g. from a previous run, you can -directly supply the features instead of the images and segmentations and -skip the feature computation step. These should be stored in .hdf5 files -matching the PREDICT CalcFeatures format. - - -Metadata --------- - -This source can be used if you want to use tags from the DICOM header as -features, e.g. patient age and sex. In this case, this source should -contain a single DICOM per patient from which the tags that are read. -Check the PREDICT.imagefeatures.patient_feature module for the currently -implemented tags. - - - -Elastix_Para ------------- - -If you have multiple images for each patient, e.g. T1 and T2, but only a -single segmentation, you can use image registration to align and -transform the segmentation to the other modality. This is done in WORC -using Elastix http://elastix.isi.uu.nl/. In this source, you can supply -a parameter file for Elastix to be used in the registration in .txt. -format. Alternatively, you can use SimpleElastix to generate a parameter -map and pass this object to WORC. **Note: WORC assume your segmentation -is made on the first WORC.images source you supply. The segmentation -will be alingned to all other image sources.** - - - -FASTR settings --------------- - -There are two WORC attributes which contain settings on running FASTR. -In WORC.fastr_plugin, you can specify which Execution Plugin should be -used: see also -http://fastr.readthedocs.io/en/stable/fastr.reference.html#executionplugin-reference. - -The default is the ProcessPollExecution plugin. The WORC.fastr_tempdir -sets the temporary directory used in your run. - - - -Construction and execution commands ------------------------------------ - - - -After supplying your sources, you need to build the FASTR network. This -can be done through the WORC.build() command. Depending on your sources, -several nodes will be added and linked. This creates the WORC.network() -object, which is a fastr.network() object. You can edit this network -freely, e.g. add another source or node. You can print the network with -the WORC.network.draw_network() command. - - -Next, we have to tell the network which sources should be used in the -source nodes. This can be done through the WORC.set() command. This will -put your supplied sources into the source nodes and also creates the -needed sink nodes. You can check these by looking at the created -WORC.source_data_data and WORC.sink objects. - - -Finally, after completing above steps, you can execute the network -through the WORC.execute() command. diff --git a/build/lib/WORC/doc/_build/html/_sources/user_reference/user_reference.rst.txt b/build/lib/WORC/doc/_build/html/_sources/user_reference/user_reference.rst.txt deleted file mode 100644 index 1f2727f6..00000000 --- a/build/lib/WORC/doc/_build/html/_sources/user_reference/user_reference.rst.txt +++ /dev/null @@ -1,66 +0,0 @@ -Fastr User Reference -==================== - -.. attribute:: fastr.tools - - A ToolManager containing all versions of all Tools loaded into the FASTR - environment. The ToolManager can be indexed using the Tool id string or - a tool id string and a version. For example if you have two versions (4.5 - and 4.8) of a tool called *Elastix*: - - .. code-block:: python - - >>> fastr.tools['elastix.Elastix'] - Tool Elastix v4.8 (Elastix Registration) - Inputs | Outputs - -------------------------------------------------------------------------------------------------- - fixed_image (ITKImageFile) | directory (Directory) - moving_image (ITKImageFile) | transform (ElastixTransformFile) - parameters (ElastixParameterFile) | log_file (ElastixLogFile) - fixed_mask (ITKImageFile) | - moving_mask (ITKImageFile) | - initial_transform (ElastixTransformFile) | - priority (__Elastix_4.8_interface__priority__Enum__) | - threads (Int) | - - >>> fastr.tools['elastix.Elastix', '4.5'] - Tool Elastix v4.5 (Elastix Registration) - Inputs | Outputs - -------------------------------------------------------------------------------------------------- - fixed_image (ITKImageFile) | directory (Directory) - moving_image (ITKImageFile) | transform (ElastixTransformFile) - parameters (ElastixParameterFile) | log_file (ElastixLogFile) - fixed_mask (ITKImageFile) | - moving_mask (ITKImageFile) | - initial_transform (ElastixTransformFile) | - priority (__Elastix_4.5_interface__priority__Enum__) | - threads (Int) | - -.. attribute:: fastr.types - - A dictionary containing all types loaded into the FASTR environment. The keys are the typenames and the values are the classes. - -.. attribute:: fastr.networks - - A dictionary containing all networks loaded in fastr - -.. automethod:: fastr.api.create_network - -.. automethod:: fastr.api.create_network_copy - -.. autoclass:: fastr.api.Network - :members: id, version, create_node, create_link, create_sink, create_source, - create_constant, create_macro, draw, execute, load, save, nodes - -.. autoclass:: fastr.api.Link - :members: id, collapse, expand - -.. autoclass:: fastr.api.Node - :members: id, inputs, outputs, input, output - -.. autoclass:: fastr.api.Input - :members: id, input_group, append, __lshift__, __rrshift__ - -.. autoclass:: fastr.api.Output - :members: id, __getitem__ - diff --git a/build/lib/WORC/doc/_build/html/_static/basic.css b/build/lib/WORC/doc/_build/html/_static/basic.css deleted file mode 100644 index 53acd096..00000000 --- a/build/lib/WORC/doc/_build/html/_static/basic.css +++ /dev/null @@ -1,748 +0,0 @@ -/* - * basic.css - * ~~~~~~~~~ - * - * Sphinx stylesheet -- basic theme. - * - * :copyright: Copyright 2007-2019 by the Sphinx team, see AUTHORS. - * :license: BSD, see LICENSE for details. - * - */ - -/* -- main layout ----------------------------------------------------------- */ - -div.clearer { - clear: both; -} - -/* -- relbar ---------------------------------------------------------------- */ - -div.related { - width: 100%; - font-size: 90%; -} - -div.related h3 { - display: none; -} - -div.related ul { - margin: 0; - padding: 0 0 0 10px; - list-style: none; -} - -div.related li { - display: inline; -} - -div.related li.right { - float: right; - margin-right: 5px; -} - -/* -- sidebar --------------------------------------------------------------- */ - -div.sphinxsidebarwrapper { - padding: 10px 5px 0 10px; -} - -div.sphinxsidebar { - float: left; - width: 230px; - margin-left: -100%; - font-size: 90%; - word-wrap: break-word; - overflow-wrap : break-word; -} - -div.sphinxsidebar ul { - list-style: none; -} - -div.sphinxsidebar ul ul, -div.sphinxsidebar ul.want-points { - margin-left: 20px; - list-style: square; -} - -div.sphinxsidebar ul ul { - margin-top: 0; - margin-bottom: 0; -} - -div.sphinxsidebar form { - margin-top: 10px; -} - -div.sphinxsidebar input { - border: 1px solid #98dbcc; - font-family: sans-serif; - font-size: 1em; -} - -div.sphinxsidebar #searchbox form.search { - overflow: hidden; -} - -div.sphinxsidebar #searchbox input[type="text"] { - float: left; - width: 80%; - padding: 0.25em; - box-sizing: border-box; -} - -div.sphinxsidebar #searchbox input[type="submit"] { - float: left; - width: 20%; - border-left: none; - padding: 0.25em; - box-sizing: border-box; -} - - -img { - border: 0; - max-width: 100%; -} - -/* -- search page ----------------------------------------------------------- */ - -ul.search { - margin: 10px 0 0 20px; - padding: 0; -} - -ul.search li { - padding: 5px 0 5px 20px; - background-image: url(file.png); - background-repeat: no-repeat; - background-position: 0 7px; -} - -ul.search li a { - font-weight: bold; -} - -ul.search li div.context { - color: #888; - margin: 2px 0 0 30px; - text-align: left; -} - -ul.keywordmatches li.goodmatch a { - font-weight: bold; -} - -/* -- index page ------------------------------------------------------------ */ - -table.contentstable { - width: 90%; - margin-left: auto; - margin-right: auto; -} - -table.contentstable p.biglink { - line-height: 150%; -} - -a.biglink { - font-size: 1.3em; -} - -span.linkdescr { - font-style: italic; - padding-top: 5px; - font-size: 90%; -} - -/* -- general index --------------------------------------------------------- */ - -table.indextable { - width: 100%; -} - -table.indextable td { - text-align: left; - vertical-align: top; -} - -table.indextable ul { - margin-top: 0; - margin-bottom: 0; - list-style-type: none; -} - -table.indextable > tbody > tr > td > ul { - padding-left: 0em; -} - -table.indextable tr.pcap { - height: 10px; -} - -table.indextable tr.cap { - margin-top: 10px; - background-color: #f2f2f2; -} - -img.toggler { - margin-right: 3px; - margin-top: 3px; - cursor: pointer; -} - -div.modindex-jumpbox { - border-top: 1px solid #ddd; - border-bottom: 1px solid #ddd; - margin: 1em 0 1em 0; - padding: 0.4em; -} - -div.genindex-jumpbox { - border-top: 1px solid #ddd; - border-bottom: 1px solid #ddd; - margin: 1em 0 1em 0; - padding: 0.4em; -} - -/* -- domain module index --------------------------------------------------- */ - -table.modindextable td { - padding: 2px; - border-collapse: collapse; -} - -/* -- general body styles --------------------------------------------------- */ - -div.body { - min-width: 450px; - max-width: 800px; -} - -div.body p, div.body dd, div.body li, div.body blockquote { - -moz-hyphens: auto; - -ms-hyphens: auto; - -webkit-hyphens: auto; - hyphens: auto; -} - -a.headerlink { - visibility: hidden; -} - -a.brackets:before, -span.brackets > a:before{ - content: "["; -} - -a.brackets:after, -span.brackets > a:after { - content: "]"; -} - -h1:hover > a.headerlink, -h2:hover > a.headerlink, -h3:hover > a.headerlink, -h4:hover > a.headerlink, -h5:hover > a.headerlink, -h6:hover > a.headerlink, -dt:hover > a.headerlink, -caption:hover > a.headerlink, -p.caption:hover > a.headerlink, -div.code-block-caption:hover > a.headerlink { - visibility: visible; -} - -div.body p.caption { - text-align: inherit; -} - -div.body td { - text-align: left; -} - -.first { - margin-top: 0 !important; -} - -p.rubric { - margin-top: 30px; - font-weight: bold; -} - -img.align-left, .figure.align-left, object.align-left { - clear: left; - float: left; - margin-right: 1em; -} - -img.align-right, .figure.align-right, object.align-right { - clear: right; - float: right; - margin-left: 1em; -} - -img.align-center, .figure.align-center, object.align-center { - display: block; - margin-left: auto; - margin-right: auto; -} - -.align-left { - text-align: left; -} - -.align-center { - text-align: center; -} - -.align-right { - text-align: right; -} - -/* -- sidebars -------------------------------------------------------------- */ - -div.sidebar { - margin: 0 0 0.5em 1em; - border: 1px solid #ddb; - padding: 7px 7px 0 7px; - background-color: #ffe; - width: 40%; - float: right; -} - -p.sidebar-title { - font-weight: bold; -} - -/* -- topics ---------------------------------------------------------------- */ - -div.topic { - border: 1px solid #ccc; - padding: 7px 7px 0 7px; - margin: 10px 0 10px 0; -} - -p.topic-title { - font-size: 1.1em; - font-weight: bold; - margin-top: 10px; -} - -/* -- admonitions ----------------------------------------------------------- */ - -div.admonition { - margin-top: 10px; - margin-bottom: 10px; - padding: 7px; -} - -div.admonition dt { - font-weight: bold; -} - -div.admonition dl { - margin-bottom: 0; -} - -p.admonition-title { - margin: 0px 10px 5px 0px; - font-weight: bold; -} - -div.body p.centered { - text-align: center; - margin-top: 25px; -} - -/* -- tables ---------------------------------------------------------------- */ - -table.docutils { - border: 0; - border-collapse: collapse; -} - -table.align-center { - margin-left: auto; - margin-right: auto; -} - -table caption span.caption-number { - font-style: italic; -} - -table caption span.caption-text { -} - -table.docutils td, table.docutils th { - padding: 1px 8px 1px 5px; - border-top: 0; - border-left: 0; - border-right: 0; - border-bottom: 1px solid #aaa; -} - -table.footnote td, table.footnote th { - border: 0 !important; -} - -th { - text-align: left; - padding-right: 5px; -} - -table.citation { - border-left: solid 1px gray; - margin-left: 1px; -} - -table.citation td { - border-bottom: none; -} - -th > p:first-child, -td > p:first-child { - margin-top: 0px; -} - -th > p:last-child, -td > p:last-child { - margin-bottom: 0px; -} - -/* -- figures --------------------------------------------------------------- */ - -div.figure { - margin: 0.5em; - padding: 0.5em; -} - -div.figure p.caption { - padding: 0.3em; -} - -div.figure p.caption span.caption-number { - font-style: italic; -} - -div.figure p.caption span.caption-text { -} - -/* -- field list styles ----------------------------------------------------- */ - -table.field-list td, table.field-list th { - border: 0 !important; -} - -.field-list ul { - margin: 0; - padding-left: 1em; -} - -.field-list p { - margin: 0; -} - -.field-name { - -moz-hyphens: manual; - -ms-hyphens: manual; - -webkit-hyphens: manual; - hyphens: manual; -} - -/* -- hlist styles ---------------------------------------------------------- */ - -table.hlist td { - vertical-align: top; -} - - -/* -- other body styles ----------------------------------------------------- */ - -ol.arabic { - list-style: decimal; -} - -ol.loweralpha { - list-style: lower-alpha; -} - -ol.upperalpha { - list-style: upper-alpha; -} - -ol.lowerroman { - list-style: lower-roman; -} - -ol.upperroman { - list-style: upper-roman; -} - -li > p:first-child { - margin-top: 0px; -} - -li > p:last-child { - margin-bottom: 0px; -} - -dl.footnote > dt, -dl.citation > dt { - float: left; -} - -dl.footnote > dd, -dl.citation > dd { - margin-bottom: 0em; -} - -dl.footnote > dd:after, -dl.citation > dd:after { - content: ""; - clear: both; -} - -dl.field-list { - display: flex; - flex-wrap: wrap; -} - -dl.field-list > dt { - flex-basis: 20%; - font-weight: bold; - word-break: break-word; -} - -dl.field-list > dt:after { - content: ":"; -} - -dl.field-list > dd { - flex-basis: 70%; - padding-left: 1em; - margin-left: 0em; - margin-bottom: 0em; -} - -dl { - margin-bottom: 15px; -} - -dd > p:first-child { - margin-top: 0px; -} - -dd ul, dd table { - margin-bottom: 10px; -} - -dd { - margin-top: 3px; - margin-bottom: 10px; - margin-left: 30px; -} - -dt:target, span.highlighted { - background-color: #fbe54e; -} - -rect.highlighted { - fill: #fbe54e; -} - -dl.glossary dt { - font-weight: bold; - font-size: 1.1em; -} - -.optional { - font-size: 1.3em; -} - -.sig-paren { - font-size: larger; -} - -.versionmodified { - font-style: italic; -} - -.system-message { - background-color: #fda; - padding: 5px; - border: 3px solid red; -} - -.footnote:target { - background-color: #ffa; -} - -.line-block { - display: block; - margin-top: 1em; - margin-bottom: 1em; -} - -.line-block .line-block { - margin-top: 0; - margin-bottom: 0; - margin-left: 1.5em; -} - -.guilabel, .menuselection { - font-family: sans-serif; -} - -.accelerator { - text-decoration: underline; -} - -.classifier { - font-style: oblique; -} - -.classifier:before { - font-style: normal; - margin: 0.5em; - content: ":"; -} - -abbr, acronym { - border-bottom: dotted 1px; - cursor: help; -} - -/* -- code displays --------------------------------------------------------- */ - -pre { - overflow: auto; - overflow-y: hidden; /* fixes display issues on Chrome browsers */ -} - -span.pre { - -moz-hyphens: none; - -ms-hyphens: none; - -webkit-hyphens: none; - hyphens: none; -} - -td.linenos pre { - padding: 5px 0px; - border: 0; - background-color: transparent; - color: #aaa; -} - -table.highlighttable { - margin-left: 0.5em; -} - -table.highlighttable td { - padding: 0 0.5em 0 0.5em; -} - -div.code-block-caption { - padding: 2px 5px; - font-size: small; -} - -div.code-block-caption code { - background-color: transparent; -} - -div.code-block-caption + div > div.highlight > pre { - margin-top: 0; -} - -div.code-block-caption span.caption-number { - padding: 0.1em 0.3em; - font-style: italic; -} - -div.code-block-caption span.caption-text { -} - -div.literal-block-wrapper { - padding: 1em 1em 0; -} - -div.literal-block-wrapper div.highlight { - margin: 0; -} - -code.descname { - background-color: transparent; - font-weight: bold; - font-size: 1.2em; -} - -code.descclassname { - background-color: transparent; -} - -code.xref, a code { - background-color: transparent; - font-weight: bold; -} - -h1 code, h2 code, h3 code, h4 code, h5 code, h6 code { - background-color: transparent; -} - -.viewcode-link { - float: right; -} - -.viewcode-back { - float: right; - font-family: sans-serif; -} - -div.viewcode-block:target { - margin: -1px -10px; - padding: 0 10px; -} - -/* -- math display ---------------------------------------------------------- */ - -img.math { - vertical-align: middle; -} - -div.body div.math p { - text-align: center; -} - -span.eqno { - float: right; -} - -span.eqno a.headerlink { - position: relative; - left: 0px; - z-index: 1; -} - -div.math:hover a.headerlink { - visibility: visible; -} - -/* -- printout stylesheet --------------------------------------------------- */ - -@media print { - div.document, - div.documentwrapper, - div.bodywrapper { - margin: 0 !important; - width: 100%; - } - - div.sphinxsidebar, - div.related, - div.footer, - #top-link { - display: none; - } -} \ No newline at end of file diff --git a/build/lib/WORC/doc/_build/html/_static/css/badge_only.css b/build/lib/WORC/doc/_build/html/_static/css/badge_only.css deleted file mode 100644 index 3c33cef5..00000000 --- a/build/lib/WORC/doc/_build/html/_static/css/badge_only.css +++ /dev/null @@ -1 +0,0 @@ -.fa:before{-webkit-font-smoothing:antialiased}.clearfix{*zoom:1}.clearfix:before,.clearfix:after{display:table;content:""}.clearfix:after{clear:both}@font-face{font-family:FontAwesome;font-weight:normal;font-style:normal;src:url("../fonts/fontawesome-webfont.eot");src:url("../fonts/fontawesome-webfont.eot?#iefix") format("embedded-opentype"),url("../fonts/fontawesome-webfont.woff") format("woff"),url("../fonts/fontawesome-webfont.ttf") format("truetype"),url("../fonts/fontawesome-webfont.svg#FontAwesome") format("svg")}.fa:before{display:inline-block;font-family:FontAwesome;font-style:normal;font-weight:normal;line-height:1;text-decoration:inherit}a .fa{display:inline-block;text-decoration:inherit}li .fa{display:inline-block}li .fa-large:before,li .fa-large:before{width:1.875em}ul.fas{list-style-type:none;margin-left:2em;text-indent:-0.8em}ul.fas li .fa{width:.8em}ul.fas li .fa-large:before,ul.fas li .fa-large:before{vertical-align:baseline}.fa-book:before{content:""}.icon-book:before{content:""}.fa-caret-down:before{content:""}.icon-caret-down:before{content:""}.fa-caret-up:before{content:""}.icon-caret-up:before{content:""}.fa-caret-left:before{content:""}.icon-caret-left:before{content:""}.fa-caret-right:before{content:""}.icon-caret-right:before{content:""}.rst-versions{position:fixed;bottom:0;left:0;width:300px;color:#fcfcfc;background:#1f1d1d;font-family:"Lato","proxima-nova","Helvetica Neue",Arial,sans-serif;z-index:400}.rst-versions a{color:#2980B9;text-decoration:none}.rst-versions .rst-badge-small{display:none}.rst-versions .rst-current-version{padding:12px;background-color:#272525;display:block;text-align:right;font-size:90%;cursor:pointer;color:#27AE60;*zoom:1}.rst-versions .rst-current-version:before,.rst-versions .rst-current-version:after{display:table;content:""}.rst-versions .rst-current-version:after{clear:both}.rst-versions .rst-current-version .fa{color:#fcfcfc}.rst-versions .rst-current-version .fa-book{float:left}.rst-versions .rst-current-version .icon-book{float:left}.rst-versions .rst-current-version.rst-out-of-date{background-color:#E74C3C;color:#fff}.rst-versions .rst-current-version.rst-active-old-version{background-color:#F1C40F;color:#000}.rst-versions.shift-up{height:auto;max-height:100%;overflow-y:scroll}.rst-versions.shift-up .rst-other-versions{display:block}.rst-versions .rst-other-versions{font-size:90%;padding:12px;color:gray;display:none}.rst-versions .rst-other-versions hr{display:block;height:1px;border:0;margin:20px 0;padding:0;border-top:solid 1px #413d3d}.rst-versions .rst-other-versions dd{display:inline-block;margin:0}.rst-versions .rst-other-versions dd a{display:inline-block;padding:6px;color:#fcfcfc}.rst-versions.rst-badge{width:auto;bottom:20px;right:20px;left:auto;border:none;max-width:300px;max-height:90%}.rst-versions.rst-badge .icon-book{float:none}.rst-versions.rst-badge .fa-book{float:none}.rst-versions.rst-badge.shift-up .rst-current-version{text-align:right}.rst-versions.rst-badge.shift-up .rst-current-version .fa-book{float:left}.rst-versions.rst-badge.shift-up .rst-current-version .icon-book{float:left}.rst-versions.rst-badge .rst-current-version{width:auto;height:30px;line-height:30px;padding:0 6px;display:block;text-align:center}@media screen and (max-width: 768px){.rst-versions{width:85%;display:none}.rst-versions.shift{display:block}} diff --git a/build/lib/WORC/doc/_build/html/_static/css/theme.css b/build/lib/WORC/doc/_build/html/_static/css/theme.css deleted file mode 100644 index aed8cef0..00000000 --- a/build/lib/WORC/doc/_build/html/_static/css/theme.css +++ /dev/null @@ -1,6 +0,0 @@ -/* sphinx_rtd_theme version 0.4.3 | MIT license */ -/* Built 20190212 16:02 */ -*{-webkit-box-sizing:border-box;-moz-box-sizing:border-box;box-sizing:border-box}article,aside,details,figcaption,figure,footer,header,hgroup,nav,section{display:block}audio,canvas,video{display:inline-block;*display:inline;*zoom:1}audio:not([controls]){display:none}[hidden]{display:none}*{-webkit-box-sizing:border-box;-moz-box-sizing:border-box;box-sizing:border-box}html{font-size:100%;-webkit-text-size-adjust:100%;-ms-text-size-adjust:100%}body{margin:0}a:hover,a:active{outline:0}abbr[title]{border-bottom:1px dotted}b,strong{font-weight:bold}blockquote{margin:0}dfn{font-style:italic}ins{background:#ff9;color:#000;text-decoration:none}mark{background:#ff0;color:#000;font-style:italic;font-weight:bold}pre,code,.rst-content tt,.rst-content code,kbd,samp{font-family:monospace,serif;_font-family:"courier new",monospace;font-size:1em}pre{white-space:pre}q{quotes:none}q:before,q:after{content:"";content:none}small{font-size:85%}sub,sup{font-size:75%;line-height:0;position:relative;vertical-align:baseline}sup{top:-0.5em}sub{bottom:-0.25em}ul,ol,dl{margin:0;padding:0;list-style:none;list-style-image:none}li{list-style:none}dd{margin:0}img{border:0;-ms-interpolation-mode:bicubic;vertical-align:middle;max-width:100%}svg:not(:root){overflow:hidden}figure{margin:0}form{margin:0}fieldset{border:0;margin:0;padding:0}label{cursor:pointer}legend{border:0;*margin-left:-7px;padding:0;white-space:normal}button,input,select,textarea{font-size:100%;margin:0;vertical-align:baseline;*vertical-align:middle}button,input{line-height:normal}button,input[type="button"],input[type="reset"],input[type="submit"]{cursor:pointer;-webkit-appearance:button;*overflow:visible}button[disabled],input[disabled]{cursor:default}input[type="checkbox"],input[type="radio"]{box-sizing:border-box;padding:0;*width:13px;*height:13px}input[type="search"]{-webkit-appearance:textfield;-moz-box-sizing:content-box;-webkit-box-sizing:content-box;box-sizing:content-box}input[type="search"]::-webkit-search-decoration,input[type="search"]::-webkit-search-cancel-button{-webkit-appearance:none}button::-moz-focus-inner,input::-moz-focus-inner{border:0;padding:0}textarea{overflow:auto;vertical-align:top;resize:vertical}table{border-collapse:collapse;border-spacing:0}td{vertical-align:top}.chromeframe{margin:.2em 0;background:#ccc;color:#000;padding:.2em 0}.ir{display:block;border:0;text-indent:-999em;overflow:hidden;background-color:transparent;background-repeat:no-repeat;text-align:left;direction:ltr;*line-height:0}.ir br{display:none}.hidden{display:none !important;visibility:hidden}.visuallyhidden{border:0;clip:rect(0 0 0 0);height:1px;margin:-1px;overflow:hidden;padding:0;position:absolute;width:1px}.visuallyhidden.focusable:active,.visuallyhidden.focusable:focus{clip:auto;height:auto;margin:0;overflow:visible;position:static;width:auto}.invisible{visibility:hidden}.relative{position:relative}big,small{font-size:100%}@media print{html,body,section{background:none !important}*{box-shadow:none !important;text-shadow:none !important;filter:none !important;-ms-filter:none !important}a,a:visited{text-decoration:underline}.ir a:after,a[href^="javascript:"]:after,a[href^="#"]:after{content:""}pre,blockquote{page-break-inside:avoid}thead{display:table-header-group}tr,img{page-break-inside:avoid}img{max-width:100% !important}@page{margin:.5cm}p,h2,.rst-content .toctree-wrapper p.caption,h3{orphans:3;widows:3}h2,.rst-content .toctree-wrapper p.caption,h3{page-break-after:avoid}}.fa:before,.wy-menu-vertical li span.toctree-expand:before,.wy-menu-vertical li.on a span.toctree-expand:before,.wy-menu-vertical li.current>a span.toctree-expand:before,.rst-content .admonition-title:before,.rst-content h1 .headerlink:before,.rst-content h2 .headerlink:before,.rst-content h3 .headerlink:before,.rst-content h4 .headerlink:before,.rst-content h5 .headerlink:before,.rst-content h6 .headerlink:before,.rst-content dl dt .headerlink:before,.rst-content p.caption .headerlink:before,.rst-content table>caption .headerlink:before,.rst-content .code-block-caption .headerlink:before,.rst-content tt.download span:first-child:before,.rst-content code.download span:first-child:before,.icon:before,.wy-dropdown .caret:before,.wy-inline-validate.wy-inline-validate-success .wy-input-context:before,.wy-inline-validate.wy-inline-validate-danger .wy-input-context:before,.wy-inline-validate.wy-inline-validate-warning .wy-input-context:before,.wy-inline-validate.wy-inline-validate-info .wy-input-context:before,.wy-alert,.rst-content .note,.rst-content .attention,.rst-content .caution,.rst-content .danger,.rst-content .error,.rst-content .hint,.rst-content .important,.rst-content .tip,.rst-content .warning,.rst-content .seealso,.rst-content .admonition-todo,.rst-content .admonition,.btn,input[type="text"],input[type="password"],input[type="email"],input[type="url"],input[type="date"],input[type="month"],input[type="time"],input[type="datetime"],input[type="datetime-local"],input[type="week"],input[type="number"],input[type="search"],input[type="tel"],input[type="color"],select,textarea,.wy-menu-vertical li.on a,.wy-menu-vertical li.current>a,.wy-side-nav-search>a,.wy-side-nav-search .wy-dropdown>a,.wy-nav-top a{-webkit-font-smoothing:antialiased}.clearfix{*zoom:1}.clearfix:before,.clearfix:after{display:table;content:""}.clearfix:after{clear:both}/*! - * Font Awesome 4.7.0 by @davegandy - http://fontawesome.io - @fontawesome - * License - http://fontawesome.io/license (Font: SIL OFL 1.1, CSS: MIT License) - */@font-face{font-family:'FontAwesome';src:url("../fonts/fontawesome-webfont.eot?v=4.7.0");src:url("../fonts/fontawesome-webfont.eot?#iefix&v=4.7.0") format("embedded-opentype"),url("../fonts/fontawesome-webfont.woff2?v=4.7.0") format("woff2"),url("../fonts/fontawesome-webfont.woff?v=4.7.0") format("woff"),url("../fonts/fontawesome-webfont.ttf?v=4.7.0") format("truetype"),url("../fonts/fontawesome-webfont.svg?v=4.7.0#fontawesomeregular") format("svg");font-weight:normal;font-style:normal}.fa,.wy-menu-vertical li span.toctree-expand,.wy-menu-vertical li.on a span.toctree-expand,.wy-menu-vertical li.current>a span.toctree-expand,.rst-content .admonition-title,.rst-content h1 .headerlink,.rst-content h2 .headerlink,.rst-content h3 .headerlink,.rst-content h4 .headerlink,.rst-content h5 .headerlink,.rst-content h6 .headerlink,.rst-content dl dt .headerlink,.rst-content p.caption .headerlink,.rst-content table>caption .headerlink,.rst-content .code-block-caption .headerlink,.rst-content tt.download span:first-child,.rst-content code.download span:first-child,.icon{display:inline-block;font:normal normal normal 14px/1 FontAwesome;font-size:inherit;text-rendering:auto;-webkit-font-smoothing:antialiased;-moz-osx-font-smoothing:grayscale}.fa-lg{font-size:1.3333333333em;line-height:.75em;vertical-align:-15%}.fa-2x{font-size:2em}.fa-3x{font-size:3em}.fa-4x{font-size:4em}.fa-5x{font-size:5em}.fa-fw{width:1.2857142857em;text-align:center}.fa-ul{padding-left:0;margin-left:2.1428571429em;list-style-type:none}.fa-ul>li{position:relative}.fa-li{position:absolute;left:-2.1428571429em;width:2.1428571429em;top:.1428571429em;text-align:center}.fa-li.fa-lg{left:-1.8571428571em}.fa-border{padding:.2em .25em .15em;border:solid 0.08em #eee;border-radius:.1em}.fa-pull-left{float:left}.fa-pull-right{float:right}.fa.fa-pull-left,.wy-menu-vertical li span.fa-pull-left.toctree-expand,.wy-menu-vertical li.on a span.fa-pull-left.toctree-expand,.wy-menu-vertical li.current>a span.fa-pull-left.toctree-expand,.rst-content .fa-pull-left.admonition-title,.rst-content h1 .fa-pull-left.headerlink,.rst-content h2 .fa-pull-left.headerlink,.rst-content h3 .fa-pull-left.headerlink,.rst-content h4 .fa-pull-left.headerlink,.rst-content h5 .fa-pull-left.headerlink,.rst-content h6 .fa-pull-left.headerlink,.rst-content dl dt .fa-pull-left.headerlink,.rst-content p.caption .fa-pull-left.headerlink,.rst-content table>caption .fa-pull-left.headerlink,.rst-content .code-block-caption .fa-pull-left.headerlink,.rst-content tt.download span.fa-pull-left:first-child,.rst-content code.download span.fa-pull-left:first-child,.fa-pull-left.icon{margin-right:.3em}.fa.fa-pull-right,.wy-menu-vertical li span.fa-pull-right.toctree-expand,.wy-menu-vertical li.on a span.fa-pull-right.toctree-expand,.wy-menu-vertical li.current>a span.fa-pull-right.toctree-expand,.rst-content .fa-pull-right.admonition-title,.rst-content h1 .fa-pull-right.headerlink,.rst-content h2 .fa-pull-right.headerlink,.rst-content h3 .fa-pull-right.headerlink,.rst-content h4 .fa-pull-right.headerlink,.rst-content h5 .fa-pull-right.headerlink,.rst-content h6 .fa-pull-right.headerlink,.rst-content dl dt .fa-pull-right.headerlink,.rst-content p.caption .fa-pull-right.headerlink,.rst-content table>caption .fa-pull-right.headerlink,.rst-content .code-block-caption .fa-pull-right.headerlink,.rst-content tt.download span.fa-pull-right:first-child,.rst-content code.download span.fa-pull-right:first-child,.fa-pull-right.icon{margin-left:.3em}.pull-right{float:right}.pull-left{float:left}.fa.pull-left,.wy-menu-vertical li span.pull-left.toctree-expand,.wy-menu-vertical li.on a span.pull-left.toctree-expand,.wy-menu-vertical li.current>a span.pull-left.toctree-expand,.rst-content .pull-left.admonition-title,.rst-content h1 .pull-left.headerlink,.rst-content h2 .pull-left.headerlink,.rst-content h3 .pull-left.headerlink,.rst-content h4 .pull-left.headerlink,.rst-content h5 .pull-left.headerlink,.rst-content h6 .pull-left.headerlink,.rst-content dl dt .pull-left.headerlink,.rst-content p.caption .pull-left.headerlink,.rst-content table>caption .pull-left.headerlink,.rst-content .code-block-caption .pull-left.headerlink,.rst-content tt.download span.pull-left:first-child,.rst-content code.download span.pull-left:first-child,.pull-left.icon{margin-right:.3em}.fa.pull-right,.wy-menu-vertical li span.pull-right.toctree-expand,.wy-menu-vertical li.on a span.pull-right.toctree-expand,.wy-menu-vertical li.current>a span.pull-right.toctree-expand,.rst-content .pull-right.admonition-title,.rst-content h1 .pull-right.headerlink,.rst-content h2 .pull-right.headerlink,.rst-content h3 .pull-right.headerlink,.rst-content h4 .pull-right.headerlink,.rst-content h5 .pull-right.headerlink,.rst-content h6 .pull-right.headerlink,.rst-content dl dt .pull-right.headerlink,.rst-content p.caption .pull-right.headerlink,.rst-content table>caption .pull-right.headerlink,.rst-content .code-block-caption .pull-right.headerlink,.rst-content tt.download span.pull-right:first-child,.rst-content code.download span.pull-right:first-child,.pull-right.icon{margin-left:.3em}.fa-spin{-webkit-animation:fa-spin 2s infinite linear;animation:fa-spin 2s infinite linear}.fa-pulse{-webkit-animation:fa-spin 1s infinite steps(8);animation:fa-spin 1s infinite steps(8)}@-webkit-keyframes fa-spin{0%{-webkit-transform:rotate(0deg);transform:rotate(0deg)}100%{-webkit-transform:rotate(359deg);transform:rotate(359deg)}}@keyframes fa-spin{0%{-webkit-transform:rotate(0deg);transform:rotate(0deg)}100%{-webkit-transform:rotate(359deg);transform:rotate(359deg)}}.fa-rotate-90{-ms-filter:"progid:DXImageTransform.Microsoft.BasicImage(rotation=1)";-webkit-transform:rotate(90deg);-ms-transform:rotate(90deg);transform:rotate(90deg)}.fa-rotate-180{-ms-filter:"progid:DXImageTransform.Microsoft.BasicImage(rotation=2)";-webkit-transform:rotate(180deg);-ms-transform:rotate(180deg);transform:rotate(180deg)}.fa-rotate-270{-ms-filter:"progid:DXImageTransform.Microsoft.BasicImage(rotation=3)";-webkit-transform:rotate(270deg);-ms-transform:rotate(270deg);transform:rotate(270deg)}.fa-flip-horizontal{-ms-filter:"progid:DXImageTransform.Microsoft.BasicImage(rotation=0, mirror=1)";-webkit-transform:scale(-1, 1);-ms-transform:scale(-1, 1);transform:scale(-1, 1)}.fa-flip-vertical{-ms-filter:"progid:DXImageTransform.Microsoft.BasicImage(rotation=2, mirror=1)";-webkit-transform:scale(1, -1);-ms-transform:scale(1, -1);transform:scale(1, -1)}:root .fa-rotate-90,:root .fa-rotate-180,:root .fa-rotate-270,:root .fa-flip-horizontal,:root .fa-flip-vertical{filter:none}.fa-stack{position:relative;display:inline-block;width:2em;height:2em;line-height:2em;vertical-align:middle}.fa-stack-1x,.fa-stack-2x{position:absolute;left:0;width:100%;text-align:center}.fa-stack-1x{line-height:inherit}.fa-stack-2x{font-size:2em}.fa-inverse{color:#fff}.fa-glass:before{content:""}.fa-music:before{content:"ï€"}.fa-search:before,.icon-search:before{content:""}.fa-envelope-o:before{content:""}.fa-heart:before{content:""}.fa-star:before{content:""}.fa-star-o:before{content:""}.fa-user:before{content:""}.fa-film:before{content:""}.fa-th-large:before{content:""}.fa-th:before{content:""}.fa-th-list:before{content:""}.fa-check:before{content:""}.fa-remove:before,.fa-close:before,.fa-times:before{content:"ï€"}.fa-search-plus:before{content:""}.fa-search-minus:before{content:"ï€"}.fa-power-off:before{content:""}.fa-signal:before{content:""}.fa-gear:before,.fa-cog:before{content:""}.fa-trash-o:before{content:""}.fa-home:before,.icon-home:before{content:""}.fa-file-o:before{content:""}.fa-clock-o:before{content:""}.fa-road:before{content:""}.fa-download:before,.rst-content tt.download span:first-child:before,.rst-content code.download span:first-child:before{content:""}.fa-arrow-circle-o-down:before{content:""}.fa-arrow-circle-o-up:before{content:""}.fa-inbox:before{content:""}.fa-play-circle-o:before{content:"ï€"}.fa-rotate-right:before,.fa-repeat:before{content:""}.fa-refresh:before{content:""}.fa-list-alt:before{content:""}.fa-lock:before{content:""}.fa-flag:before{content:""}.fa-headphones:before{content:""}.fa-volume-off:before{content:""}.fa-volume-down:before{content:""}.fa-volume-up:before{content:""}.fa-qrcode:before{content:""}.fa-barcode:before{content:""}.fa-tag:before{content:""}.fa-tags:before{content:""}.fa-book:before,.icon-book:before{content:""}.fa-bookmark:before{content:""}.fa-print:before{content:""}.fa-camera:before{content:""}.fa-font:before{content:""}.fa-bold:before{content:""}.fa-italic:before{content:""}.fa-text-height:before{content:""}.fa-text-width:before{content:""}.fa-align-left:before{content:""}.fa-align-center:before{content:""}.fa-align-right:before{content:""}.fa-align-justify:before{content:""}.fa-list:before{content:""}.fa-dedent:before,.fa-outdent:before{content:""}.fa-indent:before{content:""}.fa-video-camera:before{content:""}.fa-photo:before,.fa-image:before,.fa-picture-o:before{content:""}.fa-pencil:before{content:"ï€"}.fa-map-marker:before{content:"ï"}.fa-adjust:before{content:"ï‚"}.fa-tint:before{content:"ïƒ"}.fa-edit:before,.fa-pencil-square-o:before{content:"ï„"}.fa-share-square-o:before{content:"ï…"}.fa-check-square-o:before{content:"ï†"}.fa-arrows:before{content:"ï‡"}.fa-step-backward:before{content:"ïˆ"}.fa-fast-backward:before{content:"ï‰"}.fa-backward:before{content:"ïŠ"}.fa-play:before{content:"ï‹"}.fa-pause:before{content:"ïŒ"}.fa-stop:before{content:"ï"}.fa-forward:before{content:"ïŽ"}.fa-fast-forward:before{content:"ï"}.fa-step-forward:before{content:"ï‘"}.fa-eject:before{content:"ï’"}.fa-chevron-left:before{content:"ï“"}.fa-chevron-right:before{content:"ï”"}.fa-plus-circle:before{content:"ï•"}.fa-minus-circle:before{content:"ï–"}.fa-times-circle:before,.wy-inline-validate.wy-inline-validate-danger .wy-input-context:before{content:"ï—"}.fa-check-circle:before,.wy-inline-validate.wy-inline-validate-success .wy-input-context:before{content:"ï˜"}.fa-question-circle:before{content:"ï™"}.fa-info-circle:before{content:"ïš"}.fa-crosshairs:before{content:"ï›"}.fa-times-circle-o:before{content:"ïœ"}.fa-check-circle-o:before{content:"ï"}.fa-ban:before{content:"ïž"}.fa-arrow-left:before{content:"ï "}.fa-arrow-right:before{content:"ï¡"}.fa-arrow-up:before{content:"ï¢"}.fa-arrow-down:before{content:"ï£"}.fa-mail-forward:before,.fa-share:before{content:"ï¤"}.fa-expand:before{content:"ï¥"}.fa-compress:before{content:"ï¦"}.fa-plus:before{content:"ï§"}.fa-minus:before{content:"ï¨"}.fa-asterisk:before{content:"ï©"}.fa-exclamation-circle:before,.wy-inline-validate.wy-inline-validate-warning .wy-input-context:before,.wy-inline-validate.wy-inline-validate-info .wy-input-context:before,.rst-content .admonition-title:before{content:"ïª"}.fa-gift:before{content:"ï«"}.fa-leaf:before{content:"ï¬"}.fa-fire:before,.icon-fire:before{content:"ï­"}.fa-eye:before{content:"ï®"}.fa-eye-slash:before{content:"ï°"}.fa-warning:before,.fa-exclamation-triangle:before{content:"ï±"}.fa-plane:before{content:"ï²"}.fa-calendar:before{content:"ï³"}.fa-random:before{content:"ï´"}.fa-comment:before{content:"ïµ"}.fa-magnet:before{content:"ï¶"}.fa-chevron-up:before{content:"ï·"}.fa-chevron-down:before{content:"ï¸"}.fa-retweet:before{content:"ï¹"}.fa-shopping-cart:before{content:"ïº"}.fa-folder:before{content:"ï»"}.fa-folder-open:before{content:"ï¼"}.fa-arrows-v:before{content:"ï½"}.fa-arrows-h:before{content:"ï¾"}.fa-bar-chart-o:before,.fa-bar-chart:before{content:"ï‚€"}.fa-twitter-square:before{content:"ï‚"}.fa-facebook-square:before{content:"ï‚‚"}.fa-camera-retro:before{content:""}.fa-key:before{content:"ï‚„"}.fa-gears:before,.fa-cogs:before{content:"ï‚…"}.fa-comments:before{content:""}.fa-thumbs-o-up:before{content:""}.fa-thumbs-o-down:before{content:""}.fa-star-half:before{content:""}.fa-heart-o:before{content:"ï‚Š"}.fa-sign-out:before{content:"ï‚‹"}.fa-linkedin-square:before{content:"ï‚Œ"}.fa-thumb-tack:before{content:"ï‚"}.fa-external-link:before{content:"ï‚Ž"}.fa-sign-in:before{content:"ï‚"}.fa-trophy:before{content:"ï‚‘"}.fa-github-square:before{content:"ï‚’"}.fa-upload:before{content:"ï‚“"}.fa-lemon-o:before{content:"ï‚”"}.fa-phone:before{content:"ï‚•"}.fa-square-o:before{content:"ï‚–"}.fa-bookmark-o:before{content:"ï‚—"}.fa-phone-square:before{content:""}.fa-twitter:before{content:"ï‚™"}.fa-facebook-f:before,.fa-facebook:before{content:"ï‚š"}.fa-github:before,.icon-github:before{content:"ï‚›"}.fa-unlock:before{content:"ï‚œ"}.fa-credit-card:before{content:"ï‚"}.fa-feed:before,.fa-rss:before{content:"ï‚ž"}.fa-hdd-o:before{content:"ï‚ "}.fa-bullhorn:before{content:"ï‚¡"}.fa-bell:before{content:""}.fa-certificate:before{content:"ï‚£"}.fa-hand-o-right:before{content:""}.fa-hand-o-left:before{content:"ï‚¥"}.fa-hand-o-up:before{content:""}.fa-hand-o-down:before{content:""}.fa-arrow-circle-left:before,.icon-circle-arrow-left:before{content:""}.fa-arrow-circle-right:before,.icon-circle-arrow-right:before{content:"ï‚©"}.fa-arrow-circle-up:before{content:""}.fa-arrow-circle-down:before{content:"ï‚«"}.fa-globe:before{content:""}.fa-wrench:before{content:"ï‚­"}.fa-tasks:before{content:"ï‚®"}.fa-filter:before{content:"ï‚°"}.fa-briefcase:before{content:""}.fa-arrows-alt:before{content:""}.fa-group:before,.fa-users:before{content:""}.fa-chain:before,.fa-link:before,.icon-link:before{content:"ïƒ"}.fa-cloud:before{content:""}.fa-flask:before{content:""}.fa-cut:before,.fa-scissors:before{content:""}.fa-copy:before,.fa-files-o:before{content:""}.fa-paperclip:before{content:""}.fa-save:before,.fa-floppy-o:before{content:""}.fa-square:before{content:""}.fa-navicon:before,.fa-reorder:before,.fa-bars:before{content:""}.fa-list-ul:before{content:""}.fa-list-ol:before{content:""}.fa-strikethrough:before{content:""}.fa-underline:before{content:"ïƒ"}.fa-table:before{content:""}.fa-magic:before{content:"ïƒ"}.fa-truck:before{content:""}.fa-pinterest:before{content:""}.fa-pinterest-square:before{content:""}.fa-google-plus-square:before{content:""}.fa-google-plus:before{content:""}.fa-money:before{content:""}.fa-caret-down:before,.wy-dropdown .caret:before,.icon-caret-down:before{content:""}.fa-caret-up:before{content:""}.fa-caret-left:before{content:""}.fa-caret-right:before{content:""}.fa-columns:before{content:""}.fa-unsorted:before,.fa-sort:before{content:""}.fa-sort-down:before,.fa-sort-desc:before{content:"ïƒ"}.fa-sort-up:before,.fa-sort-asc:before{content:""}.fa-envelope:before{content:""}.fa-linkedin:before{content:""}.fa-rotate-left:before,.fa-undo:before{content:""}.fa-legal:before,.fa-gavel:before{content:""}.fa-dashboard:before,.fa-tachometer:before{content:""}.fa-comment-o:before{content:""}.fa-comments-o:before{content:""}.fa-flash:before,.fa-bolt:before{content:""}.fa-sitemap:before{content:""}.fa-umbrella:before{content:""}.fa-paste:before,.fa-clipboard:before{content:""}.fa-lightbulb-o:before{content:""}.fa-exchange:before{content:""}.fa-cloud-download:before{content:""}.fa-cloud-upload:before{content:""}.fa-user-md:before{content:""}.fa-stethoscope:before{content:""}.fa-suitcase:before{content:""}.fa-bell-o:before{content:"ï‚¢"}.fa-coffee:before{content:""}.fa-cutlery:before{content:""}.fa-file-text-o:before{content:""}.fa-building-o:before{content:""}.fa-hospital-o:before{content:""}.fa-ambulance:before{content:""}.fa-medkit:before{content:""}.fa-fighter-jet:before{content:""}.fa-beer:before{content:""}.fa-h-square:before{content:""}.fa-plus-square:before{content:""}.fa-angle-double-left:before{content:"ï„€"}.fa-angle-double-right:before{content:"ï„"}.fa-angle-double-up:before{content:"ï„‚"}.fa-angle-double-down:before{content:""}.fa-angle-left:before{content:"ï„„"}.fa-angle-right:before{content:"ï„…"}.fa-angle-up:before{content:""}.fa-angle-down:before{content:""}.fa-desktop:before{content:""}.fa-laptop:before{content:""}.fa-tablet:before{content:"ï„Š"}.fa-mobile-phone:before,.fa-mobile:before{content:"ï„‹"}.fa-circle-o:before{content:"ï„Œ"}.fa-quote-left:before{content:"ï„"}.fa-quote-right:before{content:"ï„Ž"}.fa-spinner:before{content:"ï„"}.fa-circle:before{content:"ï„‘"}.fa-mail-reply:before,.fa-reply:before{content:"ï„’"}.fa-github-alt:before{content:"ï„“"}.fa-folder-o:before{content:"ï„”"}.fa-folder-open-o:before{content:"ï„•"}.fa-smile-o:before{content:""}.fa-frown-o:before{content:"ï„™"}.fa-meh-o:before{content:"ï„š"}.fa-gamepad:before{content:"ï„›"}.fa-keyboard-o:before{content:"ï„œ"}.fa-flag-o:before{content:"ï„"}.fa-flag-checkered:before{content:"ï„ž"}.fa-terminal:before{content:"ï„ "}.fa-code:before{content:"ï„¡"}.fa-mail-reply-all:before,.fa-reply-all:before{content:"ï„¢"}.fa-star-half-empty:before,.fa-star-half-full:before,.fa-star-half-o:before{content:"ï„£"}.fa-location-arrow:before{content:""}.fa-crop:before{content:"ï„¥"}.fa-code-fork:before{content:""}.fa-unlink:before,.fa-chain-broken:before{content:""}.fa-question:before{content:""}.fa-info:before{content:"ï„©"}.fa-exclamation:before{content:""}.fa-superscript:before{content:"ï„«"}.fa-subscript:before{content:""}.fa-eraser:before{content:"ï„­"}.fa-puzzle-piece:before{content:"ï„®"}.fa-microphone:before{content:"ï„°"}.fa-microphone-slash:before{content:""}.fa-shield:before{content:""}.fa-calendar-o:before{content:""}.fa-fire-extinguisher:before{content:"ï„´"}.fa-rocket:before{content:""}.fa-maxcdn:before{content:""}.fa-chevron-circle-left:before{content:"ï„·"}.fa-chevron-circle-right:before{content:""}.fa-chevron-circle-up:before{content:""}.fa-chevron-circle-down:before{content:""}.fa-html5:before{content:"ï„»"}.fa-css3:before{content:""}.fa-anchor:before{content:""}.fa-unlock-alt:before{content:""}.fa-bullseye:before{content:"ï…€"}.fa-ellipsis-h:before{content:"ï…"}.fa-ellipsis-v:before{content:"ï…‚"}.fa-rss-square:before{content:"ï…ƒ"}.fa-play-circle:before{content:"ï…„"}.fa-ticket:before{content:"ï……"}.fa-minus-square:before{content:"ï…†"}.fa-minus-square-o:before,.wy-menu-vertical li.on a span.toctree-expand:before,.wy-menu-vertical li.current>a span.toctree-expand:before{content:"ï…‡"}.fa-level-up:before{content:"ï…ˆ"}.fa-level-down:before{content:"ï…‰"}.fa-check-square:before{content:"ï…Š"}.fa-pencil-square:before{content:"ï…‹"}.fa-external-link-square:before{content:"ï…Œ"}.fa-share-square:before{content:"ï…"}.fa-compass:before{content:"ï…Ž"}.fa-toggle-down:before,.fa-caret-square-o-down:before{content:"ï…"}.fa-toggle-up:before,.fa-caret-square-o-up:before{content:"ï…‘"}.fa-toggle-right:before,.fa-caret-square-o-right:before{content:"ï…’"}.fa-euro:before,.fa-eur:before{content:"ï…“"}.fa-gbp:before{content:"ï…”"}.fa-dollar:before,.fa-usd:before{content:"ï…•"}.fa-rupee:before,.fa-inr:before{content:"ï…–"}.fa-cny:before,.fa-rmb:before,.fa-yen:before,.fa-jpy:before{content:"ï…—"}.fa-ruble:before,.fa-rouble:before,.fa-rub:before{content:"ï…˜"}.fa-won:before,.fa-krw:before{content:"ï…™"}.fa-bitcoin:before,.fa-btc:before{content:"ï…š"}.fa-file:before{content:"ï…›"}.fa-file-text:before{content:"ï…œ"}.fa-sort-alpha-asc:before{content:"ï…"}.fa-sort-alpha-desc:before{content:"ï…ž"}.fa-sort-amount-asc:before{content:"ï… "}.fa-sort-amount-desc:before{content:"ï…¡"}.fa-sort-numeric-asc:before{content:"ï…¢"}.fa-sort-numeric-desc:before{content:"ï…£"}.fa-thumbs-up:before{content:"ï…¤"}.fa-thumbs-down:before{content:"ï…¥"}.fa-youtube-square:before{content:"ï…¦"}.fa-youtube:before{content:"ï…§"}.fa-xing:before{content:"ï…¨"}.fa-xing-square:before{content:"ï…©"}.fa-youtube-play:before{content:"ï…ª"}.fa-dropbox:before{content:"ï…«"}.fa-stack-overflow:before{content:"ï…¬"}.fa-instagram:before{content:"ï…­"}.fa-flickr:before{content:"ï…®"}.fa-adn:before{content:"ï…°"}.fa-bitbucket:before,.icon-bitbucket:before{content:"ï…±"}.fa-bitbucket-square:before{content:"ï…²"}.fa-tumblr:before{content:"ï…³"}.fa-tumblr-square:before{content:"ï…´"}.fa-long-arrow-down:before{content:"ï…µ"}.fa-long-arrow-up:before{content:"ï…¶"}.fa-long-arrow-left:before{content:"ï…·"}.fa-long-arrow-right:before{content:"ï…¸"}.fa-apple:before{content:"ï…¹"}.fa-windows:before{content:"ï…º"}.fa-android:before{content:"ï…»"}.fa-linux:before{content:"ï…¼"}.fa-dribbble:before{content:"ï…½"}.fa-skype:before{content:"ï…¾"}.fa-foursquare:before{content:""}.fa-trello:before{content:"ï†"}.fa-female:before{content:""}.fa-male:before{content:""}.fa-gittip:before,.fa-gratipay:before{content:""}.fa-sun-o:before{content:""}.fa-moon-o:before{content:""}.fa-archive:before{content:""}.fa-bug:before{content:""}.fa-vk:before{content:""}.fa-weibo:before{content:""}.fa-renren:before{content:""}.fa-pagelines:before{content:""}.fa-stack-exchange:before{content:"ï†"}.fa-arrow-circle-o-right:before{content:""}.fa-arrow-circle-o-left:before{content:"ï†"}.fa-toggle-left:before,.fa-caret-square-o-left:before{content:""}.fa-dot-circle-o:before{content:""}.fa-wheelchair:before{content:""}.fa-vimeo-square:before{content:""}.fa-turkish-lira:before,.fa-try:before{content:""}.fa-plus-square-o:before,.wy-menu-vertical li span.toctree-expand:before{content:""}.fa-space-shuttle:before{content:""}.fa-slack:before{content:""}.fa-envelope-square:before{content:""}.fa-wordpress:before{content:""}.fa-openid:before{content:""}.fa-institution:before,.fa-bank:before,.fa-university:before{content:""}.fa-mortar-board:before,.fa-graduation-cap:before{content:"ï†"}.fa-yahoo:before{content:""}.fa-google:before{content:""}.fa-reddit:before{content:""}.fa-reddit-square:before{content:""}.fa-stumbleupon-circle:before{content:""}.fa-stumbleupon:before{content:""}.fa-delicious:before{content:""}.fa-digg:before{content:""}.fa-pied-piper-pp:before{content:""}.fa-pied-piper-alt:before{content:""}.fa-drupal:before{content:""}.fa-joomla:before{content:""}.fa-language:before{content:""}.fa-fax:before{content:""}.fa-building:before{content:""}.fa-child:before{content:""}.fa-paw:before{content:""}.fa-spoon:before{content:""}.fa-cube:before{content:""}.fa-cubes:before{content:""}.fa-behance:before{content:""}.fa-behance-square:before{content:""}.fa-steam:before{content:""}.fa-steam-square:before{content:""}.fa-recycle:before{content:""}.fa-automobile:before,.fa-car:before{content:""}.fa-cab:before,.fa-taxi:before{content:""}.fa-tree:before{content:""}.fa-spotify:before{content:""}.fa-deviantart:before{content:""}.fa-soundcloud:before{content:""}.fa-database:before{content:""}.fa-file-pdf-o:before{content:"ï‡"}.fa-file-word-o:before{content:""}.fa-file-excel-o:before{content:""}.fa-file-powerpoint-o:before{content:""}.fa-file-photo-o:before,.fa-file-picture-o:before,.fa-file-image-o:before{content:""}.fa-file-zip-o:before,.fa-file-archive-o:before{content:""}.fa-file-sound-o:before,.fa-file-audio-o:before{content:""}.fa-file-movie-o:before,.fa-file-video-o:before{content:""}.fa-file-code-o:before{content:""}.fa-vine:before{content:""}.fa-codepen:before{content:""}.fa-jsfiddle:before{content:""}.fa-life-bouy:before,.fa-life-buoy:before,.fa-life-saver:before,.fa-support:before,.fa-life-ring:before{content:"ï‡"}.fa-circle-o-notch:before{content:""}.fa-ra:before,.fa-resistance:before,.fa-rebel:before{content:"ï‡"}.fa-ge:before,.fa-empire:before{content:""}.fa-git-square:before{content:""}.fa-git:before{content:""}.fa-y-combinator-square:before,.fa-yc-square:before,.fa-hacker-news:before{content:""}.fa-tencent-weibo:before{content:""}.fa-qq:before{content:""}.fa-wechat:before,.fa-weixin:before{content:""}.fa-send:before,.fa-paper-plane:before{content:""}.fa-send-o:before,.fa-paper-plane-o:before{content:""}.fa-history:before{content:""}.fa-circle-thin:before{content:""}.fa-header:before{content:""}.fa-paragraph:before{content:"ï‡"}.fa-sliders:before{content:""}.fa-share-alt:before{content:""}.fa-share-alt-square:before{content:""}.fa-bomb:before{content:""}.fa-soccer-ball-o:before,.fa-futbol-o:before{content:""}.fa-tty:before{content:""}.fa-binoculars:before{content:""}.fa-plug:before{content:""}.fa-slideshare:before{content:""}.fa-twitch:before{content:""}.fa-yelp:before{content:""}.fa-newspaper-o:before{content:""}.fa-wifi:before{content:""}.fa-calculator:before{content:""}.fa-paypal:before{content:""}.fa-google-wallet:before{content:""}.fa-cc-visa:before{content:""}.fa-cc-mastercard:before{content:""}.fa-cc-discover:before{content:""}.fa-cc-amex:before{content:""}.fa-cc-paypal:before{content:""}.fa-cc-stripe:before{content:""}.fa-bell-slash:before{content:""}.fa-bell-slash-o:before{content:""}.fa-trash:before{content:""}.fa-copyright:before{content:""}.fa-at:before{content:""}.fa-eyedropper:before{content:""}.fa-paint-brush:before{content:""}.fa-birthday-cake:before{content:""}.fa-area-chart:before{content:""}.fa-pie-chart:before{content:""}.fa-line-chart:before{content:"ïˆ"}.fa-lastfm:before{content:""}.fa-lastfm-square:before{content:""}.fa-toggle-off:before{content:""}.fa-toggle-on:before{content:""}.fa-bicycle:before{content:""}.fa-bus:before{content:""}.fa-ioxhost:before{content:""}.fa-angellist:before{content:""}.fa-cc:before{content:""}.fa-shekel:before,.fa-sheqel:before,.fa-ils:before{content:""}.fa-meanpath:before{content:""}.fa-buysellads:before{content:"ïˆ"}.fa-connectdevelop:before{content:""}.fa-dashcube:before{content:"ïˆ"}.fa-forumbee:before{content:""}.fa-leanpub:before{content:""}.fa-sellsy:before{content:""}.fa-shirtsinbulk:before{content:""}.fa-simplybuilt:before{content:""}.fa-skyatlas:before{content:""}.fa-cart-plus:before{content:""}.fa-cart-arrow-down:before{content:""}.fa-diamond:before{content:""}.fa-ship:before{content:""}.fa-user-secret:before{content:""}.fa-motorcycle:before{content:""}.fa-street-view:before{content:"ïˆ"}.fa-heartbeat:before{content:""}.fa-venus:before{content:""}.fa-mars:before{content:""}.fa-mercury:before{content:""}.fa-intersex:before,.fa-transgender:before{content:""}.fa-transgender-alt:before{content:""}.fa-venus-double:before{content:""}.fa-mars-double:before{content:""}.fa-venus-mars:before{content:""}.fa-mars-stroke:before{content:""}.fa-mars-stroke-v:before{content:""}.fa-mars-stroke-h:before{content:""}.fa-neuter:before{content:""}.fa-genderless:before{content:""}.fa-facebook-official:before{content:""}.fa-pinterest-p:before{content:""}.fa-whatsapp:before{content:""}.fa-server:before{content:""}.fa-user-plus:before{content:""}.fa-user-times:before{content:""}.fa-hotel:before,.fa-bed:before{content:""}.fa-viacoin:before{content:""}.fa-train:before{content:""}.fa-subway:before{content:""}.fa-medium:before{content:""}.fa-yc:before,.fa-y-combinator:before{content:""}.fa-optin-monster:before{content:""}.fa-opencart:before{content:""}.fa-expeditedssl:before{content:""}.fa-battery-4:before,.fa-battery:before,.fa-battery-full:before{content:""}.fa-battery-3:before,.fa-battery-three-quarters:before{content:"ï‰"}.fa-battery-2:before,.fa-battery-half:before{content:""}.fa-battery-1:before,.fa-battery-quarter:before{content:""}.fa-battery-0:before,.fa-battery-empty:before{content:""}.fa-mouse-pointer:before{content:""}.fa-i-cursor:before{content:""}.fa-object-group:before{content:""}.fa-object-ungroup:before{content:""}.fa-sticky-note:before{content:""}.fa-sticky-note-o:before{content:""}.fa-cc-jcb:before{content:""}.fa-cc-diners-club:before{content:""}.fa-clone:before{content:"ï‰"}.fa-balance-scale:before{content:""}.fa-hourglass-o:before{content:"ï‰"}.fa-hourglass-1:before,.fa-hourglass-start:before{content:""}.fa-hourglass-2:before,.fa-hourglass-half:before{content:""}.fa-hourglass-3:before,.fa-hourglass-end:before{content:""}.fa-hourglass:before{content:""}.fa-hand-grab-o:before,.fa-hand-rock-o:before{content:""}.fa-hand-stop-o:before,.fa-hand-paper-o:before{content:""}.fa-hand-scissors-o:before{content:""}.fa-hand-lizard-o:before{content:""}.fa-hand-spock-o:before{content:""}.fa-hand-pointer-o:before{content:""}.fa-hand-peace-o:before{content:""}.fa-trademark:before{content:""}.fa-registered:before{content:"ï‰"}.fa-creative-commons:before{content:""}.fa-gg:before{content:""}.fa-gg-circle:before{content:""}.fa-tripadvisor:before{content:""}.fa-odnoklassniki:before{content:""}.fa-odnoklassniki-square:before{content:""}.fa-get-pocket:before{content:""}.fa-wikipedia-w:before{content:""}.fa-safari:before{content:""}.fa-chrome:before{content:""}.fa-firefox:before{content:""}.fa-opera:before{content:""}.fa-internet-explorer:before{content:""}.fa-tv:before,.fa-television:before{content:""}.fa-contao:before{content:""}.fa-500px:before{content:""}.fa-amazon:before{content:""}.fa-calendar-plus-o:before{content:""}.fa-calendar-minus-o:before{content:""}.fa-calendar-times-o:before{content:""}.fa-calendar-check-o:before{content:""}.fa-industry:before{content:""}.fa-map-pin:before{content:""}.fa-map-signs:before{content:""}.fa-map-o:before{content:""}.fa-map:before{content:""}.fa-commenting:before{content:""}.fa-commenting-o:before{content:""}.fa-houzz:before{content:""}.fa-vimeo:before{content:""}.fa-black-tie:before{content:""}.fa-fonticons:before{content:""}.fa-reddit-alien:before{content:"ïŠ"}.fa-edge:before{content:""}.fa-credit-card-alt:before{content:""}.fa-codiepie:before{content:""}.fa-modx:before{content:""}.fa-fort-awesome:before{content:""}.fa-usb:before{content:""}.fa-product-hunt:before{content:""}.fa-mixcloud:before{content:""}.fa-scribd:before{content:""}.fa-pause-circle:before{content:""}.fa-pause-circle-o:before{content:""}.fa-stop-circle:before{content:"ïŠ"}.fa-stop-circle-o:before{content:""}.fa-shopping-bag:before{content:"ïŠ"}.fa-shopping-basket:before{content:""}.fa-hashtag:before{content:""}.fa-bluetooth:before{content:""}.fa-bluetooth-b:before{content:""}.fa-percent:before{content:""}.fa-gitlab:before,.icon-gitlab:before{content:""}.fa-wpbeginner:before{content:""}.fa-wpforms:before{content:""}.fa-envira:before{content:""}.fa-universal-access:before{content:""}.fa-wheelchair-alt:before{content:""}.fa-question-circle-o:before{content:""}.fa-blind:before{content:"ïŠ"}.fa-audio-description:before{content:""}.fa-volume-control-phone:before{content:""}.fa-braille:before{content:""}.fa-assistive-listening-systems:before{content:""}.fa-asl-interpreting:before,.fa-american-sign-language-interpreting:before{content:""}.fa-deafness:before,.fa-hard-of-hearing:before,.fa-deaf:before{content:""}.fa-glide:before{content:""}.fa-glide-g:before{content:""}.fa-signing:before,.fa-sign-language:before{content:""}.fa-low-vision:before{content:""}.fa-viadeo:before{content:""}.fa-viadeo-square:before{content:""}.fa-snapchat:before{content:""}.fa-snapchat-ghost:before{content:""}.fa-snapchat-square:before{content:""}.fa-pied-piper:before{content:""}.fa-first-order:before{content:""}.fa-yoast:before{content:""}.fa-themeisle:before{content:""}.fa-google-plus-circle:before,.fa-google-plus-official:before{content:""}.fa-fa:before,.fa-font-awesome:before{content:""}.fa-handshake-o:before{content:""}.fa-envelope-open:before{content:""}.fa-envelope-open-o:before{content:""}.fa-linode:before{content:""}.fa-address-book:before{content:""}.fa-address-book-o:before{content:""}.fa-vcard:before,.fa-address-card:before{content:""}.fa-vcard-o:before,.fa-address-card-o:before{content:""}.fa-user-circle:before{content:""}.fa-user-circle-o:before{content:""}.fa-user-o:before{content:"ï‹€"}.fa-id-badge:before{content:"ï‹"}.fa-drivers-license:before,.fa-id-card:before{content:"ï‹‚"}.fa-drivers-license-o:before,.fa-id-card-o:before{content:""}.fa-quora:before{content:"ï‹„"}.fa-free-code-camp:before{content:"ï‹…"}.fa-telegram:before{content:""}.fa-thermometer-4:before,.fa-thermometer:before,.fa-thermometer-full:before{content:""}.fa-thermometer-3:before,.fa-thermometer-three-quarters:before{content:""}.fa-thermometer-2:before,.fa-thermometer-half:before{content:""}.fa-thermometer-1:before,.fa-thermometer-quarter:before{content:"ï‹Š"}.fa-thermometer-0:before,.fa-thermometer-empty:before{content:"ï‹‹"}.fa-shower:before{content:"ï‹Œ"}.fa-bathtub:before,.fa-s15:before,.fa-bath:before{content:"ï‹"}.fa-podcast:before{content:"ï‹Ž"}.fa-window-maximize:before{content:"ï‹"}.fa-window-minimize:before{content:"ï‹‘"}.fa-window-restore:before{content:"ï‹’"}.fa-times-rectangle:before,.fa-window-close:before{content:"ï‹“"}.fa-times-rectangle-o:before,.fa-window-close-o:before{content:"ï‹”"}.fa-bandcamp:before{content:"ï‹•"}.fa-grav:before{content:"ï‹–"}.fa-etsy:before{content:"ï‹—"}.fa-imdb:before{content:""}.fa-ravelry:before{content:"ï‹™"}.fa-eercast:before{content:"ï‹š"}.fa-microchip:before{content:"ï‹›"}.fa-snowflake-o:before{content:"ï‹œ"}.fa-superpowers:before{content:"ï‹"}.fa-wpexplorer:before{content:"ï‹ž"}.fa-meetup:before{content:"ï‹ "}.sr-only{position:absolute;width:1px;height:1px;padding:0;margin:-1px;overflow:hidden;clip:rect(0, 0, 0, 0);border:0}.sr-only-focusable:active,.sr-only-focusable:focus{position:static;width:auto;height:auto;margin:0;overflow:visible;clip:auto}.fa,.wy-menu-vertical li span.toctree-expand,.wy-menu-vertical li.on a span.toctree-expand,.wy-menu-vertical li.current>a span.toctree-expand,.rst-content .admonition-title,.rst-content h1 .headerlink,.rst-content h2 .headerlink,.rst-content h3 .headerlink,.rst-content h4 .headerlink,.rst-content h5 .headerlink,.rst-content h6 .headerlink,.rst-content dl dt .headerlink,.rst-content p.caption .headerlink,.rst-content table>caption .headerlink,.rst-content .code-block-caption .headerlink,.rst-content tt.download span:first-child,.rst-content code.download span:first-child,.icon,.wy-dropdown .caret,.wy-inline-validate.wy-inline-validate-success .wy-input-context,.wy-inline-validate.wy-inline-validate-danger .wy-input-context,.wy-inline-validate.wy-inline-validate-warning .wy-input-context,.wy-inline-validate.wy-inline-validate-info .wy-input-context{font-family:inherit}.fa:before,.wy-menu-vertical li span.toctree-expand:before,.wy-menu-vertical li.on a span.toctree-expand:before,.wy-menu-vertical li.current>a span.toctree-expand:before,.rst-content .admonition-title:before,.rst-content h1 .headerlink:before,.rst-content h2 .headerlink:before,.rst-content h3 .headerlink:before,.rst-content h4 .headerlink:before,.rst-content h5 .headerlink:before,.rst-content h6 .headerlink:before,.rst-content dl dt .headerlink:before,.rst-content p.caption .headerlink:before,.rst-content table>caption .headerlink:before,.rst-content .code-block-caption .headerlink:before,.rst-content tt.download span:first-child:before,.rst-content code.download span:first-child:before,.icon:before,.wy-dropdown .caret:before,.wy-inline-validate.wy-inline-validate-success .wy-input-context:before,.wy-inline-validate.wy-inline-validate-danger .wy-input-context:before,.wy-inline-validate.wy-inline-validate-warning .wy-input-context:before,.wy-inline-validate.wy-inline-validate-info .wy-input-context:before{font-family:"FontAwesome";display:inline-block;font-style:normal;font-weight:normal;line-height:1;text-decoration:inherit}a .fa,a .wy-menu-vertical li span.toctree-expand,.wy-menu-vertical li a span.toctree-expand,.wy-menu-vertical li.on a span.toctree-expand,.wy-menu-vertical li.current>a span.toctree-expand,a .rst-content .admonition-title,.rst-content a .admonition-title,a .rst-content h1 .headerlink,.rst-content h1 a .headerlink,a .rst-content h2 .headerlink,.rst-content h2 a .headerlink,a .rst-content h3 .headerlink,.rst-content h3 a .headerlink,a .rst-content h4 .headerlink,.rst-content h4 a .headerlink,a .rst-content h5 .headerlink,.rst-content h5 a .headerlink,a .rst-content h6 .headerlink,.rst-content h6 a .headerlink,a .rst-content dl dt .headerlink,.rst-content dl dt a .headerlink,a .rst-content p.caption .headerlink,.rst-content p.caption a .headerlink,a .rst-content table>caption .headerlink,.rst-content table>caption a .headerlink,a .rst-content .code-block-caption .headerlink,.rst-content .code-block-caption a .headerlink,a .rst-content tt.download span:first-child,.rst-content tt.download a span:first-child,a .rst-content code.download span:first-child,.rst-content code.download a span:first-child,a .icon{display:inline-block;text-decoration:inherit}.btn .fa,.btn .wy-menu-vertical li span.toctree-expand,.wy-menu-vertical li .btn span.toctree-expand,.btn .wy-menu-vertical li.on a span.toctree-expand,.wy-menu-vertical li.on a .btn span.toctree-expand,.btn .wy-menu-vertical li.current>a span.toctree-expand,.wy-menu-vertical li.current>a .btn span.toctree-expand,.btn .rst-content .admonition-title,.rst-content .btn .admonition-title,.btn .rst-content h1 .headerlink,.rst-content h1 .btn .headerlink,.btn .rst-content h2 .headerlink,.rst-content h2 .btn .headerlink,.btn .rst-content h3 .headerlink,.rst-content h3 .btn .headerlink,.btn .rst-content h4 .headerlink,.rst-content h4 .btn .headerlink,.btn .rst-content h5 .headerlink,.rst-content h5 .btn .headerlink,.btn .rst-content h6 .headerlink,.rst-content h6 .btn .headerlink,.btn .rst-content dl dt .headerlink,.rst-content dl dt .btn .headerlink,.btn .rst-content p.caption .headerlink,.rst-content p.caption .btn .headerlink,.btn .rst-content table>caption .headerlink,.rst-content table>caption .btn .headerlink,.btn .rst-content .code-block-caption .headerlink,.rst-content .code-block-caption .btn .headerlink,.btn .rst-content tt.download span:first-child,.rst-content tt.download .btn span:first-child,.btn .rst-content code.download span:first-child,.rst-content code.download .btn span:first-child,.btn .icon,.nav .fa,.nav .wy-menu-vertical li span.toctree-expand,.wy-menu-vertical li .nav span.toctree-expand,.nav .wy-menu-vertical li.on a span.toctree-expand,.wy-menu-vertical li.on a .nav span.toctree-expand,.nav .wy-menu-vertical li.current>a span.toctree-expand,.wy-menu-vertical li.current>a .nav span.toctree-expand,.nav .rst-content .admonition-title,.rst-content .nav .admonition-title,.nav .rst-content h1 .headerlink,.rst-content h1 .nav .headerlink,.nav .rst-content h2 .headerlink,.rst-content h2 .nav .headerlink,.nav .rst-content h3 .headerlink,.rst-content h3 .nav .headerlink,.nav .rst-content h4 .headerlink,.rst-content h4 .nav .headerlink,.nav .rst-content h5 .headerlink,.rst-content h5 .nav .headerlink,.nav .rst-content h6 .headerlink,.rst-content h6 .nav .headerlink,.nav .rst-content dl dt .headerlink,.rst-content dl dt .nav .headerlink,.nav .rst-content p.caption .headerlink,.rst-content p.caption .nav .headerlink,.nav .rst-content table>caption .headerlink,.rst-content table>caption .nav .headerlink,.nav .rst-content .code-block-caption .headerlink,.rst-content .code-block-caption .nav .headerlink,.nav .rst-content tt.download span:first-child,.rst-content tt.download .nav span:first-child,.nav .rst-content code.download span:first-child,.rst-content code.download .nav span:first-child,.nav .icon{display:inline}.btn .fa.fa-large,.btn .wy-menu-vertical li span.fa-large.toctree-expand,.wy-menu-vertical li .btn span.fa-large.toctree-expand,.btn .rst-content .fa-large.admonition-title,.rst-content .btn .fa-large.admonition-title,.btn .rst-content h1 .fa-large.headerlink,.rst-content h1 .btn .fa-large.headerlink,.btn .rst-content h2 .fa-large.headerlink,.rst-content h2 .btn .fa-large.headerlink,.btn .rst-content h3 .fa-large.headerlink,.rst-content h3 .btn .fa-large.headerlink,.btn .rst-content h4 .fa-large.headerlink,.rst-content h4 .btn .fa-large.headerlink,.btn .rst-content h5 .fa-large.headerlink,.rst-content h5 .btn .fa-large.headerlink,.btn .rst-content h6 .fa-large.headerlink,.rst-content h6 .btn .fa-large.headerlink,.btn .rst-content dl dt .fa-large.headerlink,.rst-content dl dt .btn .fa-large.headerlink,.btn .rst-content p.caption .fa-large.headerlink,.rst-content p.caption .btn .fa-large.headerlink,.btn .rst-content table>caption .fa-large.headerlink,.rst-content table>caption .btn .fa-large.headerlink,.btn .rst-content .code-block-caption .fa-large.headerlink,.rst-content .code-block-caption .btn .fa-large.headerlink,.btn .rst-content tt.download span.fa-large:first-child,.rst-content tt.download .btn span.fa-large:first-child,.btn .rst-content code.download span.fa-large:first-child,.rst-content code.download .btn span.fa-large:first-child,.btn .fa-large.icon,.nav .fa.fa-large,.nav .wy-menu-vertical li span.fa-large.toctree-expand,.wy-menu-vertical li .nav span.fa-large.toctree-expand,.nav .rst-content .fa-large.admonition-title,.rst-content .nav .fa-large.admonition-title,.nav .rst-content h1 .fa-large.headerlink,.rst-content h1 .nav .fa-large.headerlink,.nav .rst-content h2 .fa-large.headerlink,.rst-content h2 .nav .fa-large.headerlink,.nav .rst-content h3 .fa-large.headerlink,.rst-content h3 .nav .fa-large.headerlink,.nav .rst-content h4 .fa-large.headerlink,.rst-content h4 .nav .fa-large.headerlink,.nav .rst-content h5 .fa-large.headerlink,.rst-content h5 .nav .fa-large.headerlink,.nav .rst-content h6 .fa-large.headerlink,.rst-content h6 .nav .fa-large.headerlink,.nav .rst-content dl dt .fa-large.headerlink,.rst-content dl dt .nav .fa-large.headerlink,.nav .rst-content p.caption .fa-large.headerlink,.rst-content p.caption .nav .fa-large.headerlink,.nav .rst-content table>caption .fa-large.headerlink,.rst-content table>caption .nav .fa-large.headerlink,.nav .rst-content .code-block-caption .fa-large.headerlink,.rst-content .code-block-caption .nav .fa-large.headerlink,.nav .rst-content tt.download span.fa-large:first-child,.rst-content tt.download .nav span.fa-large:first-child,.nav .rst-content code.download span.fa-large:first-child,.rst-content code.download .nav span.fa-large:first-child,.nav .fa-large.icon{line-height:.9em}.btn .fa.fa-spin,.btn .wy-menu-vertical li span.fa-spin.toctree-expand,.wy-menu-vertical li .btn span.fa-spin.toctree-expand,.btn .rst-content .fa-spin.admonition-title,.rst-content .btn .fa-spin.admonition-title,.btn .rst-content h1 .fa-spin.headerlink,.rst-content h1 .btn .fa-spin.headerlink,.btn .rst-content h2 .fa-spin.headerlink,.rst-content h2 .btn .fa-spin.headerlink,.btn .rst-content h3 .fa-spin.headerlink,.rst-content h3 .btn .fa-spin.headerlink,.btn .rst-content h4 .fa-spin.headerlink,.rst-content h4 .btn .fa-spin.headerlink,.btn .rst-content h5 .fa-spin.headerlink,.rst-content h5 .btn .fa-spin.headerlink,.btn .rst-content h6 .fa-spin.headerlink,.rst-content h6 .btn .fa-spin.headerlink,.btn .rst-content dl dt .fa-spin.headerlink,.rst-content dl dt .btn .fa-spin.headerlink,.btn .rst-content p.caption .fa-spin.headerlink,.rst-content p.caption .btn .fa-spin.headerlink,.btn .rst-content table>caption .fa-spin.headerlink,.rst-content table>caption .btn .fa-spin.headerlink,.btn .rst-content .code-block-caption .fa-spin.headerlink,.rst-content .code-block-caption .btn .fa-spin.headerlink,.btn .rst-content tt.download span.fa-spin:first-child,.rst-content tt.download .btn span.fa-spin:first-child,.btn .rst-content code.download span.fa-spin:first-child,.rst-content code.download .btn span.fa-spin:first-child,.btn .fa-spin.icon,.nav .fa.fa-spin,.nav .wy-menu-vertical li span.fa-spin.toctree-expand,.wy-menu-vertical li .nav span.fa-spin.toctree-expand,.nav .rst-content .fa-spin.admonition-title,.rst-content .nav .fa-spin.admonition-title,.nav .rst-content h1 .fa-spin.headerlink,.rst-content h1 .nav .fa-spin.headerlink,.nav .rst-content h2 .fa-spin.headerlink,.rst-content h2 .nav .fa-spin.headerlink,.nav .rst-content h3 .fa-spin.headerlink,.rst-content h3 .nav .fa-spin.headerlink,.nav .rst-content h4 .fa-spin.headerlink,.rst-content h4 .nav .fa-spin.headerlink,.nav .rst-content h5 .fa-spin.headerlink,.rst-content h5 .nav .fa-spin.headerlink,.nav .rst-content h6 .fa-spin.headerlink,.rst-content h6 .nav .fa-spin.headerlink,.nav .rst-content dl dt .fa-spin.headerlink,.rst-content dl dt .nav .fa-spin.headerlink,.nav .rst-content p.caption .fa-spin.headerlink,.rst-content p.caption .nav .fa-spin.headerlink,.nav .rst-content table>caption .fa-spin.headerlink,.rst-content table>caption .nav .fa-spin.headerlink,.nav .rst-content .code-block-caption .fa-spin.headerlink,.rst-content .code-block-caption .nav .fa-spin.headerlink,.nav .rst-content tt.download span.fa-spin:first-child,.rst-content tt.download .nav span.fa-spin:first-child,.nav .rst-content code.download span.fa-spin:first-child,.rst-content code.download .nav span.fa-spin:first-child,.nav .fa-spin.icon{display:inline-block}.btn.fa:before,.wy-menu-vertical li span.btn.toctree-expand:before,.rst-content .btn.admonition-title:before,.rst-content h1 .btn.headerlink:before,.rst-content h2 .btn.headerlink:before,.rst-content h3 .btn.headerlink:before,.rst-content h4 .btn.headerlink:before,.rst-content h5 .btn.headerlink:before,.rst-content h6 .btn.headerlink:before,.rst-content dl dt .btn.headerlink:before,.rst-content p.caption .btn.headerlink:before,.rst-content table>caption .btn.headerlink:before,.rst-content .code-block-caption .btn.headerlink:before,.rst-content tt.download span.btn:first-child:before,.rst-content code.download span.btn:first-child:before,.btn.icon:before{opacity:.5;-webkit-transition:opacity .05s ease-in;-moz-transition:opacity .05s ease-in;transition:opacity .05s ease-in}.btn.fa:hover:before,.wy-menu-vertical li span.btn.toctree-expand:hover:before,.rst-content .btn.admonition-title:hover:before,.rst-content h1 .btn.headerlink:hover:before,.rst-content h2 .btn.headerlink:hover:before,.rst-content h3 .btn.headerlink:hover:before,.rst-content h4 .btn.headerlink:hover:before,.rst-content h5 .btn.headerlink:hover:before,.rst-content h6 .btn.headerlink:hover:before,.rst-content dl dt .btn.headerlink:hover:before,.rst-content p.caption .btn.headerlink:hover:before,.rst-content table>caption .btn.headerlink:hover:before,.rst-content .code-block-caption .btn.headerlink:hover:before,.rst-content tt.download span.btn:first-child:hover:before,.rst-content code.download span.btn:first-child:hover:before,.btn.icon:hover:before{opacity:1}.btn-mini .fa:before,.btn-mini .wy-menu-vertical li span.toctree-expand:before,.wy-menu-vertical li .btn-mini span.toctree-expand:before,.btn-mini .rst-content .admonition-title:before,.rst-content .btn-mini .admonition-title:before,.btn-mini .rst-content h1 .headerlink:before,.rst-content h1 .btn-mini .headerlink:before,.btn-mini .rst-content h2 .headerlink:before,.rst-content h2 .btn-mini .headerlink:before,.btn-mini .rst-content h3 .headerlink:before,.rst-content h3 .btn-mini .headerlink:before,.btn-mini .rst-content h4 .headerlink:before,.rst-content h4 .btn-mini .headerlink:before,.btn-mini .rst-content h5 .headerlink:before,.rst-content h5 .btn-mini .headerlink:before,.btn-mini .rst-content h6 .headerlink:before,.rst-content h6 .btn-mini .headerlink:before,.btn-mini .rst-content dl dt .headerlink:before,.rst-content dl dt .btn-mini .headerlink:before,.btn-mini .rst-content p.caption .headerlink:before,.rst-content p.caption .btn-mini .headerlink:before,.btn-mini .rst-content table>caption .headerlink:before,.rst-content table>caption .btn-mini .headerlink:before,.btn-mini .rst-content .code-block-caption .headerlink:before,.rst-content .code-block-caption .btn-mini .headerlink:before,.btn-mini .rst-content tt.download span:first-child:before,.rst-content tt.download .btn-mini span:first-child:before,.btn-mini .rst-content code.download span:first-child:before,.rst-content code.download .btn-mini span:first-child:before,.btn-mini .icon:before{font-size:14px;vertical-align:-15%}.wy-alert,.rst-content .note,.rst-content .attention,.rst-content .caution,.rst-content .danger,.rst-content .error,.rst-content .hint,.rst-content .important,.rst-content .tip,.rst-content .warning,.rst-content .seealso,.rst-content .admonition-todo,.rst-content .admonition{padding:12px;line-height:24px;margin-bottom:24px;background:#e7f2fa}.wy-alert-title,.rst-content .admonition-title{color:#fff;font-weight:bold;display:block;color:#fff;background:#6ab0de;margin:-12px;padding:6px 12px;margin-bottom:12px}.wy-alert.wy-alert-danger,.rst-content .wy-alert-danger.note,.rst-content .wy-alert-danger.attention,.rst-content .wy-alert-danger.caution,.rst-content .danger,.rst-content .error,.rst-content .wy-alert-danger.hint,.rst-content .wy-alert-danger.important,.rst-content .wy-alert-danger.tip,.rst-content .wy-alert-danger.warning,.rst-content .wy-alert-danger.seealso,.rst-content .wy-alert-danger.admonition-todo,.rst-content .wy-alert-danger.admonition{background:#fdf3f2}.wy-alert.wy-alert-danger .wy-alert-title,.rst-content .wy-alert-danger.note .wy-alert-title,.rst-content .wy-alert-danger.attention .wy-alert-title,.rst-content .wy-alert-danger.caution .wy-alert-title,.rst-content .danger .wy-alert-title,.rst-content .error .wy-alert-title,.rst-content .wy-alert-danger.hint .wy-alert-title,.rst-content .wy-alert-danger.important .wy-alert-title,.rst-content .wy-alert-danger.tip .wy-alert-title,.rst-content .wy-alert-danger.warning .wy-alert-title,.rst-content .wy-alert-danger.seealso .wy-alert-title,.rst-content .wy-alert-danger.admonition-todo .wy-alert-title,.rst-content .wy-alert-danger.admonition .wy-alert-title,.wy-alert.wy-alert-danger .rst-content .admonition-title,.rst-content .wy-alert.wy-alert-danger .admonition-title,.rst-content .wy-alert-danger.note .admonition-title,.rst-content .wy-alert-danger.attention .admonition-title,.rst-content .wy-alert-danger.caution .admonition-title,.rst-content .danger .admonition-title,.rst-content .error .admonition-title,.rst-content .wy-alert-danger.hint .admonition-title,.rst-content .wy-alert-danger.important .admonition-title,.rst-content .wy-alert-danger.tip .admonition-title,.rst-content .wy-alert-danger.warning .admonition-title,.rst-content .wy-alert-danger.seealso .admonition-title,.rst-content .wy-alert-danger.admonition-todo .admonition-title,.rst-content .wy-alert-danger.admonition .admonition-title{background:#f29f97}.wy-alert.wy-alert-warning,.rst-content .wy-alert-warning.note,.rst-content .attention,.rst-content .caution,.rst-content .wy-alert-warning.danger,.rst-content .wy-alert-warning.error,.rst-content .wy-alert-warning.hint,.rst-content .wy-alert-warning.important,.rst-content .wy-alert-warning.tip,.rst-content .warning,.rst-content .wy-alert-warning.seealso,.rst-content .admonition-todo,.rst-content .wy-alert-warning.admonition{background:#ffedcc}.wy-alert.wy-alert-warning .wy-alert-title,.rst-content .wy-alert-warning.note .wy-alert-title,.rst-content .attention .wy-alert-title,.rst-content .caution .wy-alert-title,.rst-content .wy-alert-warning.danger .wy-alert-title,.rst-content .wy-alert-warning.error .wy-alert-title,.rst-content .wy-alert-warning.hint .wy-alert-title,.rst-content .wy-alert-warning.important .wy-alert-title,.rst-content .wy-alert-warning.tip .wy-alert-title,.rst-content .warning .wy-alert-title,.rst-content .wy-alert-warning.seealso .wy-alert-title,.rst-content .admonition-todo .wy-alert-title,.rst-content .wy-alert-warning.admonition .wy-alert-title,.wy-alert.wy-alert-warning .rst-content .admonition-title,.rst-content .wy-alert.wy-alert-warning .admonition-title,.rst-content .wy-alert-warning.note .admonition-title,.rst-content .attention .admonition-title,.rst-content .caution .admonition-title,.rst-content .wy-alert-warning.danger .admonition-title,.rst-content .wy-alert-warning.error .admonition-title,.rst-content .wy-alert-warning.hint .admonition-title,.rst-content .wy-alert-warning.important .admonition-title,.rst-content .wy-alert-warning.tip .admonition-title,.rst-content .warning .admonition-title,.rst-content .wy-alert-warning.seealso .admonition-title,.rst-content .admonition-todo .admonition-title,.rst-content .wy-alert-warning.admonition .admonition-title{background:#f0b37e}.wy-alert.wy-alert-info,.rst-content .note,.rst-content .wy-alert-info.attention,.rst-content .wy-alert-info.caution,.rst-content .wy-alert-info.danger,.rst-content .wy-alert-info.error,.rst-content .wy-alert-info.hint,.rst-content .wy-alert-info.important,.rst-content .wy-alert-info.tip,.rst-content .wy-alert-info.warning,.rst-content .seealso,.rst-content .wy-alert-info.admonition-todo,.rst-content .wy-alert-info.admonition{background:#e7f2fa}.wy-alert.wy-alert-info .wy-alert-title,.rst-content .note .wy-alert-title,.rst-content .wy-alert-info.attention .wy-alert-title,.rst-content .wy-alert-info.caution .wy-alert-title,.rst-content .wy-alert-info.danger .wy-alert-title,.rst-content .wy-alert-info.error .wy-alert-title,.rst-content .wy-alert-info.hint .wy-alert-title,.rst-content .wy-alert-info.important .wy-alert-title,.rst-content .wy-alert-info.tip .wy-alert-title,.rst-content .wy-alert-info.warning .wy-alert-title,.rst-content .seealso .wy-alert-title,.rst-content .wy-alert-info.admonition-todo .wy-alert-title,.rst-content .wy-alert-info.admonition .wy-alert-title,.wy-alert.wy-alert-info .rst-content .admonition-title,.rst-content .wy-alert.wy-alert-info .admonition-title,.rst-content .note .admonition-title,.rst-content .wy-alert-info.attention .admonition-title,.rst-content .wy-alert-info.caution .admonition-title,.rst-content .wy-alert-info.danger .admonition-title,.rst-content .wy-alert-info.error .admonition-title,.rst-content .wy-alert-info.hint .admonition-title,.rst-content .wy-alert-info.important .admonition-title,.rst-content .wy-alert-info.tip .admonition-title,.rst-content .wy-alert-info.warning .admonition-title,.rst-content .seealso .admonition-title,.rst-content .wy-alert-info.admonition-todo .admonition-title,.rst-content .wy-alert-info.admonition .admonition-title{background:#6ab0de}.wy-alert.wy-alert-success,.rst-content .wy-alert-success.note,.rst-content .wy-alert-success.attention,.rst-content .wy-alert-success.caution,.rst-content .wy-alert-success.danger,.rst-content .wy-alert-success.error,.rst-content .hint,.rst-content .important,.rst-content .tip,.rst-content .wy-alert-success.warning,.rst-content .wy-alert-success.seealso,.rst-content .wy-alert-success.admonition-todo,.rst-content .wy-alert-success.admonition{background:#dbfaf4}.wy-alert.wy-alert-success .wy-alert-title,.rst-content .wy-alert-success.note .wy-alert-title,.rst-content .wy-alert-success.attention .wy-alert-title,.rst-content .wy-alert-success.caution .wy-alert-title,.rst-content .wy-alert-success.danger .wy-alert-title,.rst-content .wy-alert-success.error .wy-alert-title,.rst-content .hint .wy-alert-title,.rst-content .important .wy-alert-title,.rst-content .tip .wy-alert-title,.rst-content .wy-alert-success.warning .wy-alert-title,.rst-content .wy-alert-success.seealso .wy-alert-title,.rst-content .wy-alert-success.admonition-todo .wy-alert-title,.rst-content .wy-alert-success.admonition .wy-alert-title,.wy-alert.wy-alert-success .rst-content .admonition-title,.rst-content .wy-alert.wy-alert-success .admonition-title,.rst-content .wy-alert-success.note .admonition-title,.rst-content .wy-alert-success.attention .admonition-title,.rst-content .wy-alert-success.caution .admonition-title,.rst-content .wy-alert-success.danger .admonition-title,.rst-content .wy-alert-success.error .admonition-title,.rst-content .hint .admonition-title,.rst-content .important .admonition-title,.rst-content .tip .admonition-title,.rst-content .wy-alert-success.warning .admonition-title,.rst-content .wy-alert-success.seealso .admonition-title,.rst-content .wy-alert-success.admonition-todo .admonition-title,.rst-content .wy-alert-success.admonition .admonition-title{background:#1abc9c}.wy-alert.wy-alert-neutral,.rst-content .wy-alert-neutral.note,.rst-content .wy-alert-neutral.attention,.rst-content .wy-alert-neutral.caution,.rst-content .wy-alert-neutral.danger,.rst-content .wy-alert-neutral.error,.rst-content .wy-alert-neutral.hint,.rst-content .wy-alert-neutral.important,.rst-content .wy-alert-neutral.tip,.rst-content .wy-alert-neutral.warning,.rst-content .wy-alert-neutral.seealso,.rst-content .wy-alert-neutral.admonition-todo,.rst-content .wy-alert-neutral.admonition{background:#f3f6f6}.wy-alert.wy-alert-neutral .wy-alert-title,.rst-content .wy-alert-neutral.note .wy-alert-title,.rst-content .wy-alert-neutral.attention .wy-alert-title,.rst-content .wy-alert-neutral.caution .wy-alert-title,.rst-content .wy-alert-neutral.danger .wy-alert-title,.rst-content .wy-alert-neutral.error .wy-alert-title,.rst-content .wy-alert-neutral.hint .wy-alert-title,.rst-content .wy-alert-neutral.important .wy-alert-title,.rst-content .wy-alert-neutral.tip .wy-alert-title,.rst-content .wy-alert-neutral.warning .wy-alert-title,.rst-content .wy-alert-neutral.seealso .wy-alert-title,.rst-content .wy-alert-neutral.admonition-todo .wy-alert-title,.rst-content .wy-alert-neutral.admonition .wy-alert-title,.wy-alert.wy-alert-neutral .rst-content .admonition-title,.rst-content .wy-alert.wy-alert-neutral .admonition-title,.rst-content .wy-alert-neutral.note .admonition-title,.rst-content .wy-alert-neutral.attention .admonition-title,.rst-content .wy-alert-neutral.caution .admonition-title,.rst-content .wy-alert-neutral.danger .admonition-title,.rst-content .wy-alert-neutral.error .admonition-title,.rst-content .wy-alert-neutral.hint .admonition-title,.rst-content .wy-alert-neutral.important .admonition-title,.rst-content .wy-alert-neutral.tip .admonition-title,.rst-content .wy-alert-neutral.warning .admonition-title,.rst-content .wy-alert-neutral.seealso .admonition-title,.rst-content .wy-alert-neutral.admonition-todo .admonition-title,.rst-content .wy-alert-neutral.admonition .admonition-title{color:#404040;background:#e1e4e5}.wy-alert.wy-alert-neutral a,.rst-content .wy-alert-neutral.note a,.rst-content .wy-alert-neutral.attention a,.rst-content .wy-alert-neutral.caution a,.rst-content .wy-alert-neutral.danger a,.rst-content .wy-alert-neutral.error a,.rst-content .wy-alert-neutral.hint a,.rst-content .wy-alert-neutral.important a,.rst-content .wy-alert-neutral.tip a,.rst-content .wy-alert-neutral.warning a,.rst-content .wy-alert-neutral.seealso a,.rst-content .wy-alert-neutral.admonition-todo a,.rst-content .wy-alert-neutral.admonition a{color:#2980B9}.wy-alert p:last-child,.rst-content .note p:last-child,.rst-content .attention p:last-child,.rst-content .caution p:last-child,.rst-content .danger p:last-child,.rst-content .error p:last-child,.rst-content .hint p:last-child,.rst-content .important p:last-child,.rst-content .tip p:last-child,.rst-content .warning p:last-child,.rst-content .seealso p:last-child,.rst-content .admonition-todo p:last-child,.rst-content .admonition p:last-child{margin-bottom:0}.wy-tray-container{position:fixed;bottom:0px;left:0;z-index:600}.wy-tray-container li{display:block;width:300px;background:transparent;color:#fff;text-align:center;box-shadow:0 5px 5px 0 rgba(0,0,0,0.1);padding:0 24px;min-width:20%;opacity:0;height:0;line-height:56px;overflow:hidden;-webkit-transition:all .3s ease-in;-moz-transition:all .3s ease-in;transition:all .3s ease-in}.wy-tray-container li.wy-tray-item-success{background:#27AE60}.wy-tray-container li.wy-tray-item-info{background:#2980B9}.wy-tray-container li.wy-tray-item-warning{background:#E67E22}.wy-tray-container li.wy-tray-item-danger{background:#E74C3C}.wy-tray-container li.on{opacity:1;height:56px}@media screen and (max-width: 768px){.wy-tray-container{bottom:auto;top:0;width:100%}.wy-tray-container li{width:100%}}button{font-size:100%;margin:0;vertical-align:baseline;*vertical-align:middle;cursor:pointer;line-height:normal;-webkit-appearance:button;*overflow:visible}button::-moz-focus-inner,input::-moz-focus-inner{border:0;padding:0}button[disabled]{cursor:default}.btn{display:inline-block;border-radius:2px;line-height:normal;white-space:nowrap;text-align:center;cursor:pointer;font-size:100%;padding:6px 12px 8px 12px;color:#fff;border:1px solid rgba(0,0,0,0.1);background-color:#27AE60;text-decoration:none;font-weight:normal;font-family:"Lato","proxima-nova","Helvetica Neue",Arial,sans-serif;box-shadow:0px 1px 2px -1px rgba(255,255,255,0.5) inset,0px -2px 0px 0px rgba(0,0,0,0.1) inset;outline-none:false;vertical-align:middle;*display:inline;zoom:1;-webkit-user-drag:none;-webkit-user-select:none;-moz-user-select:none;-ms-user-select:none;user-select:none;-webkit-transition:all .1s linear;-moz-transition:all .1s linear;transition:all .1s linear}.btn-hover{background:#2e8ece;color:#fff}.btn:hover{background:#2cc36b;color:#fff}.btn:focus{background:#2cc36b;outline:0}.btn:active{box-shadow:0px -1px 0px 0px rgba(0,0,0,0.05) inset,0px 2px 0px 0px rgba(0,0,0,0.1) inset;padding:8px 12px 6px 12px}.btn:visited{color:#fff}.btn:disabled{background-image:none;filter:progid:DXImageTransform.Microsoft.gradient(enabled = false);filter:alpha(opacity=40);opacity:.4;cursor:not-allowed;box-shadow:none}.btn-disabled{background-image:none;filter:progid:DXImageTransform.Microsoft.gradient(enabled = false);filter:alpha(opacity=40);opacity:.4;cursor:not-allowed;box-shadow:none}.btn-disabled:hover,.btn-disabled:focus,.btn-disabled:active{background-image:none;filter:progid:DXImageTransform.Microsoft.gradient(enabled = false);filter:alpha(opacity=40);opacity:.4;cursor:not-allowed;box-shadow:none}.btn::-moz-focus-inner{padding:0;border:0}.btn-small{font-size:80%}.btn-info{background-color:#2980B9 !important}.btn-info:hover{background-color:#2e8ece !important}.btn-neutral{background-color:#f3f6f6 !important;color:#404040 !important}.btn-neutral:hover{background-color:#e5ebeb !important;color:#404040}.btn-neutral:visited{color:#404040 !important}.btn-success{background-color:#27AE60 !important}.btn-success:hover{background-color:#295 !important}.btn-danger{background-color:#E74C3C !important}.btn-danger:hover{background-color:#ea6153 !important}.btn-warning{background-color:#E67E22 !important}.btn-warning:hover{background-color:#e98b39 !important}.btn-invert{background-color:#222}.btn-invert:hover{background-color:#2f2f2f !important}.btn-link{background-color:transparent !important;color:#2980B9;box-shadow:none;border-color:transparent !important}.btn-link:hover{background-color:transparent !important;color:#409ad5 !important;box-shadow:none}.btn-link:active{background-color:transparent !important;color:#409ad5 !important;box-shadow:none}.btn-link:visited{color:#9B59B6}.wy-btn-group .btn,.wy-control .btn{vertical-align:middle}.wy-btn-group{margin-bottom:24px;*zoom:1}.wy-btn-group:before,.wy-btn-group:after{display:table;content:""}.wy-btn-group:after{clear:both}.wy-dropdown{position:relative;display:inline-block}.wy-dropdown-active .wy-dropdown-menu{display:block}.wy-dropdown-menu{position:absolute;left:0;display:none;float:left;top:100%;min-width:100%;background:#fcfcfc;z-index:100;border:solid 1px #cfd7dd;box-shadow:0 2px 2px 0 rgba(0,0,0,0.1);padding:12px}.wy-dropdown-menu>dd>a{display:block;clear:both;color:#404040;white-space:nowrap;font-size:90%;padding:0 12px;cursor:pointer}.wy-dropdown-menu>dd>a:hover{background:#2980B9;color:#fff}.wy-dropdown-menu>dd.divider{border-top:solid 1px #cfd7dd;margin:6px 0}.wy-dropdown-menu>dd.search{padding-bottom:12px}.wy-dropdown-menu>dd.search input[type="search"]{width:100%}.wy-dropdown-menu>dd.call-to-action{background:#e3e3e3;text-transform:uppercase;font-weight:500;font-size:80%}.wy-dropdown-menu>dd.call-to-action:hover{background:#e3e3e3}.wy-dropdown-menu>dd.call-to-action .btn{color:#fff}.wy-dropdown.wy-dropdown-up .wy-dropdown-menu{bottom:100%;top:auto;left:auto;right:0}.wy-dropdown.wy-dropdown-bubble .wy-dropdown-menu{background:#fcfcfc;margin-top:2px}.wy-dropdown.wy-dropdown-bubble .wy-dropdown-menu a{padding:6px 12px}.wy-dropdown.wy-dropdown-bubble .wy-dropdown-menu a:hover{background:#2980B9;color:#fff}.wy-dropdown.wy-dropdown-left .wy-dropdown-menu{right:0;left:auto;text-align:right}.wy-dropdown-arrow:before{content:" ";border-bottom:5px solid #f5f5f5;border-left:5px solid transparent;border-right:5px solid transparent;position:absolute;display:block;top:-4px;left:50%;margin-left:-3px}.wy-dropdown-arrow.wy-dropdown-arrow-left:before{left:11px}.wy-form-stacked select{display:block}.wy-form-aligned input,.wy-form-aligned textarea,.wy-form-aligned select,.wy-form-aligned .wy-help-inline,.wy-form-aligned label{display:inline-block;*display:inline;*zoom:1;vertical-align:middle}.wy-form-aligned .wy-control-group>label{display:inline-block;vertical-align:middle;width:10em;margin:6px 12px 0 0;float:left}.wy-form-aligned .wy-control{float:left}.wy-form-aligned .wy-control label{display:block}.wy-form-aligned .wy-control select{margin-top:6px}fieldset{border:0;margin:0;padding:0}legend{display:block;width:100%;border:0;padding:0;white-space:normal;margin-bottom:24px;font-size:150%;*margin-left:-7px}label{display:block;margin:0 0 .3125em 0;color:#333;font-size:90%}input,select,textarea{font-size:100%;margin:0;vertical-align:baseline;*vertical-align:middle}.wy-control-group{margin-bottom:24px;*zoom:1;max-width:68em;margin-left:auto;margin-right:auto;*zoom:1}.wy-control-group:before,.wy-control-group:after{display:table;content:""}.wy-control-group:after{clear:both}.wy-control-group:before,.wy-control-group:after{display:table;content:""}.wy-control-group:after{clear:both}.wy-control-group.wy-control-group-required>label:after{content:" *";color:#E74C3C}.wy-control-group .wy-form-full,.wy-control-group .wy-form-halves,.wy-control-group .wy-form-thirds{padding-bottom:12px}.wy-control-group .wy-form-full select,.wy-control-group .wy-form-halves select,.wy-control-group .wy-form-thirds select{width:100%}.wy-control-group .wy-form-full input[type="text"],.wy-control-group .wy-form-full input[type="password"],.wy-control-group .wy-form-full input[type="email"],.wy-control-group .wy-form-full input[type="url"],.wy-control-group .wy-form-full input[type="date"],.wy-control-group .wy-form-full input[type="month"],.wy-control-group .wy-form-full input[type="time"],.wy-control-group .wy-form-full input[type="datetime"],.wy-control-group .wy-form-full input[type="datetime-local"],.wy-control-group .wy-form-full input[type="week"],.wy-control-group .wy-form-full input[type="number"],.wy-control-group .wy-form-full input[type="search"],.wy-control-group .wy-form-full input[type="tel"],.wy-control-group .wy-form-full input[type="color"],.wy-control-group .wy-form-halves input[type="text"],.wy-control-group .wy-form-halves input[type="password"],.wy-control-group .wy-form-halves input[type="email"],.wy-control-group .wy-form-halves input[type="url"],.wy-control-group .wy-form-halves input[type="date"],.wy-control-group .wy-form-halves input[type="month"],.wy-control-group .wy-form-halves input[type="time"],.wy-control-group .wy-form-halves input[type="datetime"],.wy-control-group .wy-form-halves input[type="datetime-local"],.wy-control-group .wy-form-halves input[type="week"],.wy-control-group .wy-form-halves input[type="number"],.wy-control-group .wy-form-halves input[type="search"],.wy-control-group .wy-form-halves input[type="tel"],.wy-control-group .wy-form-halves input[type="color"],.wy-control-group .wy-form-thirds input[type="text"],.wy-control-group .wy-form-thirds input[type="password"],.wy-control-group .wy-form-thirds input[type="email"],.wy-control-group .wy-form-thirds input[type="url"],.wy-control-group .wy-form-thirds input[type="date"],.wy-control-group .wy-form-thirds input[type="month"],.wy-control-group .wy-form-thirds input[type="time"],.wy-control-group .wy-form-thirds input[type="datetime"],.wy-control-group .wy-form-thirds input[type="datetime-local"],.wy-control-group .wy-form-thirds input[type="week"],.wy-control-group .wy-form-thirds input[type="number"],.wy-control-group .wy-form-thirds input[type="search"],.wy-control-group .wy-form-thirds input[type="tel"],.wy-control-group .wy-form-thirds input[type="color"]{width:100%}.wy-control-group .wy-form-full{float:left;display:block;margin-right:2.3576515979%;width:100%;margin-right:0}.wy-control-group .wy-form-full:last-child{margin-right:0}.wy-control-group .wy-form-halves{float:left;display:block;margin-right:2.3576515979%;width:48.821174201%}.wy-control-group .wy-form-halves:last-child{margin-right:0}.wy-control-group .wy-form-halves:nth-of-type(2n){margin-right:0}.wy-control-group .wy-form-halves:nth-of-type(2n+1){clear:left}.wy-control-group .wy-form-thirds{float:left;display:block;margin-right:2.3576515979%;width:31.7615656014%}.wy-control-group .wy-form-thirds:last-child{margin-right:0}.wy-control-group .wy-form-thirds:nth-of-type(3n){margin-right:0}.wy-control-group .wy-form-thirds:nth-of-type(3n+1){clear:left}.wy-control-group.wy-control-group-no-input .wy-control{margin:6px 0 0 0;font-size:90%}.wy-control-no-input{display:inline-block;margin:6px 0 0 0;font-size:90%}.wy-control-group.fluid-input input[type="text"],.wy-control-group.fluid-input input[type="password"],.wy-control-group.fluid-input input[type="email"],.wy-control-group.fluid-input input[type="url"],.wy-control-group.fluid-input input[type="date"],.wy-control-group.fluid-input input[type="month"],.wy-control-group.fluid-input input[type="time"],.wy-control-group.fluid-input input[type="datetime"],.wy-control-group.fluid-input input[type="datetime-local"],.wy-control-group.fluid-input input[type="week"],.wy-control-group.fluid-input input[type="number"],.wy-control-group.fluid-input input[type="search"],.wy-control-group.fluid-input input[type="tel"],.wy-control-group.fluid-input input[type="color"]{width:100%}.wy-form-message-inline{display:inline-block;padding-left:.3em;color:#666;vertical-align:middle;font-size:90%}.wy-form-message{display:block;color:#999;font-size:70%;margin-top:.3125em;font-style:italic}.wy-form-message p{font-size:inherit;font-style:italic;margin-bottom:6px}.wy-form-message p:last-child{margin-bottom:0}input{line-height:normal}input[type="button"],input[type="reset"],input[type="submit"]{-webkit-appearance:button;cursor:pointer;font-family:"Lato","proxima-nova","Helvetica Neue",Arial,sans-serif;*overflow:visible}input[type="text"],input[type="password"],input[type="email"],input[type="url"],input[type="date"],input[type="month"],input[type="time"],input[type="datetime"],input[type="datetime-local"],input[type="week"],input[type="number"],input[type="search"],input[type="tel"],input[type="color"]{-webkit-appearance:none;padding:6px;display:inline-block;border:1px solid #ccc;font-size:80%;font-family:"Lato","proxima-nova","Helvetica Neue",Arial,sans-serif;box-shadow:inset 0 1px 3px #ddd;border-radius:0;-webkit-transition:border .3s linear;-moz-transition:border .3s linear;transition:border .3s linear}input[type="datetime-local"]{padding:.34375em .625em}input[disabled]{cursor:default}input[type="checkbox"],input[type="radio"]{-webkit-box-sizing:border-box;-moz-box-sizing:border-box;box-sizing:border-box;padding:0;margin-right:.3125em;*height:13px;*width:13px}input[type="search"]{-webkit-box-sizing:border-box;-moz-box-sizing:border-box;box-sizing:border-box}input[type="search"]::-webkit-search-cancel-button,input[type="search"]::-webkit-search-decoration{-webkit-appearance:none}input[type="text"]:focus,input[type="password"]:focus,input[type="email"]:focus,input[type="url"]:focus,input[type="date"]:focus,input[type="month"]:focus,input[type="time"]:focus,input[type="datetime"]:focus,input[type="datetime-local"]:focus,input[type="week"]:focus,input[type="number"]:focus,input[type="search"]:focus,input[type="tel"]:focus,input[type="color"]:focus{outline:0;outline:thin dotted \9;border-color:#333}input.no-focus:focus{border-color:#ccc !important}input[type="file"]:focus,input[type="radio"]:focus,input[type="checkbox"]:focus{outline:thin dotted #333;outline:1px auto #129FEA}input[type="text"][disabled],input[type="password"][disabled],input[type="email"][disabled],input[type="url"][disabled],input[type="date"][disabled],input[type="month"][disabled],input[type="time"][disabled],input[type="datetime"][disabled],input[type="datetime-local"][disabled],input[type="week"][disabled],input[type="number"][disabled],input[type="search"][disabled],input[type="tel"][disabled],input[type="color"][disabled]{cursor:not-allowed;background-color:#fafafa}input:focus:invalid,textarea:focus:invalid,select:focus:invalid{color:#E74C3C;border:1px solid #E74C3C}input:focus:invalid:focus,textarea:focus:invalid:focus,select:focus:invalid:focus{border-color:#E74C3C}input[type="file"]:focus:invalid:focus,input[type="radio"]:focus:invalid:focus,input[type="checkbox"]:focus:invalid:focus{outline-color:#E74C3C}input.wy-input-large{padding:12px;font-size:100%}textarea{overflow:auto;vertical-align:top;width:100%;font-family:"Lato","proxima-nova","Helvetica Neue",Arial,sans-serif}select,textarea{padding:.5em .625em;display:inline-block;border:1px solid #ccc;font-size:80%;box-shadow:inset 0 1px 3px #ddd;-webkit-transition:border .3s linear;-moz-transition:border .3s linear;transition:border .3s linear}select{border:1px solid #ccc;background-color:#fff}select[multiple]{height:auto}select:focus,textarea:focus{outline:0}select[disabled],textarea[disabled],input[readonly],select[readonly],textarea[readonly]{cursor:not-allowed;background-color:#fafafa}input[type="radio"][disabled],input[type="checkbox"][disabled]{cursor:not-allowed}.wy-checkbox,.wy-radio{margin:6px 0;color:#404040;display:block}.wy-checkbox input,.wy-radio input{vertical-align:baseline}.wy-form-message-inline{display:inline-block;*display:inline;*zoom:1;vertical-align:middle}.wy-input-prefix,.wy-input-suffix{white-space:nowrap;padding:6px}.wy-input-prefix .wy-input-context,.wy-input-suffix .wy-input-context{line-height:27px;padding:0 8px;display:inline-block;font-size:80%;background-color:#f3f6f6;border:solid 1px #ccc;color:#999}.wy-input-suffix .wy-input-context{border-left:0}.wy-input-prefix .wy-input-context{border-right:0}.wy-switch{position:relative;display:block;height:24px;margin-top:12px;cursor:pointer}.wy-switch:before{position:absolute;content:"";display:block;left:0;top:0;width:36px;height:12px;border-radius:4px;background:#ccc;-webkit-transition:all .2s ease-in-out;-moz-transition:all .2s ease-in-out;transition:all .2s ease-in-out}.wy-switch:after{position:absolute;content:"";display:block;width:18px;height:18px;border-radius:4px;background:#999;left:-3px;top:-3px;-webkit-transition:all .2s ease-in-out;-moz-transition:all .2s ease-in-out;transition:all .2s ease-in-out}.wy-switch span{position:absolute;left:48px;display:block;font-size:12px;color:#ccc;line-height:1}.wy-switch.active:before{background:#1e8449}.wy-switch.active:after{left:24px;background:#27AE60}.wy-switch.disabled{cursor:not-allowed;opacity:.8}.wy-control-group.wy-control-group-error .wy-form-message,.wy-control-group.wy-control-group-error>label{color:#E74C3C}.wy-control-group.wy-control-group-error input[type="text"],.wy-control-group.wy-control-group-error input[type="password"],.wy-control-group.wy-control-group-error input[type="email"],.wy-control-group.wy-control-group-error input[type="url"],.wy-control-group.wy-control-group-error input[type="date"],.wy-control-group.wy-control-group-error input[type="month"],.wy-control-group.wy-control-group-error input[type="time"],.wy-control-group.wy-control-group-error input[type="datetime"],.wy-control-group.wy-control-group-error input[type="datetime-local"],.wy-control-group.wy-control-group-error input[type="week"],.wy-control-group.wy-control-group-error input[type="number"],.wy-control-group.wy-control-group-error input[type="search"],.wy-control-group.wy-control-group-error input[type="tel"],.wy-control-group.wy-control-group-error input[type="color"]{border:solid 1px #E74C3C}.wy-control-group.wy-control-group-error textarea{border:solid 1px #E74C3C}.wy-inline-validate{white-space:nowrap}.wy-inline-validate .wy-input-context{padding:.5em .625em;display:inline-block;font-size:80%}.wy-inline-validate.wy-inline-validate-success .wy-input-context{color:#27AE60}.wy-inline-validate.wy-inline-validate-danger .wy-input-context{color:#E74C3C}.wy-inline-validate.wy-inline-validate-warning .wy-input-context{color:#E67E22}.wy-inline-validate.wy-inline-validate-info .wy-input-context{color:#2980B9}.rotate-90{-webkit-transform:rotate(90deg);-moz-transform:rotate(90deg);-ms-transform:rotate(90deg);-o-transform:rotate(90deg);transform:rotate(90deg)}.rotate-180{-webkit-transform:rotate(180deg);-moz-transform:rotate(180deg);-ms-transform:rotate(180deg);-o-transform:rotate(180deg);transform:rotate(180deg)}.rotate-270{-webkit-transform:rotate(270deg);-moz-transform:rotate(270deg);-ms-transform:rotate(270deg);-o-transform:rotate(270deg);transform:rotate(270deg)}.mirror{-webkit-transform:scaleX(-1);-moz-transform:scaleX(-1);-ms-transform:scaleX(-1);-o-transform:scaleX(-1);transform:scaleX(-1)}.mirror.rotate-90{-webkit-transform:scaleX(-1) rotate(90deg);-moz-transform:scaleX(-1) rotate(90deg);-ms-transform:scaleX(-1) rotate(90deg);-o-transform:scaleX(-1) rotate(90deg);transform:scaleX(-1) rotate(90deg)}.mirror.rotate-180{-webkit-transform:scaleX(-1) rotate(180deg);-moz-transform:scaleX(-1) rotate(180deg);-ms-transform:scaleX(-1) rotate(180deg);-o-transform:scaleX(-1) rotate(180deg);transform:scaleX(-1) rotate(180deg)}.mirror.rotate-270{-webkit-transform:scaleX(-1) rotate(270deg);-moz-transform:scaleX(-1) rotate(270deg);-ms-transform:scaleX(-1) rotate(270deg);-o-transform:scaleX(-1) rotate(270deg);transform:scaleX(-1) rotate(270deg)}@media only screen and (max-width: 480px){.wy-form button[type="submit"]{margin:.7em 0 0}.wy-form input[type="text"],.wy-form input[type="password"],.wy-form input[type="email"],.wy-form input[type="url"],.wy-form input[type="date"],.wy-form input[type="month"],.wy-form input[type="time"],.wy-form input[type="datetime"],.wy-form input[type="datetime-local"],.wy-form input[type="week"],.wy-form input[type="number"],.wy-form input[type="search"],.wy-form input[type="tel"],.wy-form input[type="color"]{margin-bottom:.3em;display:block}.wy-form label{margin-bottom:.3em;display:block}.wy-form input[type="password"],.wy-form input[type="email"],.wy-form input[type="url"],.wy-form input[type="date"],.wy-form input[type="month"],.wy-form input[type="time"],.wy-form input[type="datetime"],.wy-form input[type="datetime-local"],.wy-form input[type="week"],.wy-form input[type="number"],.wy-form input[type="search"],.wy-form input[type="tel"],.wy-form input[type="color"]{margin-bottom:0}.wy-form-aligned .wy-control-group label{margin-bottom:.3em;text-align:left;display:block;width:100%}.wy-form-aligned .wy-control{margin:1.5em 0 0 0}.wy-form .wy-help-inline,.wy-form-message-inline,.wy-form-message{display:block;font-size:80%;padding:6px 0}}@media screen and (max-width: 768px){.tablet-hide{display:none}}@media screen and (max-width: 480px){.mobile-hide{display:none}}.float-left{float:left}.float-right{float:right}.full-width{width:100%}.wy-table,.rst-content table.docutils,.rst-content table.field-list{border-collapse:collapse;border-spacing:0;empty-cells:show;margin-bottom:24px}.wy-table caption,.rst-content table.docutils caption,.rst-content table.field-list caption{color:#000;font:italic 85%/1 arial,sans-serif;padding:1em 0;text-align:center}.wy-table td,.rst-content table.docutils td,.rst-content table.field-list td,.wy-table th,.rst-content table.docutils th,.rst-content table.field-list th{font-size:90%;margin:0;overflow:visible;padding:8px 16px}.wy-table td:first-child,.rst-content table.docutils td:first-child,.rst-content table.field-list td:first-child,.wy-table th:first-child,.rst-content table.docutils th:first-child,.rst-content table.field-list th:first-child{border-left-width:0}.wy-table thead,.rst-content table.docutils thead,.rst-content table.field-list thead{color:#000;text-align:left;vertical-align:bottom;white-space:nowrap}.wy-table thead th,.rst-content table.docutils thead th,.rst-content table.field-list thead th{font-weight:bold;border-bottom:solid 2px #e1e4e5}.wy-table td,.rst-content table.docutils td,.rst-content table.field-list td{background-color:transparent;vertical-align:middle}.wy-table td p,.rst-content table.docutils td p,.rst-content table.field-list td p{line-height:18px}.wy-table td p:last-child,.rst-content table.docutils td p:last-child,.rst-content table.field-list td p:last-child{margin-bottom:0}.wy-table .wy-table-cell-min,.rst-content table.docutils .wy-table-cell-min,.rst-content table.field-list .wy-table-cell-min{width:1%;padding-right:0}.wy-table .wy-table-cell-min input[type=checkbox],.rst-content table.docutils .wy-table-cell-min input[type=checkbox],.rst-content table.field-list .wy-table-cell-min input[type=checkbox],.wy-table .wy-table-cell-min input[type=checkbox],.rst-content table.docutils .wy-table-cell-min input[type=checkbox],.rst-content table.field-list .wy-table-cell-min input[type=checkbox]{margin:0}.wy-table-secondary{color:gray;font-size:90%}.wy-table-tertiary{color:gray;font-size:80%}.wy-table-odd td,.wy-table-striped tr:nth-child(2n-1) td,.rst-content table.docutils:not(.field-list) tr:nth-child(2n-1) td{background-color:#f3f6f6}.wy-table-backed{background-color:#f3f6f6}.wy-table-bordered-all,.rst-content table.docutils{border:1px solid #e1e4e5}.wy-table-bordered-all td,.rst-content table.docutils td{border-bottom:1px solid #e1e4e5;border-left:1px solid #e1e4e5}.wy-table-bordered-all tbody>tr:last-child td,.rst-content table.docutils tbody>tr:last-child td{border-bottom-width:0}.wy-table-bordered{border:1px solid #e1e4e5}.wy-table-bordered-rows td{border-bottom:1px solid #e1e4e5}.wy-table-bordered-rows tbody>tr:last-child td{border-bottom-width:0}.wy-table-horizontal tbody>tr:last-child td{border-bottom-width:0}.wy-table-horizontal td,.wy-table-horizontal th{border-width:0 0 1px 0;border-bottom:1px solid #e1e4e5}.wy-table-horizontal tbody>tr:last-child td{border-bottom-width:0}.wy-table-responsive{margin-bottom:24px;max-width:100%;overflow:auto}.wy-table-responsive table{margin-bottom:0 !important}.wy-table-responsive table td,.wy-table-responsive table th{white-space:nowrap}a{color:#2980B9;text-decoration:none;cursor:pointer}a:hover{color:#3091d1}a:visited{color:#9B59B6}html{height:100%;overflow-x:hidden}body{font-family:"Lato","proxima-nova","Helvetica Neue",Arial,sans-serif;font-weight:normal;color:#404040;min-height:100%;overflow-x:hidden;background:#edf0f2}.wy-text-left{text-align:left}.wy-text-center{text-align:center}.wy-text-right{text-align:right}.wy-text-large{font-size:120%}.wy-text-normal{font-size:100%}.wy-text-small,small{font-size:80%}.wy-text-strike{text-decoration:line-through}.wy-text-warning{color:#E67E22 !important}a.wy-text-warning:hover{color:#eb9950 !important}.wy-text-info{color:#2980B9 !important}a.wy-text-info:hover{color:#409ad5 !important}.wy-text-success{color:#27AE60 !important}a.wy-text-success:hover{color:#36d278 !important}.wy-text-danger{color:#E74C3C !important}a.wy-text-danger:hover{color:#ed7669 !important}.wy-text-neutral{color:#404040 !important}a.wy-text-neutral:hover{color:#595959 !important}h1,h2,.rst-content .toctree-wrapper p.caption,h3,h4,h5,h6,legend{margin-top:0;font-weight:700;font-family:"Roboto Slab","ff-tisa-web-pro","Georgia",Arial,sans-serif}p{line-height:24px;margin:0;font-size:16px;margin-bottom:24px}h1{font-size:175%}h2,.rst-content .toctree-wrapper p.caption{font-size:150%}h3{font-size:125%}h4{font-size:115%}h5{font-size:110%}h6{font-size:100%}hr{display:block;height:1px;border:0;border-top:1px solid #e1e4e5;margin:24px 0;padding:0}code,.rst-content tt,.rst-content code{white-space:nowrap;max-width:100%;background:#fff;border:solid 1px #e1e4e5;font-size:75%;padding:0 5px;font-family:SFMono-Regular,Menlo,Monaco,Consolas,"Liberation Mono","Courier New",Courier,monospace;color:#E74C3C;overflow-x:auto}code.code-large,.rst-content tt.code-large{font-size:90%}.wy-plain-list-disc,.rst-content .section ul,.rst-content .toctree-wrapper ul,article ul{list-style:disc;line-height:24px;margin-bottom:24px}.wy-plain-list-disc li,.rst-content .section ul li,.rst-content .toctree-wrapper ul li,article ul li{list-style:disc;margin-left:24px}.wy-plain-list-disc li p:last-child,.rst-content .section ul li p:last-child,.rst-content .toctree-wrapper ul li p:last-child,article ul li p:last-child{margin-bottom:0}.wy-plain-list-disc li ul,.rst-content .section ul li ul,.rst-content .toctree-wrapper ul li ul,article ul li ul{margin-bottom:0}.wy-plain-list-disc li li,.rst-content .section ul li li,.rst-content .toctree-wrapper ul li li,article ul li li{list-style:circle}.wy-plain-list-disc li li li,.rst-content .section ul li li li,.rst-content .toctree-wrapper ul li li li,article ul li li li{list-style:square}.wy-plain-list-disc li ol li,.rst-content .section ul li ol li,.rst-content .toctree-wrapper ul li ol li,article ul li ol li{list-style:decimal}.wy-plain-list-decimal,.rst-content .section ol,.rst-content ol.arabic,article ol{list-style:decimal;line-height:24px;margin-bottom:24px}.wy-plain-list-decimal li,.rst-content .section ol li,.rst-content ol.arabic li,article ol li{list-style:decimal;margin-left:24px}.wy-plain-list-decimal li p:last-child,.rst-content .section ol li p:last-child,.rst-content ol.arabic li p:last-child,article ol li p:last-child{margin-bottom:0}.wy-plain-list-decimal li ul,.rst-content .section ol li ul,.rst-content ol.arabic li ul,article ol li ul{margin-bottom:0}.wy-plain-list-decimal li ul li,.rst-content .section ol li ul li,.rst-content ol.arabic li ul li,article ol li ul li{list-style:disc}.wy-breadcrumbs{*zoom:1}.wy-breadcrumbs:before,.wy-breadcrumbs:after{display:table;content:""}.wy-breadcrumbs:after{clear:both}.wy-breadcrumbs li{display:inline-block}.wy-breadcrumbs li.wy-breadcrumbs-aside{float:right}.wy-breadcrumbs li a{display:inline-block;padding:5px}.wy-breadcrumbs li a:first-child{padding-left:0}.wy-breadcrumbs li code,.wy-breadcrumbs li .rst-content tt,.rst-content .wy-breadcrumbs li tt{padding:5px;border:none;background:none}.wy-breadcrumbs li code.literal,.wy-breadcrumbs li .rst-content tt.literal,.rst-content .wy-breadcrumbs li tt.literal{color:#404040}.wy-breadcrumbs-extra{margin-bottom:0;color:#b3b3b3;font-size:80%;display:inline-block}@media screen and (max-width: 480px){.wy-breadcrumbs-extra{display:none}.wy-breadcrumbs li.wy-breadcrumbs-aside{display:none}}@media print{.wy-breadcrumbs li.wy-breadcrumbs-aside{display:none}}html{font-size:16px}.wy-affix{position:fixed;top:1.618em}.wy-menu a:hover{text-decoration:none}.wy-menu-horiz{*zoom:1}.wy-menu-horiz:before,.wy-menu-horiz:after{display:table;content:""}.wy-menu-horiz:after{clear:both}.wy-menu-horiz ul,.wy-menu-horiz li{display:inline-block}.wy-menu-horiz li:hover{background:rgba(255,255,255,0.1)}.wy-menu-horiz li.divide-left{border-left:solid 1px #404040}.wy-menu-horiz li.divide-right{border-right:solid 1px #404040}.wy-menu-horiz a{height:32px;display:inline-block;line-height:32px;padding:0 16px}.wy-menu-vertical{width:300px}.wy-menu-vertical header,.wy-menu-vertical p.caption{color:#3a7ca8;height:32px;display:inline-block;line-height:32px;padding:0 1.618em;margin:12px 0 0 0;display:block;font-weight:bold;text-transform:uppercase;font-size:85%;white-space:nowrap}.wy-menu-vertical ul{margin-bottom:0}.wy-menu-vertical li.divide-top{border-top:solid 1px #404040}.wy-menu-vertical li.divide-bottom{border-bottom:solid 1px #404040}.wy-menu-vertical li.current{background:#e3e3e3}.wy-menu-vertical li.current a{color:gray;border-right:solid 1px #c9c9c9;padding:.4045em 2.427em}.wy-menu-vertical li.current a:hover{background:#d6d6d6}.wy-menu-vertical li code,.wy-menu-vertical li .rst-content tt,.rst-content .wy-menu-vertical li tt{border:none;background:inherit;color:inherit;padding-left:0;padding-right:0}.wy-menu-vertical li span.toctree-expand{display:block;float:left;margin-left:-1.2em;font-size:.8em;line-height:1.6em;color:#4d4d4d}.wy-menu-vertical li.on a,.wy-menu-vertical li.current>a{color:#404040;padding:.4045em 1.618em;font-weight:bold;position:relative;background:#fcfcfc;border:none;padding-left:1.618em -4px}.wy-menu-vertical li.on a:hover,.wy-menu-vertical li.current>a:hover{background:#fcfcfc}.wy-menu-vertical li.on a:hover span.toctree-expand,.wy-menu-vertical li.current>a:hover span.toctree-expand{color:gray}.wy-menu-vertical li.on a span.toctree-expand,.wy-menu-vertical li.current>a span.toctree-expand{display:block;font-size:.8em;line-height:1.6em;color:#333}.wy-menu-vertical li.toctree-l1.current>a{border-bottom:solid 1px #c9c9c9;border-top:solid 1px #c9c9c9}.wy-menu-vertical li.toctree-l2 a,.wy-menu-vertical li.toctree-l3 a,.wy-menu-vertical li.toctree-l4 a{color:#404040}.wy-menu-vertical li.toctree-l1.current li.toctree-l2>ul,.wy-menu-vertical li.toctree-l2.current li.toctree-l3>ul{display:none}.wy-menu-vertical li.toctree-l1.current li.toctree-l2.current>ul,.wy-menu-vertical li.toctree-l2.current li.toctree-l3.current>ul{display:block}.wy-menu-vertical li.toctree-l2.current>a{background:#c9c9c9;padding:.4045em 2.427em}.wy-menu-vertical li.toctree-l2.current li.toctree-l3>a{display:block;background:#c9c9c9;padding:.4045em 4.045em}.wy-menu-vertical li.toctree-l2 a:hover span.toctree-expand{color:gray}.wy-menu-vertical li.toctree-l2 span.toctree-expand{color:#a3a3a3}.wy-menu-vertical li.toctree-l3{font-size:.9em}.wy-menu-vertical li.toctree-l3.current>a{background:#bdbdbd;padding:.4045em 4.045em}.wy-menu-vertical li.toctree-l3.current li.toctree-l4>a{display:block;background:#bdbdbd;padding:.4045em 5.663em}.wy-menu-vertical li.toctree-l3 a:hover span.toctree-expand{color:gray}.wy-menu-vertical li.toctree-l3 span.toctree-expand{color:#969696}.wy-menu-vertical li.toctree-l4{font-size:.9em}.wy-menu-vertical li.current ul{display:block}.wy-menu-vertical li ul{margin-bottom:0;display:none}.wy-menu-vertical li ul li a{margin-bottom:0;color:#d9d9d9;font-weight:normal}.wy-menu-vertical a{display:inline-block;line-height:18px;padding:.4045em 1.618em;display:block;position:relative;font-size:90%;color:#d9d9d9}.wy-menu-vertical a:hover{background-color:#4e4a4a;cursor:pointer}.wy-menu-vertical a:hover span.toctree-expand{color:#d9d9d9}.wy-menu-vertical a:active{background-color:#2980B9;cursor:pointer;color:#fff}.wy-menu-vertical a:active span.toctree-expand{color:#fff}.wy-side-nav-search{display:block;width:300px;padding:.809em;margin-bottom:.809em;z-index:200;background-color:#2980B9;text-align:center;padding:.809em;display:block;color:#fcfcfc;margin-bottom:.809em}.wy-side-nav-search input[type=text]{width:100%;border-radius:50px;padding:6px 12px;border-color:#2472a4}.wy-side-nav-search img{display:block;margin:auto auto .809em auto;height:45px;width:45px;background-color:#2980B9;padding:5px;border-radius:100%}.wy-side-nav-search>a,.wy-side-nav-search .wy-dropdown>a{color:#fcfcfc;font-size:100%;font-weight:bold;display:inline-block;padding:4px 6px;margin-bottom:.809em}.wy-side-nav-search>a:hover,.wy-side-nav-search .wy-dropdown>a:hover{background:rgba(255,255,255,0.1)}.wy-side-nav-search>a img.logo,.wy-side-nav-search .wy-dropdown>a img.logo{display:block;margin:0 auto;height:auto;width:auto;border-radius:0;max-width:100%;background:transparent}.wy-side-nav-search>a.icon img.logo,.wy-side-nav-search .wy-dropdown>a.icon img.logo{margin-top:.85em}.wy-side-nav-search>div.version{margin-top:-.4045em;margin-bottom:.809em;font-weight:normal;color:rgba(255,255,255,0.3)}.wy-nav .wy-menu-vertical header{color:#2980B9}.wy-nav .wy-menu-vertical a{color:#b3b3b3}.wy-nav .wy-menu-vertical a:hover{background-color:#2980B9;color:#fff}[data-menu-wrap]{-webkit-transition:all .2s ease-in;-moz-transition:all .2s ease-in;transition:all .2s ease-in;position:absolute;opacity:1;width:100%;opacity:0}[data-menu-wrap].move-center{left:0;right:auto;opacity:1}[data-menu-wrap].move-left{right:auto;left:-100%;opacity:0}[data-menu-wrap].move-right{right:-100%;left:auto;opacity:0}.wy-body-for-nav{background:#fcfcfc}.wy-grid-for-nav{position:absolute;width:100%;height:100%}.wy-nav-side{position:fixed;top:0;bottom:0;left:0;padding-bottom:2em;width:300px;overflow-x:hidden;overflow-y:hidden;min-height:100%;color:#9b9b9b;background:#343131;z-index:200}.wy-side-scroll{width:320px;position:relative;overflow-x:hidden;overflow-y:scroll;height:100%}.wy-nav-top{display:none;background:#2980B9;color:#fff;padding:.4045em .809em;position:relative;line-height:50px;text-align:center;font-size:100%;*zoom:1}.wy-nav-top:before,.wy-nav-top:after{display:table;content:""}.wy-nav-top:after{clear:both}.wy-nav-top a{color:#fff;font-weight:bold}.wy-nav-top img{margin-right:12px;height:45px;width:45px;background-color:#2980B9;padding:5px;border-radius:100%}.wy-nav-top i{font-size:30px;float:left;cursor:pointer;padding-top:inherit}.wy-nav-content-wrap{margin-left:300px;background:#fcfcfc;min-height:100%}.wy-nav-content{padding:1.618em 3.236em;height:100%;max-width:800px;margin:auto}.wy-body-mask{position:fixed;width:100%;height:100%;background:rgba(0,0,0,0.2);display:none;z-index:499}.wy-body-mask.on{display:block}footer{color:gray}footer p{margin-bottom:12px}footer span.commit code,footer span.commit .rst-content tt,.rst-content footer span.commit tt{padding:0px;font-family:SFMono-Regular,Menlo,Monaco,Consolas,"Liberation Mono","Courier New",Courier,monospace;font-size:1em;background:none;border:none;color:gray}.rst-footer-buttons{*zoom:1}.rst-footer-buttons:before,.rst-footer-buttons:after{width:100%}.rst-footer-buttons:before,.rst-footer-buttons:after{display:table;content:""}.rst-footer-buttons:after{clear:both}.rst-breadcrumbs-buttons{margin-top:12px;*zoom:1}.rst-breadcrumbs-buttons:before,.rst-breadcrumbs-buttons:after{display:table;content:""}.rst-breadcrumbs-buttons:after{clear:both}#search-results .search li{margin-bottom:24px;border-bottom:solid 1px #e1e4e5;padding-bottom:24px}#search-results .search li:first-child{border-top:solid 1px #e1e4e5;padding-top:24px}#search-results .search li a{font-size:120%;margin-bottom:12px;display:inline-block}#search-results .context{color:gray;font-size:90%}.genindextable li>ul{margin-left:24px}@media screen and (max-width: 768px){.wy-body-for-nav{background:#fcfcfc}.wy-nav-top{display:block}.wy-nav-side{left:-300px}.wy-nav-side.shift{width:85%;left:0}.wy-side-scroll{width:auto}.wy-side-nav-search{width:auto}.wy-menu.wy-menu-vertical{width:auto}.wy-nav-content-wrap{margin-left:0}.wy-nav-content-wrap .wy-nav-content{padding:1.618em}.wy-nav-content-wrap.shift{position:fixed;min-width:100%;left:85%;top:0;height:100%;overflow:hidden}}@media screen and (min-width: 1100px){.wy-nav-content-wrap{background:rgba(0,0,0,0.05)}.wy-nav-content{margin:0;background:#fcfcfc}}@media print{.rst-versions,footer,.wy-nav-side{display:none}.wy-nav-content-wrap{margin-left:0}}.rst-versions{position:fixed;bottom:0;left:0;width:300px;color:#fcfcfc;background:#1f1d1d;font-family:"Lato","proxima-nova","Helvetica Neue",Arial,sans-serif;z-index:400}.rst-versions a{color:#2980B9;text-decoration:none}.rst-versions .rst-badge-small{display:none}.rst-versions .rst-current-version{padding:12px;background-color:#272525;display:block;text-align:right;font-size:90%;cursor:pointer;color:#27AE60;*zoom:1}.rst-versions .rst-current-version:before,.rst-versions .rst-current-version:after{display:table;content:""}.rst-versions .rst-current-version:after{clear:both}.rst-versions .rst-current-version .fa,.rst-versions .rst-current-version .wy-menu-vertical li span.toctree-expand,.wy-menu-vertical li .rst-versions .rst-current-version span.toctree-expand,.rst-versions .rst-current-version .rst-content .admonition-title,.rst-content .rst-versions .rst-current-version .admonition-title,.rst-versions .rst-current-version .rst-content h1 .headerlink,.rst-content h1 .rst-versions .rst-current-version .headerlink,.rst-versions .rst-current-version .rst-content h2 .headerlink,.rst-content h2 .rst-versions .rst-current-version .headerlink,.rst-versions .rst-current-version .rst-content h3 .headerlink,.rst-content h3 .rst-versions .rst-current-version .headerlink,.rst-versions .rst-current-version .rst-content h4 .headerlink,.rst-content h4 .rst-versions .rst-current-version .headerlink,.rst-versions .rst-current-version .rst-content h5 .headerlink,.rst-content h5 .rst-versions .rst-current-version .headerlink,.rst-versions .rst-current-version .rst-content h6 .headerlink,.rst-content h6 .rst-versions .rst-current-version .headerlink,.rst-versions .rst-current-version .rst-content dl dt .headerlink,.rst-content dl dt .rst-versions .rst-current-version .headerlink,.rst-versions .rst-current-version .rst-content p.caption .headerlink,.rst-content p.caption .rst-versions .rst-current-version .headerlink,.rst-versions .rst-current-version .rst-content table>caption .headerlink,.rst-content table>caption .rst-versions .rst-current-version .headerlink,.rst-versions .rst-current-version .rst-content .code-block-caption .headerlink,.rst-content .code-block-caption .rst-versions .rst-current-version .headerlink,.rst-versions .rst-current-version .rst-content tt.download span:first-child,.rst-content tt.download .rst-versions .rst-current-version span:first-child,.rst-versions .rst-current-version .rst-content code.download span:first-child,.rst-content code.download .rst-versions .rst-current-version span:first-child,.rst-versions .rst-current-version .icon{color:#fcfcfc}.rst-versions .rst-current-version .fa-book,.rst-versions .rst-current-version .icon-book{float:left}.rst-versions .rst-current-version .icon-book{float:left}.rst-versions .rst-current-version.rst-out-of-date{background-color:#E74C3C;color:#fff}.rst-versions .rst-current-version.rst-active-old-version{background-color:#F1C40F;color:#000}.rst-versions.shift-up{height:auto;max-height:100%;overflow-y:scroll}.rst-versions.shift-up .rst-other-versions{display:block}.rst-versions .rst-other-versions{font-size:90%;padding:12px;color:gray;display:none}.rst-versions .rst-other-versions hr{display:block;height:1px;border:0;margin:20px 0;padding:0;border-top:solid 1px #413d3d}.rst-versions .rst-other-versions dd{display:inline-block;margin:0}.rst-versions .rst-other-versions dd a{display:inline-block;padding:6px;color:#fcfcfc}.rst-versions.rst-badge{width:auto;bottom:20px;right:20px;left:auto;border:none;max-width:300px;max-height:90%}.rst-versions.rst-badge .icon-book{float:none}.rst-versions.rst-badge .fa-book,.rst-versions.rst-badge .icon-book{float:none}.rst-versions.rst-badge.shift-up .rst-current-version{text-align:right}.rst-versions.rst-badge.shift-up .rst-current-version .fa-book,.rst-versions.rst-badge.shift-up .rst-current-version .icon-book{float:left}.rst-versions.rst-badge.shift-up .rst-current-version .icon-book{float:left}.rst-versions.rst-badge .rst-current-version{width:auto;height:30px;line-height:30px;padding:0 6px;display:block;text-align:center}@media screen and (max-width: 768px){.rst-versions{width:85%;display:none}.rst-versions.shift{display:block}}.rst-content img{max-width:100%;height:auto}.rst-content div.figure{margin-bottom:24px}.rst-content div.figure p.caption{font-style:italic}.rst-content div.figure p:last-child.caption{margin-bottom:0px}.rst-content div.figure.align-center{text-align:center}.rst-content .section>img,.rst-content .section>a>img{margin-bottom:24px}.rst-content abbr[title]{text-decoration:none}.rst-content.style-external-links a.reference.external:after{font-family:FontAwesome;content:"ï‚Ž";color:#b3b3b3;vertical-align:super;font-size:60%;margin:0 .2em}.rst-content blockquote{margin-left:24px;line-height:24px;margin-bottom:24px}.rst-content pre.literal-block{white-space:pre;margin:0;padding:12px 12px;font-family:SFMono-Regular,Menlo,Monaco,Consolas,"Liberation Mono","Courier New",Courier,monospace;display:block;overflow:auto}.rst-content pre.literal-block,.rst-content div[class^='highlight']{border:1px solid #e1e4e5;overflow-x:auto;margin:1px 0 24px 0}.rst-content pre.literal-block div[class^='highlight'],.rst-content div[class^='highlight'] div[class^='highlight']{padding:0px;border:none;margin:0}.rst-content div[class^='highlight'] td.code{width:100%}.rst-content .linenodiv pre{border-right:solid 1px #e6e9ea;margin:0;padding:12px 12px;font-family:SFMono-Regular,Menlo,Monaco,Consolas,"Liberation Mono","Courier New",Courier,monospace;user-select:none;pointer-events:none}.rst-content div[class^='highlight'] pre{white-space:pre;margin:0;padding:12px 12px;display:block;overflow:auto}.rst-content div[class^='highlight'] pre .hll{display:block;margin:0 -12px;padding:0 12px}.rst-content pre.literal-block,.rst-content div[class^='highlight'] pre,.rst-content .linenodiv pre{font-family:SFMono-Regular,Menlo,Monaco,Consolas,"Liberation Mono","Courier New",Courier,monospace;font-size:12px;line-height:1.4}.rst-content .code-block-caption{font-style:italic;font-size:85%;line-height:1;padding:1em 0;text-align:center}@media print{.rst-content .codeblock,.rst-content div[class^='highlight'],.rst-content div[class^='highlight'] pre{white-space:pre-wrap}}.rst-content .note .last,.rst-content .attention .last,.rst-content .caution .last,.rst-content .danger .last,.rst-content .error .last,.rst-content .hint .last,.rst-content .important .last,.rst-content .tip .last,.rst-content .warning .last,.rst-content .seealso .last,.rst-content .admonition-todo .last,.rst-content .admonition .last{margin-bottom:0}.rst-content .admonition-title:before{margin-right:4px}.rst-content .admonition table{border-color:rgba(0,0,0,0.1)}.rst-content .admonition table td,.rst-content .admonition table th{background:transparent !important;border-color:rgba(0,0,0,0.1) !important}.rst-content .section ol.loweralpha,.rst-content .section ol.loweralpha li{list-style:lower-alpha}.rst-content .section ol.upperalpha,.rst-content .section ol.upperalpha li{list-style:upper-alpha}.rst-content .section ol p,.rst-content .section ul p{margin-bottom:12px}.rst-content .section ol p:last-child,.rst-content .section ul p:last-child{margin-bottom:24px}.rst-content .line-block{margin-left:0px;margin-bottom:24px;line-height:24px}.rst-content .line-block .line-block{margin-left:24px;margin-bottom:0px}.rst-content .topic-title{font-weight:bold;margin-bottom:12px}.rst-content .toc-backref{color:#404040}.rst-content .align-right{float:right;margin:0px 0px 24px 24px}.rst-content .align-left{float:left;margin:0px 24px 24px 0px}.rst-content .align-center{margin:auto}.rst-content .align-center:not(table){display:block}.rst-content h1 .headerlink,.rst-content h2 .headerlink,.rst-content .toctree-wrapper p.caption .headerlink,.rst-content h3 .headerlink,.rst-content h4 .headerlink,.rst-content h5 .headerlink,.rst-content h6 .headerlink,.rst-content dl dt .headerlink,.rst-content p.caption .headerlink,.rst-content table>caption .headerlink,.rst-content .code-block-caption .headerlink{visibility:hidden;font-size:14px}.rst-content h1 .headerlink:after,.rst-content h2 .headerlink:after,.rst-content .toctree-wrapper p.caption .headerlink:after,.rst-content h3 .headerlink:after,.rst-content h4 .headerlink:after,.rst-content h5 .headerlink:after,.rst-content h6 .headerlink:after,.rst-content dl dt .headerlink:after,.rst-content p.caption .headerlink:after,.rst-content table>caption .headerlink:after,.rst-content .code-block-caption .headerlink:after{content:"ïƒ";font-family:FontAwesome}.rst-content h1:hover .headerlink:after,.rst-content h2:hover .headerlink:after,.rst-content .toctree-wrapper p.caption:hover .headerlink:after,.rst-content h3:hover .headerlink:after,.rst-content h4:hover .headerlink:after,.rst-content h5:hover .headerlink:after,.rst-content h6:hover .headerlink:after,.rst-content dl dt:hover .headerlink:after,.rst-content p.caption:hover .headerlink:after,.rst-content table>caption:hover .headerlink:after,.rst-content .code-block-caption:hover .headerlink:after{visibility:visible}.rst-content table>caption .headerlink:after{font-size:12px}.rst-content .centered{text-align:center}.rst-content .sidebar{float:right;width:40%;display:block;margin:0 0 24px 24px;padding:24px;background:#f3f6f6;border:solid 1px #e1e4e5}.rst-content .sidebar p,.rst-content .sidebar ul,.rst-content .sidebar dl{font-size:90%}.rst-content .sidebar .last{margin-bottom:0}.rst-content .sidebar .sidebar-title{display:block;font-family:"Roboto Slab","ff-tisa-web-pro","Georgia",Arial,sans-serif;font-weight:bold;background:#e1e4e5;padding:6px 12px;margin:-24px;margin-bottom:24px;font-size:100%}.rst-content .highlighted{background:#F1C40F;display:inline-block;font-weight:bold;padding:0 6px}.rst-content .footnote-reference,.rst-content .citation-reference{vertical-align:baseline;position:relative;top:-0.4em;line-height:0;font-size:90%}.rst-content table.docutils.citation,.rst-content table.docutils.footnote{background:none;border:none;color:gray}.rst-content table.docutils.citation td,.rst-content table.docutils.citation tr,.rst-content table.docutils.footnote td,.rst-content table.docutils.footnote tr{border:none;background-color:transparent !important;white-space:normal}.rst-content table.docutils.citation td.label,.rst-content table.docutils.footnote td.label{padding-left:0;padding-right:0;vertical-align:top}.rst-content table.docutils.citation tt,.rst-content table.docutils.citation code,.rst-content table.docutils.footnote tt,.rst-content table.docutils.footnote code{color:#555}.rst-content .wy-table-responsive.citation,.rst-content .wy-table-responsive.footnote{margin-bottom:0}.rst-content .wy-table-responsive.citation+:not(.citation),.rst-content .wy-table-responsive.footnote+:not(.footnote){margin-top:24px}.rst-content .wy-table-responsive.citation:last-child,.rst-content .wy-table-responsive.footnote:last-child{margin-bottom:24px}.rst-content table.docutils th{border-color:#e1e4e5}.rst-content table.docutils td .last,.rst-content table.docutils td .last :last-child{margin-bottom:0}.rst-content table.field-list{border:none}.rst-content table.field-list td{border:none}.rst-content table.field-list td p{font-size:inherit;line-height:inherit}.rst-content table.field-list td>strong{display:inline-block}.rst-content table.field-list .field-name{padding-right:10px;text-align:left;white-space:nowrap}.rst-content table.field-list .field-body{text-align:left}.rst-content tt,.rst-content tt,.rst-content code{color:#000;font-family:SFMono-Regular,Menlo,Monaco,Consolas,"Liberation Mono","Courier New",Courier,monospace;padding:2px 5px}.rst-content tt big,.rst-content tt em,.rst-content tt big,.rst-content code big,.rst-content tt em,.rst-content code em{font-size:100% !important;line-height:normal}.rst-content tt.literal,.rst-content tt.literal,.rst-content code.literal{color:#E74C3C}.rst-content tt.xref,a .rst-content tt,.rst-content tt.xref,.rst-content code.xref,a .rst-content tt,a .rst-content code{font-weight:bold;color:#404040}.rst-content pre,.rst-content kbd,.rst-content samp{font-family:SFMono-Regular,Menlo,Monaco,Consolas,"Liberation Mono","Courier New",Courier,monospace}.rst-content a tt,.rst-content a tt,.rst-content a code{color:#2980B9}.rst-content dl{margin-bottom:24px}.rst-content dl dt{font-weight:bold;margin-bottom:12px}.rst-content dl p,.rst-content dl table,.rst-content dl ul,.rst-content dl ol{margin-bottom:12px !important}.rst-content dl dd{margin:0 0 12px 24px;line-height:24px}.rst-content dl:not(.docutils){margin-bottom:24px}.rst-content dl:not(.docutils) dt{display:table;margin:6px 0;font-size:90%;line-height:normal;background:#e7f2fa;color:#2980B9;border-top:solid 3px #6ab0de;padding:6px;position:relative}.rst-content dl:not(.docutils) dt:before{color:#6ab0de}.rst-content dl:not(.docutils) dt .headerlink{color:#404040;font-size:100% !important}.rst-content dl:not(.docutils) dl dt{margin-bottom:6px;border:none;border-left:solid 3px #ccc;background:#f0f0f0;color:#555}.rst-content dl:not(.docutils) dl dt .headerlink{color:#404040;font-size:100% !important}.rst-content dl:not(.docutils) dt:first-child{margin-top:0}.rst-content dl:not(.docutils) tt,.rst-content dl:not(.docutils) tt,.rst-content dl:not(.docutils) code{font-weight:bold}.rst-content dl:not(.docutils) tt.descname,.rst-content dl:not(.docutils) tt.descclassname,.rst-content dl:not(.docutils) tt.descname,.rst-content dl:not(.docutils) code.descname,.rst-content dl:not(.docutils) tt.descclassname,.rst-content dl:not(.docutils) code.descclassname{background-color:transparent;border:none;padding:0;font-size:100% !important}.rst-content dl:not(.docutils) tt.descname,.rst-content dl:not(.docutils) tt.descname,.rst-content dl:not(.docutils) code.descname{font-weight:bold}.rst-content dl:not(.docutils) .optional{display:inline-block;padding:0 4px;color:#000;font-weight:bold}.rst-content dl:not(.docutils) .property{display:inline-block;padding-right:8px}.rst-content .viewcode-link,.rst-content .viewcode-back{display:inline-block;color:#27AE60;font-size:80%;padding-left:24px}.rst-content .viewcode-back{display:block;float:right}.rst-content p.rubric{margin-bottom:12px;font-weight:bold}.rst-content tt.download,.rst-content code.download{background:inherit;padding:inherit;font-weight:normal;font-family:inherit;font-size:inherit;color:inherit;border:inherit;white-space:inherit}.rst-content tt.download span:first-child,.rst-content code.download span:first-child{-webkit-font-smoothing:subpixel-antialiased}.rst-content tt.download span:first-child:before,.rst-content code.download span:first-child:before{margin-right:4px}.rst-content .guilabel{border:1px solid #7fbbe3;background:#e7f2fa;font-size:80%;font-weight:700;border-radius:4px;padding:2.4px 6px;margin:auto 2px}.rst-content .versionmodified{font-style:italic}@media screen and (max-width: 480px){.rst-content .sidebar{width:100%}}span[id*='MathJax-Span']{color:#404040}.math{text-align:center}@font-face{font-family:"Lato";src:url("../fonts/Lato/lato-regular.eot");src:url("../fonts/Lato/lato-regular.eot?#iefix") format("embedded-opentype"),url("../fonts/Lato/lato-regular.woff2") format("woff2"),url("../fonts/Lato/lato-regular.woff") format("woff"),url("../fonts/Lato/lato-regular.ttf") format("truetype");font-weight:400;font-style:normal}@font-face{font-family:"Lato";src:url("../fonts/Lato/lato-bold.eot");src:url("../fonts/Lato/lato-bold.eot?#iefix") format("embedded-opentype"),url("../fonts/Lato/lato-bold.woff2") format("woff2"),url("../fonts/Lato/lato-bold.woff") format("woff"),url("../fonts/Lato/lato-bold.ttf") format("truetype");font-weight:700;font-style:normal}@font-face{font-family:"Lato";src:url("../fonts/Lato/lato-bolditalic.eot");src:url("../fonts/Lato/lato-bolditalic.eot?#iefix") format("embedded-opentype"),url("../fonts/Lato/lato-bolditalic.woff2") format("woff2"),url("../fonts/Lato/lato-bolditalic.woff") format("woff"),url("../fonts/Lato/lato-bolditalic.ttf") format("truetype");font-weight:700;font-style:italic}@font-face{font-family:"Lato";src:url("../fonts/Lato/lato-italic.eot");src:url("../fonts/Lato/lato-italic.eot?#iefix") format("embedded-opentype"),url("../fonts/Lato/lato-italic.woff2") format("woff2"),url("../fonts/Lato/lato-italic.woff") format("woff"),url("../fonts/Lato/lato-italic.ttf") format("truetype");font-weight:400;font-style:italic}@font-face{font-family:"Roboto Slab";font-style:normal;font-weight:400;src:url("../fonts/RobotoSlab/roboto-slab.eot");src:url("../fonts/RobotoSlab/roboto-slab-v7-regular.eot?#iefix") format("embedded-opentype"),url("../fonts/RobotoSlab/roboto-slab-v7-regular.woff2") format("woff2"),url("../fonts/RobotoSlab/roboto-slab-v7-regular.woff") format("woff"),url("../fonts/RobotoSlab/roboto-slab-v7-regular.ttf") format("truetype")}@font-face{font-family:"Roboto Slab";font-style:normal;font-weight:700;src:url("../fonts/RobotoSlab/roboto-slab-v7-bold.eot");src:url("../fonts/RobotoSlab/roboto-slab-v7-bold.eot?#iefix") format("embedded-opentype"),url("../fonts/RobotoSlab/roboto-slab-v7-bold.woff2") format("woff2"),url("../fonts/RobotoSlab/roboto-slab-v7-bold.woff") format("woff"),url("../fonts/RobotoSlab/roboto-slab-v7-bold.ttf") format("truetype")} diff --git a/build/lib/WORC/doc/_build/html/_static/doctools.js b/build/lib/WORC/doc/_build/html/_static/doctools.js deleted file mode 100644 index b33f87fc..00000000 --- a/build/lib/WORC/doc/_build/html/_static/doctools.js +++ /dev/null @@ -1,314 +0,0 @@ -/* - * doctools.js - * ~~~~~~~~~~~ - * - * Sphinx JavaScript utilities for all documentation. - * - * :copyright: Copyright 2007-2019 by the Sphinx team, see AUTHORS. - * :license: BSD, see LICENSE for details. - * - */ - -/** - * select a different prefix for underscore - */ -$u = _.noConflict(); - -/** - * make the code below compatible with browsers without - * an installed firebug like debugger -if (!window.console || !console.firebug) { - var names = ["log", "debug", "info", "warn", "error", "assert", "dir", - "dirxml", "group", "groupEnd", "time", "timeEnd", "count", "trace", - "profile", "profileEnd"]; - window.console = {}; - for (var i = 0; i < names.length; ++i) - window.console[names[i]] = function() {}; -} - */ - -/** - * small helper function to urldecode strings - */ -jQuery.urldecode = function(x) { - return decodeURIComponent(x).replace(/\+/g, ' '); -}; - -/** - * small helper function to urlencode strings - */ -jQuery.urlencode = encodeURIComponent; - -/** - * This function returns the parsed url parameters of the - * current request. Multiple values per key are supported, - * it will always return arrays of strings for the value parts. - */ -jQuery.getQueryParameters = function(s) { - if (typeof s === 'undefined') - s = document.location.search; - var parts = s.substr(s.indexOf('?') + 1).split('&'); - var result = {}; - for (var i = 0; i < parts.length; i++) { - var tmp = parts[i].split('=', 2); - var key = jQuery.urldecode(tmp[0]); - var value = jQuery.urldecode(tmp[1]); - if (key in result) - result[key].push(value); - else - result[key] = [value]; - } - return result; -}; - -/** - * highlight a given string on a jquery object by wrapping it in - * span elements with the given class name. - */ -jQuery.fn.highlightText = function(text, className) { - function highlight(node, addItems) { - if (node.nodeType === 3) { - var val = node.nodeValue; - var pos = val.toLowerCase().indexOf(text); - if (pos >= 0 && - !jQuery(node.parentNode).hasClass(className) && - !jQuery(node.parentNode).hasClass("nohighlight")) { - var span; - var isInSVG = jQuery(node).closest("body, svg, foreignObject").is("svg"); - if (isInSVG) { - span = document.createElementNS("http://www.w3.org/2000/svg", "tspan"); - } else { - span = document.createElement("span"); - span.className = className; - } - span.appendChild(document.createTextNode(val.substr(pos, text.length))); - node.parentNode.insertBefore(span, node.parentNode.insertBefore( - document.createTextNode(val.substr(pos + text.length)), - node.nextSibling)); - node.nodeValue = val.substr(0, pos); - if (isInSVG) { - var rect = document.createElementNS("http://www.w3.org/2000/svg", "rect"); - var bbox = node.parentElement.getBBox(); - rect.x.baseVal.value = bbox.x; - rect.y.baseVal.value = bbox.y; - rect.width.baseVal.value = bbox.width; - rect.height.baseVal.value = bbox.height; - rect.setAttribute('class', className); - addItems.push({ - "parent": node.parentNode, - "target": rect}); - } - } - } - else if (!jQuery(node).is("button, select, textarea")) { - jQuery.each(node.childNodes, function() { - highlight(this, addItems); - }); - } - } - var addItems = []; - var result = this.each(function() { - highlight(this, addItems); - }); - for (var i = 0; i < addItems.length; ++i) { - jQuery(addItems[i].parent).before(addItems[i].target); - } - return result; -}; - -/* - * backward compatibility for jQuery.browser - * This will be supported until firefox bug is fixed. - */ -if (!jQuery.browser) { - jQuery.uaMatch = function(ua) { - ua = ua.toLowerCase(); - - var match = /(chrome)[ \/]([\w.]+)/.exec(ua) || - /(webkit)[ \/]([\w.]+)/.exec(ua) || - /(opera)(?:.*version|)[ \/]([\w.]+)/.exec(ua) || - /(msie) ([\w.]+)/.exec(ua) || - ua.indexOf("compatible") < 0 && /(mozilla)(?:.*? rv:([\w.]+)|)/.exec(ua) || - []; - - return { - browser: match[ 1 ] || "", - version: match[ 2 ] || "0" - }; - }; - jQuery.browser = {}; - jQuery.browser[jQuery.uaMatch(navigator.userAgent).browser] = true; -} - -/** - * Small JavaScript module for the documentation. - */ -var Documentation = { - - init : function() { - this.fixFirefoxAnchorBug(); - this.highlightSearchWords(); - this.initIndexTable(); - if (DOCUMENTATION_OPTIONS.NAVIGATION_WITH_KEYS) { - this.initOnKeyListeners(); - } - }, - - /** - * i18n support - */ - TRANSLATIONS : {}, - PLURAL_EXPR : function(n) { return n === 1 ? 0 : 1; }, - LOCALE : 'unknown', - - // gettext and ngettext don't access this so that the functions - // can safely bound to a different name (_ = Documentation.gettext) - gettext : function(string) { - var translated = Documentation.TRANSLATIONS[string]; - if (typeof translated === 'undefined') - return string; - return (typeof translated === 'string') ? translated : translated[0]; - }, - - ngettext : function(singular, plural, n) { - var translated = Documentation.TRANSLATIONS[singular]; - if (typeof translated === 'undefined') - return (n == 1) ? singular : plural; - return translated[Documentation.PLURALEXPR(n)]; - }, - - addTranslations : function(catalog) { - for (var key in catalog.messages) - this.TRANSLATIONS[key] = catalog.messages[key]; - this.PLURAL_EXPR = new Function('n', 'return +(' + catalog.plural_expr + ')'); - this.LOCALE = catalog.locale; - }, - - /** - * add context elements like header anchor links - */ - addContextElements : function() { - $('div[id] > :header:first').each(function() { - $('\u00B6'). - attr('href', '#' + this.id). - attr('title', _('Permalink to this headline')). - appendTo(this); - }); - $('dt[id]').each(function() { - $('\u00B6'). - attr('href', '#' + this.id). - attr('title', _('Permalink to this definition')). - appendTo(this); - }); - }, - - /** - * workaround a firefox stupidity - * see: https://bugzilla.mozilla.org/show_bug.cgi?id=645075 - */ - fixFirefoxAnchorBug : function() { - if (document.location.hash && $.browser.mozilla) - window.setTimeout(function() { - document.location.href += ''; - }, 10); - }, - - /** - * highlight the search words provided in the url in the text - */ - highlightSearchWords : function() { - var params = $.getQueryParameters(); - var terms = (params.highlight) ? params.highlight[0].split(/\s+/) : []; - if (terms.length) { - var body = $('div.body'); - if (!body.length) { - body = $('body'); - } - window.setTimeout(function() { - $.each(terms, function() { - body.highlightText(this.toLowerCase(), 'highlighted'); - }); - }, 10); - $('') - .appendTo($('#searchbox')); - } - }, - - /** - * init the domain index toggle buttons - */ - initIndexTable : function() { - var togglers = $('img.toggler').click(function() { - var src = $(this).attr('src'); - var idnum = $(this).attr('id').substr(7); - $('tr.cg-' + idnum).toggle(); - if (src.substr(-9) === 'minus.png') - $(this).attr('src', src.substr(0, src.length-9) + 'plus.png'); - else - $(this).attr('src', src.substr(0, src.length-8) + 'minus.png'); - }).css('display', ''); - if (DOCUMENTATION_OPTIONS.COLLAPSE_INDEX) { - togglers.click(); - } - }, - - /** - * helper function to hide the search marks again - */ - hideSearchWords : function() { - $('#searchbox .highlight-link').fadeOut(300); - $('span.highlighted').removeClass('highlighted'); - }, - - /** - * make the url absolute - */ - makeURL : function(relativeURL) { - return DOCUMENTATION_OPTIONS.URL_ROOT + '/' + relativeURL; - }, - - /** - * get the current relative url - */ - getCurrentURL : function() { - var path = document.location.pathname; - var parts = path.split(/\//); - $.each(DOCUMENTATION_OPTIONS.URL_ROOT.split(/\//), function() { - if (this === '..') - parts.pop(); - }); - var url = parts.join('/'); - return path.substring(url.lastIndexOf('/') + 1, path.length - 1); - }, - - initOnKeyListeners: function() { - $(document).keyup(function(event) { - var activeElementType = document.activeElement.tagName; - // don't navigate when in search box or textarea - if (activeElementType !== 'TEXTAREA' && activeElementType !== 'INPUT' && activeElementType !== 'SELECT') { - switch (event.keyCode) { - case 37: // left - var prevHref = $('link[rel="prev"]').prop('href'); - if (prevHref) { - window.location.href = prevHref; - return false; - } - case 39: // right - var nextHref = $('link[rel="next"]').prop('href'); - if (nextHref) { - window.location.href = nextHref; - return false; - } - } - } - }); - } -}; - -// quick alias for translations -_ = Documentation.gettext; - -$(document).ready(function() { - Documentation.init(); -}); diff --git a/build/lib/WORC/doc/_build/html/_static/documentation_options.js b/build/lib/WORC/doc/_build/html/_static/documentation_options.js deleted file mode 100644 index ef965269..00000000 --- a/build/lib/WORC/doc/_build/html/_static/documentation_options.js +++ /dev/null @@ -1,10 +0,0 @@ -var DOCUMENTATION_OPTIONS = { - URL_ROOT: document.getElementById("documentation_options").getAttribute('data-url_root'), - VERSION: '3.0.0', - LANGUAGE: 'None', - COLLAPSE_INDEX: false, - FILE_SUFFIX: '.html', - HAS_SOURCE: true, - SOURCELINK_SUFFIX: '.txt', - NAVIGATION_WITH_KEYS: false -}; \ No newline at end of file diff --git a/build/lib/WORC/doc/_build/html/_static/file.png b/build/lib/WORC/doc/_build/html/_static/file.png deleted file mode 100644 index a858a410..00000000 Binary files a/build/lib/WORC/doc/_build/html/_static/file.png and /dev/null differ diff --git a/build/lib/WORC/doc/_build/html/_static/fonts/Inconsolata-Bold.ttf b/build/lib/WORC/doc/_build/html/_static/fonts/Inconsolata-Bold.ttf deleted file mode 100644 index 809c1f58..00000000 Binary files a/build/lib/WORC/doc/_build/html/_static/fonts/Inconsolata-Bold.ttf and /dev/null differ diff --git a/build/lib/WORC/doc/_build/html/_static/fonts/Inconsolata-Regular.ttf b/build/lib/WORC/doc/_build/html/_static/fonts/Inconsolata-Regular.ttf deleted file mode 100644 index fc981ce7..00000000 Binary files a/build/lib/WORC/doc/_build/html/_static/fonts/Inconsolata-Regular.ttf and /dev/null differ diff --git a/build/lib/WORC/doc/_build/html/_static/fonts/Inconsolata.ttf b/build/lib/WORC/doc/_build/html/_static/fonts/Inconsolata.ttf deleted file mode 100644 index 4b8a36d2..00000000 Binary files a/build/lib/WORC/doc/_build/html/_static/fonts/Inconsolata.ttf and /dev/null differ diff --git a/build/lib/WORC/doc/_build/html/_static/fonts/Lato-Bold.ttf b/build/lib/WORC/doc/_build/html/_static/fonts/Lato-Bold.ttf deleted file mode 100644 index 1d23c706..00000000 Binary files a/build/lib/WORC/doc/_build/html/_static/fonts/Lato-Bold.ttf and /dev/null differ diff --git a/build/lib/WORC/doc/_build/html/_static/fonts/Lato-Regular.ttf b/build/lib/WORC/doc/_build/html/_static/fonts/Lato-Regular.ttf deleted file mode 100644 index 0f3d0f83..00000000 Binary files a/build/lib/WORC/doc/_build/html/_static/fonts/Lato-Regular.ttf and /dev/null differ diff --git a/build/lib/WORC/doc/_build/html/_static/fonts/Lato/lato-bold.eot b/build/lib/WORC/doc/_build/html/_static/fonts/Lato/lato-bold.eot deleted file mode 100644 index 3361183a..00000000 Binary files a/build/lib/WORC/doc/_build/html/_static/fonts/Lato/lato-bold.eot and /dev/null differ diff --git a/build/lib/WORC/doc/_build/html/_static/fonts/Lato/lato-bold.ttf b/build/lib/WORC/doc/_build/html/_static/fonts/Lato/lato-bold.ttf deleted file mode 100644 index 29f691d5..00000000 Binary files a/build/lib/WORC/doc/_build/html/_static/fonts/Lato/lato-bold.ttf and /dev/null differ diff --git a/build/lib/WORC/doc/_build/html/_static/fonts/Lato/lato-bold.woff b/build/lib/WORC/doc/_build/html/_static/fonts/Lato/lato-bold.woff deleted file mode 100644 index c6dff51f..00000000 Binary files a/build/lib/WORC/doc/_build/html/_static/fonts/Lato/lato-bold.woff and /dev/null differ diff --git a/build/lib/WORC/doc/_build/html/_static/fonts/Lato/lato-bold.woff2 b/build/lib/WORC/doc/_build/html/_static/fonts/Lato/lato-bold.woff2 deleted file mode 100644 index bb195043..00000000 Binary files a/build/lib/WORC/doc/_build/html/_static/fonts/Lato/lato-bold.woff2 and /dev/null differ diff --git a/build/lib/WORC/doc/_build/html/_static/fonts/Lato/lato-bolditalic.eot b/build/lib/WORC/doc/_build/html/_static/fonts/Lato/lato-bolditalic.eot deleted file mode 100644 index 3d415493..00000000 Binary files a/build/lib/WORC/doc/_build/html/_static/fonts/Lato/lato-bolditalic.eot and /dev/null differ diff --git a/build/lib/WORC/doc/_build/html/_static/fonts/Lato/lato-bolditalic.ttf b/build/lib/WORC/doc/_build/html/_static/fonts/Lato/lato-bolditalic.ttf deleted file mode 100644 index f402040b..00000000 Binary files a/build/lib/WORC/doc/_build/html/_static/fonts/Lato/lato-bolditalic.ttf and /dev/null differ diff --git a/build/lib/WORC/doc/_build/html/_static/fonts/Lato/lato-bolditalic.woff b/build/lib/WORC/doc/_build/html/_static/fonts/Lato/lato-bolditalic.woff deleted file mode 100644 index 88ad05b9..00000000 Binary files a/build/lib/WORC/doc/_build/html/_static/fonts/Lato/lato-bolditalic.woff and /dev/null differ diff --git a/build/lib/WORC/doc/_build/html/_static/fonts/Lato/lato-bolditalic.woff2 b/build/lib/WORC/doc/_build/html/_static/fonts/Lato/lato-bolditalic.woff2 deleted file mode 100644 index c4e3d804..00000000 Binary files a/build/lib/WORC/doc/_build/html/_static/fonts/Lato/lato-bolditalic.woff2 and /dev/null differ diff --git a/build/lib/WORC/doc/_build/html/_static/fonts/Lato/lato-italic.eot b/build/lib/WORC/doc/_build/html/_static/fonts/Lato/lato-italic.eot deleted file mode 100644 index 3f826421..00000000 Binary files a/build/lib/WORC/doc/_build/html/_static/fonts/Lato/lato-italic.eot and /dev/null differ diff --git a/build/lib/WORC/doc/_build/html/_static/fonts/Lato/lato-italic.ttf b/build/lib/WORC/doc/_build/html/_static/fonts/Lato/lato-italic.ttf deleted file mode 100644 index b4bfc9b2..00000000 Binary files a/build/lib/WORC/doc/_build/html/_static/fonts/Lato/lato-italic.ttf and /dev/null differ diff --git a/build/lib/WORC/doc/_build/html/_static/fonts/Lato/lato-italic.woff b/build/lib/WORC/doc/_build/html/_static/fonts/Lato/lato-italic.woff deleted file mode 100644 index 76114bc0..00000000 Binary files a/build/lib/WORC/doc/_build/html/_static/fonts/Lato/lato-italic.woff and /dev/null differ diff --git a/build/lib/WORC/doc/_build/html/_static/fonts/Lato/lato-italic.woff2 b/build/lib/WORC/doc/_build/html/_static/fonts/Lato/lato-italic.woff2 deleted file mode 100644 index 3404f37e..00000000 Binary files a/build/lib/WORC/doc/_build/html/_static/fonts/Lato/lato-italic.woff2 and /dev/null differ diff --git a/build/lib/WORC/doc/_build/html/_static/fonts/Lato/lato-regular.eot b/build/lib/WORC/doc/_build/html/_static/fonts/Lato/lato-regular.eot deleted file mode 100644 index 11e3f2a5..00000000 Binary files a/build/lib/WORC/doc/_build/html/_static/fonts/Lato/lato-regular.eot and /dev/null differ diff --git a/build/lib/WORC/doc/_build/html/_static/fonts/Lato/lato-regular.ttf b/build/lib/WORC/doc/_build/html/_static/fonts/Lato/lato-regular.ttf deleted file mode 100644 index 74decd9e..00000000 Binary files a/build/lib/WORC/doc/_build/html/_static/fonts/Lato/lato-regular.ttf and /dev/null differ diff --git a/build/lib/WORC/doc/_build/html/_static/fonts/Lato/lato-regular.woff b/build/lib/WORC/doc/_build/html/_static/fonts/Lato/lato-regular.woff deleted file mode 100644 index ae1307ff..00000000 Binary files a/build/lib/WORC/doc/_build/html/_static/fonts/Lato/lato-regular.woff and /dev/null differ diff --git a/build/lib/WORC/doc/_build/html/_static/fonts/Lato/lato-regular.woff2 b/build/lib/WORC/doc/_build/html/_static/fonts/Lato/lato-regular.woff2 deleted file mode 100644 index 3bf98433..00000000 Binary files a/build/lib/WORC/doc/_build/html/_static/fonts/Lato/lato-regular.woff2 and /dev/null differ diff --git a/build/lib/WORC/doc/_build/html/_static/fonts/RobotoSlab-Bold.ttf b/build/lib/WORC/doc/_build/html/_static/fonts/RobotoSlab-Bold.ttf deleted file mode 100644 index df5d1df2..00000000 Binary files a/build/lib/WORC/doc/_build/html/_static/fonts/RobotoSlab-Bold.ttf and /dev/null differ diff --git a/build/lib/WORC/doc/_build/html/_static/fonts/RobotoSlab-Regular.ttf b/build/lib/WORC/doc/_build/html/_static/fonts/RobotoSlab-Regular.ttf deleted file mode 100644 index eb52a790..00000000 Binary files a/build/lib/WORC/doc/_build/html/_static/fonts/RobotoSlab-Regular.ttf and /dev/null differ diff --git a/build/lib/WORC/doc/_build/html/_static/fonts/RobotoSlab/roboto-slab-v7-bold.eot b/build/lib/WORC/doc/_build/html/_static/fonts/RobotoSlab/roboto-slab-v7-bold.eot deleted file mode 100644 index 79dc8efe..00000000 Binary files a/build/lib/WORC/doc/_build/html/_static/fonts/RobotoSlab/roboto-slab-v7-bold.eot and /dev/null differ diff --git a/build/lib/WORC/doc/_build/html/_static/fonts/RobotoSlab/roboto-slab-v7-bold.ttf b/build/lib/WORC/doc/_build/html/_static/fonts/RobotoSlab/roboto-slab-v7-bold.ttf deleted file mode 100644 index df5d1df2..00000000 Binary files a/build/lib/WORC/doc/_build/html/_static/fonts/RobotoSlab/roboto-slab-v7-bold.ttf and /dev/null differ diff --git a/build/lib/WORC/doc/_build/html/_static/fonts/RobotoSlab/roboto-slab-v7-bold.woff b/build/lib/WORC/doc/_build/html/_static/fonts/RobotoSlab/roboto-slab-v7-bold.woff deleted file mode 100644 index 6cb60000..00000000 Binary files a/build/lib/WORC/doc/_build/html/_static/fonts/RobotoSlab/roboto-slab-v7-bold.woff and /dev/null differ diff --git a/build/lib/WORC/doc/_build/html/_static/fonts/RobotoSlab/roboto-slab-v7-bold.woff2 b/build/lib/WORC/doc/_build/html/_static/fonts/RobotoSlab/roboto-slab-v7-bold.woff2 deleted file mode 100644 index 7059e231..00000000 Binary files a/build/lib/WORC/doc/_build/html/_static/fonts/RobotoSlab/roboto-slab-v7-bold.woff2 and /dev/null differ diff --git a/build/lib/WORC/doc/_build/html/_static/fonts/RobotoSlab/roboto-slab-v7-regular.eot b/build/lib/WORC/doc/_build/html/_static/fonts/RobotoSlab/roboto-slab-v7-regular.eot deleted file mode 100644 index 2f7ca78a..00000000 Binary files a/build/lib/WORC/doc/_build/html/_static/fonts/RobotoSlab/roboto-slab-v7-regular.eot and /dev/null differ diff --git a/build/lib/WORC/doc/_build/html/_static/fonts/RobotoSlab/roboto-slab-v7-regular.ttf b/build/lib/WORC/doc/_build/html/_static/fonts/RobotoSlab/roboto-slab-v7-regular.ttf deleted file mode 100644 index eb52a790..00000000 Binary files a/build/lib/WORC/doc/_build/html/_static/fonts/RobotoSlab/roboto-slab-v7-regular.ttf and /dev/null differ diff --git a/build/lib/WORC/doc/_build/html/_static/fonts/RobotoSlab/roboto-slab-v7-regular.woff b/build/lib/WORC/doc/_build/html/_static/fonts/RobotoSlab/roboto-slab-v7-regular.woff deleted file mode 100644 index f815f63f..00000000 Binary files a/build/lib/WORC/doc/_build/html/_static/fonts/RobotoSlab/roboto-slab-v7-regular.woff and /dev/null differ diff --git a/build/lib/WORC/doc/_build/html/_static/fonts/RobotoSlab/roboto-slab-v7-regular.woff2 b/build/lib/WORC/doc/_build/html/_static/fonts/RobotoSlab/roboto-slab-v7-regular.woff2 deleted file mode 100644 index f2c76e5b..00000000 Binary files a/build/lib/WORC/doc/_build/html/_static/fonts/RobotoSlab/roboto-slab-v7-regular.woff2 and /dev/null differ diff --git a/build/lib/WORC/doc/_build/html/_static/fonts/fontawesome-webfont.eot b/build/lib/WORC/doc/_build/html/_static/fonts/fontawesome-webfont.eot deleted file mode 100644 index e9f60ca9..00000000 Binary files a/build/lib/WORC/doc/_build/html/_static/fonts/fontawesome-webfont.eot and /dev/null differ diff --git a/build/lib/WORC/doc/_build/html/_static/fonts/fontawesome-webfont.svg b/build/lib/WORC/doc/_build/html/_static/fonts/fontawesome-webfont.svg deleted file mode 100644 index 855c845e..00000000 --- a/build/lib/WORC/doc/_build/html/_static/fonts/fontawesome-webfont.svg +++ /dev/null @@ -1,2671 +0,0 @@ - - - - -Created by FontForge 20120731 at Mon Oct 24 17:37:40 2016 - By ,,, -Copyright Dave Gandy 2016. All rights reserved. - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - diff --git a/build/lib/WORC/doc/_build/html/_static/fonts/fontawesome-webfont.ttf b/build/lib/WORC/doc/_build/html/_static/fonts/fontawesome-webfont.ttf deleted file mode 100644 index 35acda2f..00000000 Binary files a/build/lib/WORC/doc/_build/html/_static/fonts/fontawesome-webfont.ttf and /dev/null differ diff --git a/build/lib/WORC/doc/_build/html/_static/fonts/fontawesome-webfont.woff b/build/lib/WORC/doc/_build/html/_static/fonts/fontawesome-webfont.woff deleted file mode 100644 index 400014a4..00000000 Binary files a/build/lib/WORC/doc/_build/html/_static/fonts/fontawesome-webfont.woff and /dev/null differ diff --git a/build/lib/WORC/doc/_build/html/_static/fonts/fontawesome-webfont.woff2 b/build/lib/WORC/doc/_build/html/_static/fonts/fontawesome-webfont.woff2 deleted file mode 100644 index 4d13fc60..00000000 Binary files a/build/lib/WORC/doc/_build/html/_static/fonts/fontawesome-webfont.woff2 and /dev/null differ diff --git a/build/lib/WORC/doc/_build/html/_static/graphviz.css b/build/lib/WORC/doc/_build/html/_static/graphviz.css deleted file mode 100644 index 09288cbb..00000000 --- a/build/lib/WORC/doc/_build/html/_static/graphviz.css +++ /dev/null @@ -1,19 +0,0 @@ -/* - * graphviz.css - * ~~~~~~~~~~~~ - * - * Sphinx stylesheet -- graphviz extension. - * - * :copyright: Copyright 2007-2019 by the Sphinx team, see AUTHORS. - * :license: BSD, see LICENSE for details. - * - */ - -img.graphviz { - border: 0; - max-width: 100%; -} - -object.graphviz { - max-width: 100%; -} diff --git a/build/lib/WORC/doc/_build/html/_static/jquery-3.2.1.js b/build/lib/WORC/doc/_build/html/_static/jquery-3.2.1.js deleted file mode 100644 index d2d8ca47..00000000 --- a/build/lib/WORC/doc/_build/html/_static/jquery-3.2.1.js +++ /dev/null @@ -1,10253 +0,0 @@ -/*! - * jQuery JavaScript Library v3.2.1 - * https://jquery.com/ - * - * Includes Sizzle.js - * https://sizzlejs.com/ - * - * Copyright JS Foundation and other contributors - * Released under the MIT license - * https://jquery.org/license - * - * Date: 2017-03-20T18:59Z - */ -( function( global, factory ) { - - "use strict"; - - if ( typeof module === "object" && typeof module.exports === "object" ) { - - // For CommonJS and CommonJS-like environments where a proper `window` - // is present, execute the factory and get jQuery. - // For environments that do not have a `window` with a `document` - // (such as Node.js), expose a factory as module.exports. - // This accentuates the need for the creation of a real `window`. - // e.g. var jQuery = require("jquery")(window); - // See ticket #14549 for more info. - module.exports = global.document ? - factory( global, true ) : - function( w ) { - if ( !w.document ) { - throw new Error( "jQuery requires a window with a document" ); - } - return factory( w ); - }; - } else { - factory( global ); - } - -// Pass this if window is not defined yet -} )( typeof window !== "undefined" ? window : this, function( window, noGlobal ) { - -// Edge <= 12 - 13+, Firefox <=18 - 45+, IE 10 - 11, Safari 5.1 - 9+, iOS 6 - 9.1 -// throw exceptions when non-strict code (e.g., ASP.NET 4.5) accesses strict mode -// arguments.callee.caller (trac-13335). But as of jQuery 3.0 (2016), strict mode should be common -// enough that all such attempts are guarded in a try block. -"use strict"; - -var arr = []; - -var document = window.document; - -var getProto = Object.getPrototypeOf; - -var slice = arr.slice; - -var concat = arr.concat; - -var push = arr.push; - -var indexOf = arr.indexOf; - -var class2type = {}; - -var toString = class2type.toString; - -var hasOwn = class2type.hasOwnProperty; - -var fnToString = hasOwn.toString; - -var ObjectFunctionString = fnToString.call( Object ); - -var support = {}; - - - - function DOMEval( code, doc ) { - doc = doc || document; - - var script = doc.createElement( "script" ); - - script.text = code; - doc.head.appendChild( script ).parentNode.removeChild( script ); - } -/* global Symbol */ -// Defining this global in .eslintrc.json would create a danger of using the global -// unguarded in another place, it seems safer to define global only for this module - - - -var - version = "3.2.1", - - // Define a local copy of jQuery - jQuery = function( selector, context ) { - - // The jQuery object is actually just the init constructor 'enhanced' - // Need init if jQuery is called (just allow error to be thrown if not included) - return new jQuery.fn.init( selector, context ); - }, - - // Support: Android <=4.0 only - // Make sure we trim BOM and NBSP - rtrim = /^[\s\uFEFF\xA0]+|[\s\uFEFF\xA0]+$/g, - - // Matches dashed string for camelizing - rmsPrefix = /^-ms-/, - rdashAlpha = /-([a-z])/g, - - // Used by jQuery.camelCase as callback to replace() - fcamelCase = function( all, letter ) { - return letter.toUpperCase(); - }; - -jQuery.fn = jQuery.prototype = { - - // The current version of jQuery being used - jquery: version, - - constructor: jQuery, - - // The default length of a jQuery object is 0 - length: 0, - - toArray: function() { - return slice.call( this ); - }, - - // Get the Nth element in the matched element set OR - // Get the whole matched element set as a clean array - get: function( num ) { - - // Return all the elements in a clean array - if ( num == null ) { - return slice.call( this ); - } - - // Return just the one element from the set - return num < 0 ? this[ num + this.length ] : this[ num ]; - }, - - // Take an array of elements and push it onto the stack - // (returning the new matched element set) - pushStack: function( elems ) { - - // Build a new jQuery matched element set - var ret = jQuery.merge( this.constructor(), elems ); - - // Add the old object onto the stack (as a reference) - ret.prevObject = this; - - // Return the newly-formed element set - return ret; - }, - - // Execute a callback for every element in the matched set. - each: function( callback ) { - return jQuery.each( this, callback ); - }, - - map: function( callback ) { - return this.pushStack( jQuery.map( this, function( elem, i ) { - return callback.call( elem, i, elem ); - } ) ); - }, - - slice: function() { - return this.pushStack( slice.apply( this, arguments ) ); - }, - - first: function() { - return this.eq( 0 ); - }, - - last: function() { - return this.eq( -1 ); - }, - - eq: function( i ) { - var len = this.length, - j = +i + ( i < 0 ? len : 0 ); - return this.pushStack( j >= 0 && j < len ? [ this[ j ] ] : [] ); - }, - - end: function() { - return this.prevObject || this.constructor(); - }, - - // For internal use only. - // Behaves like an Array's method, not like a jQuery method. - push: push, - sort: arr.sort, - splice: arr.splice -}; - -jQuery.extend = jQuery.fn.extend = function() { - var options, name, src, copy, copyIsArray, clone, - target = arguments[ 0 ] || {}, - i = 1, - length = arguments.length, - deep = false; - - // Handle a deep copy situation - if ( typeof target === "boolean" ) { - deep = target; - - // Skip the boolean and the target - target = arguments[ i ] || {}; - i++; - } - - // Handle case when target is a string or something (possible in deep copy) - if ( typeof target !== "object" && !jQuery.isFunction( target ) ) { - target = {}; - } - - // Extend jQuery itself if only one argument is passed - if ( i === length ) { - target = this; - i--; - } - - for ( ; i < length; i++ ) { - - // Only deal with non-null/undefined values - if ( ( options = arguments[ i ] ) != null ) { - - // Extend the base object - for ( name in options ) { - src = target[ name ]; - copy = options[ name ]; - - // Prevent never-ending loop - if ( target === copy ) { - continue; - } - - // Recurse if we're merging plain objects or arrays - if ( deep && copy && ( jQuery.isPlainObject( copy ) || - ( copyIsArray = Array.isArray( copy ) ) ) ) { - - if ( copyIsArray ) { - copyIsArray = false; - clone = src && Array.isArray( src ) ? src : []; - - } else { - clone = src && jQuery.isPlainObject( src ) ? src : {}; - } - - // Never move original objects, clone them - target[ name ] = jQuery.extend( deep, clone, copy ); - - // Don't bring in undefined values - } else if ( copy !== undefined ) { - target[ name ] = copy; - } - } - } - } - - // Return the modified object - return target; -}; - -jQuery.extend( { - - // Unique for each copy of jQuery on the page - expando: "jQuery" + ( version + Math.random() ).replace( /\D/g, "" ), - - // Assume jQuery is ready without the ready module - isReady: true, - - error: function( msg ) { - throw new Error( msg ); - }, - - noop: function() {}, - - isFunction: function( obj ) { - return jQuery.type( obj ) === "function"; - }, - - isWindow: function( obj ) { - return obj != null && obj === obj.window; - }, - - isNumeric: function( obj ) { - - // As of jQuery 3.0, isNumeric is limited to - // strings and numbers (primitives or objects) - // that can be coerced to finite numbers (gh-2662) - var type = jQuery.type( obj ); - return ( type === "number" || type === "string" ) && - - // parseFloat NaNs numeric-cast false positives ("") - // ...but misinterprets leading-number strings, particularly hex literals ("0x...") - // subtraction forces infinities to NaN - !isNaN( obj - parseFloat( obj ) ); - }, - - isPlainObject: function( obj ) { - var proto, Ctor; - - // Detect obvious negatives - // Use toString instead of jQuery.type to catch host objects - if ( !obj || toString.call( obj ) !== "[object Object]" ) { - return false; - } - - proto = getProto( obj ); - - // Objects with no prototype (e.g., `Object.create( null )`) are plain - if ( !proto ) { - return true; - } - - // Objects with prototype are plain iff they were constructed by a global Object function - Ctor = hasOwn.call( proto, "constructor" ) && proto.constructor; - return typeof Ctor === "function" && fnToString.call( Ctor ) === ObjectFunctionString; - }, - - isEmptyObject: function( obj ) { - - /* eslint-disable no-unused-vars */ - // See https://github.com/eslint/eslint/issues/6125 - var name; - - for ( name in obj ) { - return false; - } - return true; - }, - - type: function( obj ) { - if ( obj == null ) { - return obj + ""; - } - - // Support: Android <=2.3 only (functionish RegExp) - return typeof obj === "object" || typeof obj === "function" ? - class2type[ toString.call( obj ) ] || "object" : - typeof obj; - }, - - // Evaluates a script in a global context - globalEval: function( code ) { - DOMEval( code ); - }, - - // Convert dashed to camelCase; used by the css and data modules - // Support: IE <=9 - 11, Edge 12 - 13 - // Microsoft forgot to hump their vendor prefix (#9572) - camelCase: function( string ) { - return string.replace( rmsPrefix, "ms-" ).replace( rdashAlpha, fcamelCase ); - }, - - each: function( obj, callback ) { - var length, i = 0; - - if ( isArrayLike( obj ) ) { - length = obj.length; - for ( ; i < length; i++ ) { - if ( callback.call( obj[ i ], i, obj[ i ] ) === false ) { - break; - } - } - } else { - for ( i in obj ) { - if ( callback.call( obj[ i ], i, obj[ i ] ) === false ) { - break; - } - } - } - - return obj; - }, - - // Support: Android <=4.0 only - trim: function( text ) { - return text == null ? - "" : - ( text + "" ).replace( rtrim, "" ); - }, - - // results is for internal usage only - makeArray: function( arr, results ) { - var ret = results || []; - - if ( arr != null ) { - if ( isArrayLike( Object( arr ) ) ) { - jQuery.merge( ret, - typeof arr === "string" ? - [ arr ] : arr - ); - } else { - push.call( ret, arr ); - } - } - - return ret; - }, - - inArray: function( elem, arr, i ) { - return arr == null ? -1 : indexOf.call( arr, elem, i ); - }, - - // Support: Android <=4.0 only, PhantomJS 1 only - // push.apply(_, arraylike) throws on ancient WebKit - merge: function( first, second ) { - var len = +second.length, - j = 0, - i = first.length; - - for ( ; j < len; j++ ) { - first[ i++ ] = second[ j ]; - } - - first.length = i; - - return first; - }, - - grep: function( elems, callback, invert ) { - var callbackInverse, - matches = [], - i = 0, - length = elems.length, - callbackExpect = !invert; - - // Go through the array, only saving the items - // that pass the validator function - for ( ; i < length; i++ ) { - callbackInverse = !callback( elems[ i ], i ); - if ( callbackInverse !== callbackExpect ) { - matches.push( elems[ i ] ); - } - } - - return matches; - }, - - // arg is for internal usage only - map: function( elems, callback, arg ) { - var length, value, - i = 0, - ret = []; - - // Go through the array, translating each of the items to their new values - if ( isArrayLike( elems ) ) { - length = elems.length; - for ( ; i < length; i++ ) { - value = callback( elems[ i ], i, arg ); - - if ( value != null ) { - ret.push( value ); - } - } - - // Go through every key on the object, - } else { - for ( i in elems ) { - value = callback( elems[ i ], i, arg ); - - if ( value != null ) { - ret.push( value ); - } - } - } - - // Flatten any nested arrays - return concat.apply( [], ret ); - }, - - // A global GUID counter for objects - guid: 1, - - // Bind a function to a context, optionally partially applying any - // arguments. - proxy: function( fn, context ) { - var tmp, args, proxy; - - if ( typeof context === "string" ) { - tmp = fn[ context ]; - context = fn; - fn = tmp; - } - - // Quick check to determine if target is callable, in the spec - // this throws a TypeError, but we will just return undefined. - if ( !jQuery.isFunction( fn ) ) { - return undefined; - } - - // Simulated bind - args = slice.call( arguments, 2 ); - proxy = function() { - return fn.apply( context || this, args.concat( slice.call( arguments ) ) ); - }; - - // Set the guid of unique handler to the same of original handler, so it can be removed - proxy.guid = fn.guid = fn.guid || jQuery.guid++; - - return proxy; - }, - - now: Date.now, - - // jQuery.support is not used in Core but other projects attach their - // properties to it so it needs to exist. - support: support -} ); - -if ( typeof Symbol === "function" ) { - jQuery.fn[ Symbol.iterator ] = arr[ Symbol.iterator ]; -} - -// Populate the class2type map -jQuery.each( "Boolean Number String Function Array Date RegExp Object Error Symbol".split( " " ), -function( i, name ) { - class2type[ "[object " + name + "]" ] = name.toLowerCase(); -} ); - -function isArrayLike( obj ) { - - // Support: real iOS 8.2 only (not reproducible in simulator) - // `in` check used to prevent JIT error (gh-2145) - // hasOwn isn't used here due to false negatives - // regarding Nodelist length in IE - var length = !!obj && "length" in obj && obj.length, - type = jQuery.type( obj ); - - if ( type === "function" || jQuery.isWindow( obj ) ) { - return false; - } - - return type === "array" || length === 0 || - typeof length === "number" && length > 0 && ( length - 1 ) in obj; -} -var Sizzle = -/*! - * Sizzle CSS Selector Engine v2.3.3 - * https://sizzlejs.com/ - * - * Copyright jQuery Foundation and other contributors - * Released under the MIT license - * http://jquery.org/license - * - * Date: 2016-08-08 - */ -(function( window ) { - -var i, - support, - Expr, - getText, - isXML, - tokenize, - compile, - select, - outermostContext, - sortInput, - hasDuplicate, - - // Local document vars - setDocument, - document, - docElem, - documentIsHTML, - rbuggyQSA, - rbuggyMatches, - matches, - contains, - - // Instance-specific data - expando = "sizzle" + 1 * new Date(), - preferredDoc = window.document, - dirruns = 0, - done = 0, - classCache = createCache(), - tokenCache = createCache(), - compilerCache = createCache(), - sortOrder = function( a, b ) { - if ( a === b ) { - hasDuplicate = true; - } - return 0; - }, - - // Instance methods - hasOwn = ({}).hasOwnProperty, - arr = [], - pop = arr.pop, - push_native = arr.push, - push = arr.push, - slice = arr.slice, - // Use a stripped-down indexOf as it's faster than native - // https://jsperf.com/thor-indexof-vs-for/5 - indexOf = function( list, elem ) { - var i = 0, - len = list.length; - for ( ; i < len; i++ ) { - if ( list[i] === elem ) { - return i; - } - } - return -1; - }, - - booleans = "checked|selected|async|autofocus|autoplay|controls|defer|disabled|hidden|ismap|loop|multiple|open|readonly|required|scoped", - - // Regular expressions - - // http://www.w3.org/TR/css3-selectors/#whitespace - whitespace = "[\\x20\\t\\r\\n\\f]", - - // http://www.w3.org/TR/CSS21/syndata.html#value-def-identifier - identifier = "(?:\\\\.|[\\w-]|[^\0-\\xa0])+", - - // Attribute selectors: http://www.w3.org/TR/selectors/#attribute-selectors - attributes = "\\[" + whitespace + "*(" + identifier + ")(?:" + whitespace + - // Operator (capture 2) - "*([*^$|!~]?=)" + whitespace + - // "Attribute values must be CSS identifiers [capture 5] or strings [capture 3 or capture 4]" - "*(?:'((?:\\\\.|[^\\\\'])*)'|\"((?:\\\\.|[^\\\\\"])*)\"|(" + identifier + "))|)" + whitespace + - "*\\]", - - pseudos = ":(" + identifier + ")(?:\\((" + - // To reduce the number of selectors needing tokenize in the preFilter, prefer arguments: - // 1. quoted (capture 3; capture 4 or capture 5) - "('((?:\\\\.|[^\\\\'])*)'|\"((?:\\\\.|[^\\\\\"])*)\")|" + - // 2. simple (capture 6) - "((?:\\\\.|[^\\\\()[\\]]|" + attributes + ")*)|" + - // 3. anything else (capture 2) - ".*" + - ")\\)|)", - - // Leading and non-escaped trailing whitespace, capturing some non-whitespace characters preceding the latter - rwhitespace = new RegExp( whitespace + "+", "g" ), - rtrim = new RegExp( "^" + whitespace + "+|((?:^|[^\\\\])(?:\\\\.)*)" + whitespace + "+$", "g" ), - - rcomma = new RegExp( "^" + whitespace + "*," + whitespace + "*" ), - rcombinators = new RegExp( "^" + whitespace + "*([>+~]|" + whitespace + ")" + whitespace + "*" ), - - rattributeQuotes = new RegExp( "=" + whitespace + "*([^\\]'\"]*?)" + whitespace + "*\\]", "g" ), - - rpseudo = new RegExp( pseudos ), - ridentifier = new RegExp( "^" + identifier + "$" ), - - matchExpr = { - "ID": new RegExp( "^#(" + identifier + ")" ), - "CLASS": new RegExp( "^\\.(" + identifier + ")" ), - "TAG": new RegExp( "^(" + identifier + "|[*])" ), - "ATTR": new RegExp( "^" + attributes ), - "PSEUDO": new RegExp( "^" + pseudos ), - "CHILD": new RegExp( "^:(only|first|last|nth|nth-last)-(child|of-type)(?:\\(" + whitespace + - "*(even|odd|(([+-]|)(\\d*)n|)" + whitespace + "*(?:([+-]|)" + whitespace + - "*(\\d+)|))" + whitespace + "*\\)|)", "i" ), - "bool": new RegExp( "^(?:" + booleans + ")$", "i" ), - // For use in libraries implementing .is() - // We use this for POS matching in `select` - "needsContext": new RegExp( "^" + whitespace + "*[>+~]|:(even|odd|eq|gt|lt|nth|first|last)(?:\\(" + - whitespace + "*((?:-\\d)?\\d*)" + whitespace + "*\\)|)(?=[^-]|$)", "i" ) - }, - - rinputs = /^(?:input|select|textarea|button)$/i, - rheader = /^h\d$/i, - - rnative = /^[^{]+\{\s*\[native \w/, - - // Easily-parseable/retrievable ID or TAG or CLASS selectors - rquickExpr = /^(?:#([\w-]+)|(\w+)|\.([\w-]+))$/, - - rsibling = /[+~]/, - - // CSS escapes - // http://www.w3.org/TR/CSS21/syndata.html#escaped-characters - runescape = new RegExp( "\\\\([\\da-f]{1,6}" + whitespace + "?|(" + whitespace + ")|.)", "ig" ), - funescape = function( _, escaped, escapedWhitespace ) { - var high = "0x" + escaped - 0x10000; - // NaN means non-codepoint - // Support: Firefox<24 - // Workaround erroneous numeric interpretation of +"0x" - return high !== high || escapedWhitespace ? - escaped : - high < 0 ? - // BMP codepoint - String.fromCharCode( high + 0x10000 ) : - // Supplemental Plane codepoint (surrogate pair) - String.fromCharCode( high >> 10 | 0xD800, high & 0x3FF | 0xDC00 ); - }, - - // CSS string/identifier serialization - // https://drafts.csswg.org/cssom/#common-serializing-idioms - rcssescape = /([\0-\x1f\x7f]|^-?\d)|^-$|[^\0-\x1f\x7f-\uFFFF\w-]/g, - fcssescape = function( ch, asCodePoint ) { - if ( asCodePoint ) { - - // U+0000 NULL becomes U+FFFD REPLACEMENT CHARACTER - if ( ch === "\0" ) { - return "\uFFFD"; - } - - // Control characters and (dependent upon position) numbers get escaped as code points - return ch.slice( 0, -1 ) + "\\" + ch.charCodeAt( ch.length - 1 ).toString( 16 ) + " "; - } - - // Other potentially-special ASCII characters get backslash-escaped - return "\\" + ch; - }, - - // Used for iframes - // See setDocument() - // Removing the function wrapper causes a "Permission Denied" - // error in IE - unloadHandler = function() { - setDocument(); - }, - - disabledAncestor = addCombinator( - function( elem ) { - return elem.disabled === true && ("form" in elem || "label" in elem); - }, - { dir: "parentNode", next: "legend" } - ); - -// Optimize for push.apply( _, NodeList ) -try { - push.apply( - (arr = slice.call( preferredDoc.childNodes )), - preferredDoc.childNodes - ); - // Support: Android<4.0 - // Detect silently failing push.apply - arr[ preferredDoc.childNodes.length ].nodeType; -} catch ( e ) { - push = { apply: arr.length ? - - // Leverage slice if possible - function( target, els ) { - push_native.apply( target, slice.call(els) ); - } : - - // Support: IE<9 - // Otherwise append directly - function( target, els ) { - var j = target.length, - i = 0; - // Can't trust NodeList.length - while ( (target[j++] = els[i++]) ) {} - target.length = j - 1; - } - }; -} - -function Sizzle( selector, context, results, seed ) { - var m, i, elem, nid, match, groups, newSelector, - newContext = context && context.ownerDocument, - - // nodeType defaults to 9, since context defaults to document - nodeType = context ? context.nodeType : 9; - - results = results || []; - - // Return early from calls with invalid selector or context - if ( typeof selector !== "string" || !selector || - nodeType !== 1 && nodeType !== 9 && nodeType !== 11 ) { - - return results; - } - - // Try to shortcut find operations (as opposed to filters) in HTML documents - if ( !seed ) { - - if ( ( context ? context.ownerDocument || context : preferredDoc ) !== document ) { - setDocument( context ); - } - context = context || document; - - if ( documentIsHTML ) { - - // If the selector is sufficiently simple, try using a "get*By*" DOM method - // (excepting DocumentFragment context, where the methods don't exist) - if ( nodeType !== 11 && (match = rquickExpr.exec( selector )) ) { - - // ID selector - if ( (m = match[1]) ) { - - // Document context - if ( nodeType === 9 ) { - if ( (elem = context.getElementById( m )) ) { - - // Support: IE, Opera, Webkit - // TODO: identify versions - // getElementById can match elements by name instead of ID - if ( elem.id === m ) { - results.push( elem ); - return results; - } - } else { - return results; - } - - // Element context - } else { - - // Support: IE, Opera, Webkit - // TODO: identify versions - // getElementById can match elements by name instead of ID - if ( newContext && (elem = newContext.getElementById( m )) && - contains( context, elem ) && - elem.id === m ) { - - results.push( elem ); - return results; - } - } - - // Type selector - } else if ( match[2] ) { - push.apply( results, context.getElementsByTagName( selector ) ); - return results; - - // Class selector - } else if ( (m = match[3]) && support.getElementsByClassName && - context.getElementsByClassName ) { - - push.apply( results, context.getElementsByClassName( m ) ); - return results; - } - } - - // Take advantage of querySelectorAll - if ( support.qsa && - !compilerCache[ selector + " " ] && - (!rbuggyQSA || !rbuggyQSA.test( selector )) ) { - - if ( nodeType !== 1 ) { - newContext = context; - newSelector = selector; - - // qSA looks outside Element context, which is not what we want - // Thanks to Andrew Dupont for this workaround technique - // Support: IE <=8 - // Exclude object elements - } else if ( context.nodeName.toLowerCase() !== "object" ) { - - // Capture the context ID, setting it first if necessary - if ( (nid = context.getAttribute( "id" )) ) { - nid = nid.replace( rcssescape, fcssescape ); - } else { - context.setAttribute( "id", (nid = expando) ); - } - - // Prefix every selector in the list - groups = tokenize( selector ); - i = groups.length; - while ( i-- ) { - groups[i] = "#" + nid + " " + toSelector( groups[i] ); - } - newSelector = groups.join( "," ); - - // Expand context for sibling selectors - newContext = rsibling.test( selector ) && testContext( context.parentNode ) || - context; - } - - if ( newSelector ) { - try { - push.apply( results, - newContext.querySelectorAll( newSelector ) - ); - return results; - } catch ( qsaError ) { - } finally { - if ( nid === expando ) { - context.removeAttribute( "id" ); - } - } - } - } - } - } - - // All others - return select( selector.replace( rtrim, "$1" ), context, results, seed ); -} - -/** - * Create key-value caches of limited size - * @returns {function(string, object)} Returns the Object data after storing it on itself with - * property name the (space-suffixed) string and (if the cache is larger than Expr.cacheLength) - * deleting the oldest entry - */ -function createCache() { - var keys = []; - - function cache( key, value ) { - // Use (key + " ") to avoid collision with native prototype properties (see Issue #157) - if ( keys.push( key + " " ) > Expr.cacheLength ) { - // Only keep the most recent entries - delete cache[ keys.shift() ]; - } - return (cache[ key + " " ] = value); - } - return cache; -} - -/** - * Mark a function for special use by Sizzle - * @param {Function} fn The function to mark - */ -function markFunction( fn ) { - fn[ expando ] = true; - return fn; -} - -/** - * Support testing using an element - * @param {Function} fn Passed the created element and returns a boolean result - */ -function assert( fn ) { - var el = document.createElement("fieldset"); - - try { - return !!fn( el ); - } catch (e) { - return false; - } finally { - // Remove from its parent by default - if ( el.parentNode ) { - el.parentNode.removeChild( el ); - } - // release memory in IE - el = null; - } -} - -/** - * Adds the same handler for all of the specified attrs - * @param {String} attrs Pipe-separated list of attributes - * @param {Function} handler The method that will be applied - */ -function addHandle( attrs, handler ) { - var arr = attrs.split("|"), - i = arr.length; - - while ( i-- ) { - Expr.attrHandle[ arr[i] ] = handler; - } -} - -/** - * Checks document order of two siblings - * @param {Element} a - * @param {Element} b - * @returns {Number} Returns less than 0 if a precedes b, greater than 0 if a follows b - */ -function siblingCheck( a, b ) { - var cur = b && a, - diff = cur && a.nodeType === 1 && b.nodeType === 1 && - a.sourceIndex - b.sourceIndex; - - // Use IE sourceIndex if available on both nodes - if ( diff ) { - return diff; - } - - // Check if b follows a - if ( cur ) { - while ( (cur = cur.nextSibling) ) { - if ( cur === b ) { - return -1; - } - } - } - - return a ? 1 : -1; -} - -/** - * Returns a function to use in pseudos for input types - * @param {String} type - */ -function createInputPseudo( type ) { - return function( elem ) { - var name = elem.nodeName.toLowerCase(); - return name === "input" && elem.type === type; - }; -} - -/** - * Returns a function to use in pseudos for buttons - * @param {String} type - */ -function createButtonPseudo( type ) { - return function( elem ) { - var name = elem.nodeName.toLowerCase(); - return (name === "input" || name === "button") && elem.type === type; - }; -} - -/** - * Returns a function to use in pseudos for :enabled/:disabled - * @param {Boolean} disabled true for :disabled; false for :enabled - */ -function createDisabledPseudo( disabled ) { - - // Known :disabled false positives: fieldset[disabled] > legend:nth-of-type(n+2) :can-disable - return function( elem ) { - - // Only certain elements can match :enabled or :disabled - // https://html.spec.whatwg.org/multipage/scripting.html#selector-enabled - // https://html.spec.whatwg.org/multipage/scripting.html#selector-disabled - if ( "form" in elem ) { - - // Check for inherited disabledness on relevant non-disabled elements: - // * listed form-associated elements in a disabled fieldset - // https://html.spec.whatwg.org/multipage/forms.html#category-listed - // https://html.spec.whatwg.org/multipage/forms.html#concept-fe-disabled - // * option elements in a disabled optgroup - // https://html.spec.whatwg.org/multipage/forms.html#concept-option-disabled - // All such elements have a "form" property. - if ( elem.parentNode && elem.disabled === false ) { - - // Option elements defer to a parent optgroup if present - if ( "label" in elem ) { - if ( "label" in elem.parentNode ) { - return elem.parentNode.disabled === disabled; - } else { - return elem.disabled === disabled; - } - } - - // Support: IE 6 - 11 - // Use the isDisabled shortcut property to check for disabled fieldset ancestors - return elem.isDisabled === disabled || - - // Where there is no isDisabled, check manually - /* jshint -W018 */ - elem.isDisabled !== !disabled && - disabledAncestor( elem ) === disabled; - } - - return elem.disabled === disabled; - - // Try to winnow out elements that can't be disabled before trusting the disabled property. - // Some victims get caught in our net (label, legend, menu, track), but it shouldn't - // even exist on them, let alone have a boolean value. - } else if ( "label" in elem ) { - return elem.disabled === disabled; - } - - // Remaining elements are neither :enabled nor :disabled - return false; - }; -} - -/** - * Returns a function to use in pseudos for positionals - * @param {Function} fn - */ -function createPositionalPseudo( fn ) { - return markFunction(function( argument ) { - argument = +argument; - return markFunction(function( seed, matches ) { - var j, - matchIndexes = fn( [], seed.length, argument ), - i = matchIndexes.length; - - // Match elements found at the specified indexes - while ( i-- ) { - if ( seed[ (j = matchIndexes[i]) ] ) { - seed[j] = !(matches[j] = seed[j]); - } - } - }); - }); -} - -/** - * Checks a node for validity as a Sizzle context - * @param {Element|Object=} context - * @returns {Element|Object|Boolean} The input node if acceptable, otherwise a falsy value - */ -function testContext( context ) { - return context && typeof context.getElementsByTagName !== "undefined" && context; -} - -// Expose support vars for convenience -support = Sizzle.support = {}; - -/** - * Detects XML nodes - * @param {Element|Object} elem An element or a document - * @returns {Boolean} True iff elem is a non-HTML XML node - */ -isXML = Sizzle.isXML = function( elem ) { - // documentElement is verified for cases where it doesn't yet exist - // (such as loading iframes in IE - #4833) - var documentElement = elem && (elem.ownerDocument || elem).documentElement; - return documentElement ? documentElement.nodeName !== "HTML" : false; -}; - -/** - * Sets document-related variables once based on the current document - * @param {Element|Object} [doc] An element or document object to use to set the document - * @returns {Object} Returns the current document - */ -setDocument = Sizzle.setDocument = function( node ) { - var hasCompare, subWindow, - doc = node ? node.ownerDocument || node : preferredDoc; - - // Return early if doc is invalid or already selected - if ( doc === document || doc.nodeType !== 9 || !doc.documentElement ) { - return document; - } - - // Update global variables - document = doc; - docElem = document.documentElement; - documentIsHTML = !isXML( document ); - - // Support: IE 9-11, Edge - // Accessing iframe documents after unload throws "permission denied" errors (jQuery #13936) - if ( preferredDoc !== document && - (subWindow = document.defaultView) && subWindow.top !== subWindow ) { - - // Support: IE 11, Edge - if ( subWindow.addEventListener ) { - subWindow.addEventListener( "unload", unloadHandler, false ); - - // Support: IE 9 - 10 only - } else if ( subWindow.attachEvent ) { - subWindow.attachEvent( "onunload", unloadHandler ); - } - } - - /* Attributes - ---------------------------------------------------------------------- */ - - // Support: IE<8 - // Verify that getAttribute really returns attributes and not properties - // (excepting IE8 booleans) - support.attributes = assert(function( el ) { - el.className = "i"; - return !el.getAttribute("className"); - }); - - /* getElement(s)By* - ---------------------------------------------------------------------- */ - - // Check if getElementsByTagName("*") returns only elements - support.getElementsByTagName = assert(function( el ) { - el.appendChild( document.createComment("") ); - return !el.getElementsByTagName("*").length; - }); - - // Support: IE<9 - support.getElementsByClassName = rnative.test( document.getElementsByClassName ); - - // Support: IE<10 - // Check if getElementById returns elements by name - // The broken getElementById methods don't pick up programmatically-set names, - // so use a roundabout getElementsByName test - support.getById = assert(function( el ) { - docElem.appendChild( el ).id = expando; - return !document.getElementsByName || !document.getElementsByName( expando ).length; - }); - - // ID filter and find - if ( support.getById ) { - Expr.filter["ID"] = function( id ) { - var attrId = id.replace( runescape, funescape ); - return function( elem ) { - return elem.getAttribute("id") === attrId; - }; - }; - Expr.find["ID"] = function( id, context ) { - if ( typeof context.getElementById !== "undefined" && documentIsHTML ) { - var elem = context.getElementById( id ); - return elem ? [ elem ] : []; - } - }; - } else { - Expr.filter["ID"] = function( id ) { - var attrId = id.replace( runescape, funescape ); - return function( elem ) { - var node = typeof elem.getAttributeNode !== "undefined" && - elem.getAttributeNode("id"); - return node && node.value === attrId; - }; - }; - - // Support: IE 6 - 7 only - // getElementById is not reliable as a find shortcut - Expr.find["ID"] = function( id, context ) { - if ( typeof context.getElementById !== "undefined" && documentIsHTML ) { - var node, i, elems, - elem = context.getElementById( id ); - - if ( elem ) { - - // Verify the id attribute - node = elem.getAttributeNode("id"); - if ( node && node.value === id ) { - return [ elem ]; - } - - // Fall back on getElementsByName - elems = context.getElementsByName( id ); - i = 0; - while ( (elem = elems[i++]) ) { - node = elem.getAttributeNode("id"); - if ( node && node.value === id ) { - return [ elem ]; - } - } - } - - return []; - } - }; - } - - // Tag - Expr.find["TAG"] = support.getElementsByTagName ? - function( tag, context ) { - if ( typeof context.getElementsByTagName !== "undefined" ) { - return context.getElementsByTagName( tag ); - - // DocumentFragment nodes don't have gEBTN - } else if ( support.qsa ) { - return context.querySelectorAll( tag ); - } - } : - - function( tag, context ) { - var elem, - tmp = [], - i = 0, - // By happy coincidence, a (broken) gEBTN appears on DocumentFragment nodes too - results = context.getElementsByTagName( tag ); - - // Filter out possible comments - if ( tag === "*" ) { - while ( (elem = results[i++]) ) { - if ( elem.nodeType === 1 ) { - tmp.push( elem ); - } - } - - return tmp; - } - return results; - }; - - // Class - Expr.find["CLASS"] = support.getElementsByClassName && function( className, context ) { - if ( typeof context.getElementsByClassName !== "undefined" && documentIsHTML ) { - return context.getElementsByClassName( className ); - } - }; - - /* QSA/matchesSelector - ---------------------------------------------------------------------- */ - - // QSA and matchesSelector support - - // matchesSelector(:active) reports false when true (IE9/Opera 11.5) - rbuggyMatches = []; - - // qSa(:focus) reports false when true (Chrome 21) - // We allow this because of a bug in IE8/9 that throws an error - // whenever `document.activeElement` is accessed on an iframe - // So, we allow :focus to pass through QSA all the time to avoid the IE error - // See https://bugs.jquery.com/ticket/13378 - rbuggyQSA = []; - - if ( (support.qsa = rnative.test( document.querySelectorAll )) ) { - // Build QSA regex - // Regex strategy adopted from Diego Perini - assert(function( el ) { - // Select is set to empty string on purpose - // This is to test IE's treatment of not explicitly - // setting a boolean content attribute, - // since its presence should be enough - // https://bugs.jquery.com/ticket/12359 - docElem.appendChild( el ).innerHTML = "" + - ""; - - // Support: IE8, Opera 11-12.16 - // Nothing should be selected when empty strings follow ^= or $= or *= - // The test attribute must be unknown in Opera but "safe" for WinRT - // https://msdn.microsoft.com/en-us/library/ie/hh465388.aspx#attribute_section - if ( el.querySelectorAll("[msallowcapture^='']").length ) { - rbuggyQSA.push( "[*^$]=" + whitespace + "*(?:''|\"\")" ); - } - - // Support: IE8 - // Boolean attributes and "value" are not treated correctly - if ( !el.querySelectorAll("[selected]").length ) { - rbuggyQSA.push( "\\[" + whitespace + "*(?:value|" + booleans + ")" ); - } - - // Support: Chrome<29, Android<4.4, Safari<7.0+, iOS<7.0+, PhantomJS<1.9.8+ - if ( !el.querySelectorAll( "[id~=" + expando + "-]" ).length ) { - rbuggyQSA.push("~="); - } - - // Webkit/Opera - :checked should return selected option elements - // http://www.w3.org/TR/2011/REC-css3-selectors-20110929/#checked - // IE8 throws error here and will not see later tests - if ( !el.querySelectorAll(":checked").length ) { - rbuggyQSA.push(":checked"); - } - - // Support: Safari 8+, iOS 8+ - // https://bugs.webkit.org/show_bug.cgi?id=136851 - // In-page `selector#id sibling-combinator selector` fails - if ( !el.querySelectorAll( "a#" + expando + "+*" ).length ) { - rbuggyQSA.push(".#.+[+~]"); - } - }); - - assert(function( el ) { - el.innerHTML = "" + - ""; - - // Support: Windows 8 Native Apps - // The type and name attributes are restricted during .innerHTML assignment - var input = document.createElement("input"); - input.setAttribute( "type", "hidden" ); - el.appendChild( input ).setAttribute( "name", "D" ); - - // Support: IE8 - // Enforce case-sensitivity of name attribute - if ( el.querySelectorAll("[name=d]").length ) { - rbuggyQSA.push( "name" + whitespace + "*[*^$|!~]?=" ); - } - - // FF 3.5 - :enabled/:disabled and hidden elements (hidden elements are still enabled) - // IE8 throws error here and will not see later tests - if ( el.querySelectorAll(":enabled").length !== 2 ) { - rbuggyQSA.push( ":enabled", ":disabled" ); - } - - // Support: IE9-11+ - // IE's :disabled selector does not pick up the children of disabled fieldsets - docElem.appendChild( el ).disabled = true; - if ( el.querySelectorAll(":disabled").length !== 2 ) { - rbuggyQSA.push( ":enabled", ":disabled" ); - } - - // Opera 10-11 does not throw on post-comma invalid pseudos - el.querySelectorAll("*,:x"); - rbuggyQSA.push(",.*:"); - }); - } - - if ( (support.matchesSelector = rnative.test( (matches = docElem.matches || - docElem.webkitMatchesSelector || - docElem.mozMatchesSelector || - docElem.oMatchesSelector || - docElem.msMatchesSelector) )) ) { - - assert(function( el ) { - // Check to see if it's possible to do matchesSelector - // on a disconnected node (IE 9) - support.disconnectedMatch = matches.call( el, "*" ); - - // This should fail with an exception - // Gecko does not error, returns false instead - matches.call( el, "[s!='']:x" ); - rbuggyMatches.push( "!=", pseudos ); - }); - } - - rbuggyQSA = rbuggyQSA.length && new RegExp( rbuggyQSA.join("|") ); - rbuggyMatches = rbuggyMatches.length && new RegExp( rbuggyMatches.join("|") ); - - /* Contains - ---------------------------------------------------------------------- */ - hasCompare = rnative.test( docElem.compareDocumentPosition ); - - // Element contains another - // Purposefully self-exclusive - // As in, an element does not contain itself - contains = hasCompare || rnative.test( docElem.contains ) ? - function( a, b ) { - var adown = a.nodeType === 9 ? a.documentElement : a, - bup = b && b.parentNode; - return a === bup || !!( bup && bup.nodeType === 1 && ( - adown.contains ? - adown.contains( bup ) : - a.compareDocumentPosition && a.compareDocumentPosition( bup ) & 16 - )); - } : - function( a, b ) { - if ( b ) { - while ( (b = b.parentNode) ) { - if ( b === a ) { - return true; - } - } - } - return false; - }; - - /* Sorting - ---------------------------------------------------------------------- */ - - // Document order sorting - sortOrder = hasCompare ? - function( a, b ) { - - // Flag for duplicate removal - if ( a === b ) { - hasDuplicate = true; - return 0; - } - - // Sort on method existence if only one input has compareDocumentPosition - var compare = !a.compareDocumentPosition - !b.compareDocumentPosition; - if ( compare ) { - return compare; - } - - // Calculate position if both inputs belong to the same document - compare = ( a.ownerDocument || a ) === ( b.ownerDocument || b ) ? - a.compareDocumentPosition( b ) : - - // Otherwise we know they are disconnected - 1; - - // Disconnected nodes - if ( compare & 1 || - (!support.sortDetached && b.compareDocumentPosition( a ) === compare) ) { - - // Choose the first element that is related to our preferred document - if ( a === document || a.ownerDocument === preferredDoc && contains(preferredDoc, a) ) { - return -1; - } - if ( b === document || b.ownerDocument === preferredDoc && contains(preferredDoc, b) ) { - return 1; - } - - // Maintain original order - return sortInput ? - ( indexOf( sortInput, a ) - indexOf( sortInput, b ) ) : - 0; - } - - return compare & 4 ? -1 : 1; - } : - function( a, b ) { - // Exit early if the nodes are identical - if ( a === b ) { - hasDuplicate = true; - return 0; - } - - var cur, - i = 0, - aup = a.parentNode, - bup = b.parentNode, - ap = [ a ], - bp = [ b ]; - - // Parentless nodes are either documents or disconnected - if ( !aup || !bup ) { - return a === document ? -1 : - b === document ? 1 : - aup ? -1 : - bup ? 1 : - sortInput ? - ( indexOf( sortInput, a ) - indexOf( sortInput, b ) ) : - 0; - - // If the nodes are siblings, we can do a quick check - } else if ( aup === bup ) { - return siblingCheck( a, b ); - } - - // Otherwise we need full lists of their ancestors for comparison - cur = a; - while ( (cur = cur.parentNode) ) { - ap.unshift( cur ); - } - cur = b; - while ( (cur = cur.parentNode) ) { - bp.unshift( cur ); - } - - // Walk down the tree looking for a discrepancy - while ( ap[i] === bp[i] ) { - i++; - } - - return i ? - // Do a sibling check if the nodes have a common ancestor - siblingCheck( ap[i], bp[i] ) : - - // Otherwise nodes in our document sort first - ap[i] === preferredDoc ? -1 : - bp[i] === preferredDoc ? 1 : - 0; - }; - - return document; -}; - -Sizzle.matches = function( expr, elements ) { - return Sizzle( expr, null, null, elements ); -}; - -Sizzle.matchesSelector = function( elem, expr ) { - // Set document vars if needed - if ( ( elem.ownerDocument || elem ) !== document ) { - setDocument( elem ); - } - - // Make sure that attribute selectors are quoted - expr = expr.replace( rattributeQuotes, "='$1']" ); - - if ( support.matchesSelector && documentIsHTML && - !compilerCache[ expr + " " ] && - ( !rbuggyMatches || !rbuggyMatches.test( expr ) ) && - ( !rbuggyQSA || !rbuggyQSA.test( expr ) ) ) { - - try { - var ret = matches.call( elem, expr ); - - // IE 9's matchesSelector returns false on disconnected nodes - if ( ret || support.disconnectedMatch || - // As well, disconnected nodes are said to be in a document - // fragment in IE 9 - elem.document && elem.document.nodeType !== 11 ) { - return ret; - } - } catch (e) {} - } - - return Sizzle( expr, document, null, [ elem ] ).length > 0; -}; - -Sizzle.contains = function( context, elem ) { - // Set document vars if needed - if ( ( context.ownerDocument || context ) !== document ) { - setDocument( context ); - } - return contains( context, elem ); -}; - -Sizzle.attr = function( elem, name ) { - // Set document vars if needed - if ( ( elem.ownerDocument || elem ) !== document ) { - setDocument( elem ); - } - - var fn = Expr.attrHandle[ name.toLowerCase() ], - // Don't get fooled by Object.prototype properties (jQuery #13807) - val = fn && hasOwn.call( Expr.attrHandle, name.toLowerCase() ) ? - fn( elem, name, !documentIsHTML ) : - undefined; - - return val !== undefined ? - val : - support.attributes || !documentIsHTML ? - elem.getAttribute( name ) : - (val = elem.getAttributeNode(name)) && val.specified ? - val.value : - null; -}; - -Sizzle.escape = function( sel ) { - return (sel + "").replace( rcssescape, fcssescape ); -}; - -Sizzle.error = function( msg ) { - throw new Error( "Syntax error, unrecognized expression: " + msg ); -}; - -/** - * Document sorting and removing duplicates - * @param {ArrayLike} results - */ -Sizzle.uniqueSort = function( results ) { - var elem, - duplicates = [], - j = 0, - i = 0; - - // Unless we *know* we can detect duplicates, assume their presence - hasDuplicate = !support.detectDuplicates; - sortInput = !support.sortStable && results.slice( 0 ); - results.sort( sortOrder ); - - if ( hasDuplicate ) { - while ( (elem = results[i++]) ) { - if ( elem === results[ i ] ) { - j = duplicates.push( i ); - } - } - while ( j-- ) { - results.splice( duplicates[ j ], 1 ); - } - } - - // Clear input after sorting to release objects - // See https://github.com/jquery/sizzle/pull/225 - sortInput = null; - - return results; -}; - -/** - * Utility function for retrieving the text value of an array of DOM nodes - * @param {Array|Element} elem - */ -getText = Sizzle.getText = function( elem ) { - var node, - ret = "", - i = 0, - nodeType = elem.nodeType; - - if ( !nodeType ) { - // If no nodeType, this is expected to be an array - while ( (node = elem[i++]) ) { - // Do not traverse comment nodes - ret += getText( node ); - } - } else if ( nodeType === 1 || nodeType === 9 || nodeType === 11 ) { - // Use textContent for elements - // innerText usage removed for consistency of new lines (jQuery #11153) - if ( typeof elem.textContent === "string" ) { - return elem.textContent; - } else { - // Traverse its children - for ( elem = elem.firstChild; elem; elem = elem.nextSibling ) { - ret += getText( elem ); - } - } - } else if ( nodeType === 3 || nodeType === 4 ) { - return elem.nodeValue; - } - // Do not include comment or processing instruction nodes - - return ret; -}; - -Expr = Sizzle.selectors = { - - // Can be adjusted by the user - cacheLength: 50, - - createPseudo: markFunction, - - match: matchExpr, - - attrHandle: {}, - - find: {}, - - relative: { - ">": { dir: "parentNode", first: true }, - " ": { dir: "parentNode" }, - "+": { dir: "previousSibling", first: true }, - "~": { dir: "previousSibling" } - }, - - preFilter: { - "ATTR": function( match ) { - match[1] = match[1].replace( runescape, funescape ); - - // Move the given value to match[3] whether quoted or unquoted - match[3] = ( match[3] || match[4] || match[5] || "" ).replace( runescape, funescape ); - - if ( match[2] === "~=" ) { - match[3] = " " + match[3] + " "; - } - - return match.slice( 0, 4 ); - }, - - "CHILD": function( match ) { - /* matches from matchExpr["CHILD"] - 1 type (only|nth|...) - 2 what (child|of-type) - 3 argument (even|odd|\d*|\d*n([+-]\d+)?|...) - 4 xn-component of xn+y argument ([+-]?\d*n|) - 5 sign of xn-component - 6 x of xn-component - 7 sign of y-component - 8 y of y-component - */ - match[1] = match[1].toLowerCase(); - - if ( match[1].slice( 0, 3 ) === "nth" ) { - // nth-* requires argument - if ( !match[3] ) { - Sizzle.error( match[0] ); - } - - // numeric x and y parameters for Expr.filter.CHILD - // remember that false/true cast respectively to 0/1 - match[4] = +( match[4] ? match[5] + (match[6] || 1) : 2 * ( match[3] === "even" || match[3] === "odd" ) ); - match[5] = +( ( match[7] + match[8] ) || match[3] === "odd" ); - - // other types prohibit arguments - } else if ( match[3] ) { - Sizzle.error( match[0] ); - } - - return match; - }, - - "PSEUDO": function( match ) { - var excess, - unquoted = !match[6] && match[2]; - - if ( matchExpr["CHILD"].test( match[0] ) ) { - return null; - } - - // Accept quoted arguments as-is - if ( match[3] ) { - match[2] = match[4] || match[5] || ""; - - // Strip excess characters from unquoted arguments - } else if ( unquoted && rpseudo.test( unquoted ) && - // Get excess from tokenize (recursively) - (excess = tokenize( unquoted, true )) && - // advance to the next closing parenthesis - (excess = unquoted.indexOf( ")", unquoted.length - excess ) - unquoted.length) ) { - - // excess is a negative index - match[0] = match[0].slice( 0, excess ); - match[2] = unquoted.slice( 0, excess ); - } - - // Return only captures needed by the pseudo filter method (type and argument) - return match.slice( 0, 3 ); - } - }, - - filter: { - - "TAG": function( nodeNameSelector ) { - var nodeName = nodeNameSelector.replace( runescape, funescape ).toLowerCase(); - return nodeNameSelector === "*" ? - function() { return true; } : - function( elem ) { - return elem.nodeName && elem.nodeName.toLowerCase() === nodeName; - }; - }, - - "CLASS": function( className ) { - var pattern = classCache[ className + " " ]; - - return pattern || - (pattern = new RegExp( "(^|" + whitespace + ")" + className + "(" + whitespace + "|$)" )) && - classCache( className, function( elem ) { - return pattern.test( typeof elem.className === "string" && elem.className || typeof elem.getAttribute !== "undefined" && elem.getAttribute("class") || "" ); - }); - }, - - "ATTR": function( name, operator, check ) { - return function( elem ) { - var result = Sizzle.attr( elem, name ); - - if ( result == null ) { - return operator === "!="; - } - if ( !operator ) { - return true; - } - - result += ""; - - return operator === "=" ? result === check : - operator === "!=" ? result !== check : - operator === "^=" ? check && result.indexOf( check ) === 0 : - operator === "*=" ? check && result.indexOf( check ) > -1 : - operator === "$=" ? check && result.slice( -check.length ) === check : - operator === "~=" ? ( " " + result.replace( rwhitespace, " " ) + " " ).indexOf( check ) > -1 : - operator === "|=" ? result === check || result.slice( 0, check.length + 1 ) === check + "-" : - false; - }; - }, - - "CHILD": function( type, what, argument, first, last ) { - var simple = type.slice( 0, 3 ) !== "nth", - forward = type.slice( -4 ) !== "last", - ofType = what === "of-type"; - - return first === 1 && last === 0 ? - - // Shortcut for :nth-*(n) - function( elem ) { - return !!elem.parentNode; - } : - - function( elem, context, xml ) { - var cache, uniqueCache, outerCache, node, nodeIndex, start, - dir = simple !== forward ? "nextSibling" : "previousSibling", - parent = elem.parentNode, - name = ofType && elem.nodeName.toLowerCase(), - useCache = !xml && !ofType, - diff = false; - - if ( parent ) { - - // :(first|last|only)-(child|of-type) - if ( simple ) { - while ( dir ) { - node = elem; - while ( (node = node[ dir ]) ) { - if ( ofType ? - node.nodeName.toLowerCase() === name : - node.nodeType === 1 ) { - - return false; - } - } - // Reverse direction for :only-* (if we haven't yet done so) - start = dir = type === "only" && !start && "nextSibling"; - } - return true; - } - - start = [ forward ? parent.firstChild : parent.lastChild ]; - - // non-xml :nth-child(...) stores cache data on `parent` - if ( forward && useCache ) { - - // Seek `elem` from a previously-cached index - - // ...in a gzip-friendly way - node = parent; - outerCache = node[ expando ] || (node[ expando ] = {}); - - // Support: IE <9 only - // Defend against cloned attroperties (jQuery gh-1709) - uniqueCache = outerCache[ node.uniqueID ] || - (outerCache[ node.uniqueID ] = {}); - - cache = uniqueCache[ type ] || []; - nodeIndex = cache[ 0 ] === dirruns && cache[ 1 ]; - diff = nodeIndex && cache[ 2 ]; - node = nodeIndex && parent.childNodes[ nodeIndex ]; - - while ( (node = ++nodeIndex && node && node[ dir ] || - - // Fallback to seeking `elem` from the start - (diff = nodeIndex = 0) || start.pop()) ) { - - // When found, cache indexes on `parent` and break - if ( node.nodeType === 1 && ++diff && node === elem ) { - uniqueCache[ type ] = [ dirruns, nodeIndex, diff ]; - break; - } - } - - } else { - // Use previously-cached element index if available - if ( useCache ) { - // ...in a gzip-friendly way - node = elem; - outerCache = node[ expando ] || (node[ expando ] = {}); - - // Support: IE <9 only - // Defend against cloned attroperties (jQuery gh-1709) - uniqueCache = outerCache[ node.uniqueID ] || - (outerCache[ node.uniqueID ] = {}); - - cache = uniqueCache[ type ] || []; - nodeIndex = cache[ 0 ] === dirruns && cache[ 1 ]; - diff = nodeIndex; - } - - // xml :nth-child(...) - // or :nth-last-child(...) or :nth(-last)?-of-type(...) - if ( diff === false ) { - // Use the same loop as above to seek `elem` from the start - while ( (node = ++nodeIndex && node && node[ dir ] || - (diff = nodeIndex = 0) || start.pop()) ) { - - if ( ( ofType ? - node.nodeName.toLowerCase() === name : - node.nodeType === 1 ) && - ++diff ) { - - // Cache the index of each encountered element - if ( useCache ) { - outerCache = node[ expando ] || (node[ expando ] = {}); - - // Support: IE <9 only - // Defend against cloned attroperties (jQuery gh-1709) - uniqueCache = outerCache[ node.uniqueID ] || - (outerCache[ node.uniqueID ] = {}); - - uniqueCache[ type ] = [ dirruns, diff ]; - } - - if ( node === elem ) { - break; - } - } - } - } - } - - // Incorporate the offset, then check against cycle size - diff -= last; - return diff === first || ( diff % first === 0 && diff / first >= 0 ); - } - }; - }, - - "PSEUDO": function( pseudo, argument ) { - // pseudo-class names are case-insensitive - // http://www.w3.org/TR/selectors/#pseudo-classes - // Prioritize by case sensitivity in case custom pseudos are added with uppercase letters - // Remember that setFilters inherits from pseudos - var args, - fn = Expr.pseudos[ pseudo ] || Expr.setFilters[ pseudo.toLowerCase() ] || - Sizzle.error( "unsupported pseudo: " + pseudo ); - - // The user may use createPseudo to indicate that - // arguments are needed to create the filter function - // just as Sizzle does - if ( fn[ expando ] ) { - return fn( argument ); - } - - // But maintain support for old signatures - if ( fn.length > 1 ) { - args = [ pseudo, pseudo, "", argument ]; - return Expr.setFilters.hasOwnProperty( pseudo.toLowerCase() ) ? - markFunction(function( seed, matches ) { - var idx, - matched = fn( seed, argument ), - i = matched.length; - while ( i-- ) { - idx = indexOf( seed, matched[i] ); - seed[ idx ] = !( matches[ idx ] = matched[i] ); - } - }) : - function( elem ) { - return fn( elem, 0, args ); - }; - } - - return fn; - } - }, - - pseudos: { - // Potentially complex pseudos - "not": markFunction(function( selector ) { - // Trim the selector passed to compile - // to avoid treating leading and trailing - // spaces as combinators - var input = [], - results = [], - matcher = compile( selector.replace( rtrim, "$1" ) ); - - return matcher[ expando ] ? - markFunction(function( seed, matches, context, xml ) { - var elem, - unmatched = matcher( seed, null, xml, [] ), - i = seed.length; - - // Match elements unmatched by `matcher` - while ( i-- ) { - if ( (elem = unmatched[i]) ) { - seed[i] = !(matches[i] = elem); - } - } - }) : - function( elem, context, xml ) { - input[0] = elem; - matcher( input, null, xml, results ); - // Don't keep the element (issue #299) - input[0] = null; - return !results.pop(); - }; - }), - - "has": markFunction(function( selector ) { - return function( elem ) { - return Sizzle( selector, elem ).length > 0; - }; - }), - - "contains": markFunction(function( text ) { - text = text.replace( runescape, funescape ); - return function( elem ) { - return ( elem.textContent || elem.innerText || getText( elem ) ).indexOf( text ) > -1; - }; - }), - - // "Whether an element is represented by a :lang() selector - // is based solely on the element's language value - // being equal to the identifier C, - // or beginning with the identifier C immediately followed by "-". - // The matching of C against the element's language value is performed case-insensitively. - // The identifier C does not have to be a valid language name." - // http://www.w3.org/TR/selectors/#lang-pseudo - "lang": markFunction( function( lang ) { - // lang value must be a valid identifier - if ( !ridentifier.test(lang || "") ) { - Sizzle.error( "unsupported lang: " + lang ); - } - lang = lang.replace( runescape, funescape ).toLowerCase(); - return function( elem ) { - var elemLang; - do { - if ( (elemLang = documentIsHTML ? - elem.lang : - elem.getAttribute("xml:lang") || elem.getAttribute("lang")) ) { - - elemLang = elemLang.toLowerCase(); - return elemLang === lang || elemLang.indexOf( lang + "-" ) === 0; - } - } while ( (elem = elem.parentNode) && elem.nodeType === 1 ); - return false; - }; - }), - - // Miscellaneous - "target": function( elem ) { - var hash = window.location && window.location.hash; - return hash && hash.slice( 1 ) === elem.id; - }, - - "root": function( elem ) { - return elem === docElem; - }, - - "focus": function( elem ) { - return elem === document.activeElement && (!document.hasFocus || document.hasFocus()) && !!(elem.type || elem.href || ~elem.tabIndex); - }, - - // Boolean properties - "enabled": createDisabledPseudo( false ), - "disabled": createDisabledPseudo( true ), - - "checked": function( elem ) { - // In CSS3, :checked should return both checked and selected elements - // http://www.w3.org/TR/2011/REC-css3-selectors-20110929/#checked - var nodeName = elem.nodeName.toLowerCase(); - return (nodeName === "input" && !!elem.checked) || (nodeName === "option" && !!elem.selected); - }, - - "selected": function( elem ) { - // Accessing this property makes selected-by-default - // options in Safari work properly - if ( elem.parentNode ) { - elem.parentNode.selectedIndex; - } - - return elem.selected === true; - }, - - // Contents - "empty": function( elem ) { - // http://www.w3.org/TR/selectors/#empty-pseudo - // :empty is negated by element (1) or content nodes (text: 3; cdata: 4; entity ref: 5), - // but not by others (comment: 8; processing instruction: 7; etc.) - // nodeType < 6 works because attributes (2) do not appear as children - for ( elem = elem.firstChild; elem; elem = elem.nextSibling ) { - if ( elem.nodeType < 6 ) { - return false; - } - } - return true; - }, - - "parent": function( elem ) { - return !Expr.pseudos["empty"]( elem ); - }, - - // Element/input types - "header": function( elem ) { - return rheader.test( elem.nodeName ); - }, - - "input": function( elem ) { - return rinputs.test( elem.nodeName ); - }, - - "button": function( elem ) { - var name = elem.nodeName.toLowerCase(); - return name === "input" && elem.type === "button" || name === "button"; - }, - - "text": function( elem ) { - var attr; - return elem.nodeName.toLowerCase() === "input" && - elem.type === "text" && - - // Support: IE<8 - // New HTML5 attribute values (e.g., "search") appear with elem.type === "text" - ( (attr = elem.getAttribute("type")) == null || attr.toLowerCase() === "text" ); - }, - - // Position-in-collection - "first": createPositionalPseudo(function() { - return [ 0 ]; - }), - - "last": createPositionalPseudo(function( matchIndexes, length ) { - return [ length - 1 ]; - }), - - "eq": createPositionalPseudo(function( matchIndexes, length, argument ) { - return [ argument < 0 ? argument + length : argument ]; - }), - - "even": createPositionalPseudo(function( matchIndexes, length ) { - var i = 0; - for ( ; i < length; i += 2 ) { - matchIndexes.push( i ); - } - return matchIndexes; - }), - - "odd": createPositionalPseudo(function( matchIndexes, length ) { - var i = 1; - for ( ; i < length; i += 2 ) { - matchIndexes.push( i ); - } - return matchIndexes; - }), - - "lt": createPositionalPseudo(function( matchIndexes, length, argument ) { - var i = argument < 0 ? argument + length : argument; - for ( ; --i >= 0; ) { - matchIndexes.push( i ); - } - return matchIndexes; - }), - - "gt": createPositionalPseudo(function( matchIndexes, length, argument ) { - var i = argument < 0 ? argument + length : argument; - for ( ; ++i < length; ) { - matchIndexes.push( i ); - } - return matchIndexes; - }) - } -}; - -Expr.pseudos["nth"] = Expr.pseudos["eq"]; - -// Add button/input type pseudos -for ( i in { radio: true, checkbox: true, file: true, password: true, image: true } ) { - Expr.pseudos[ i ] = createInputPseudo( i ); -} -for ( i in { submit: true, reset: true } ) { - Expr.pseudos[ i ] = createButtonPseudo( i ); -} - -// Easy API for creating new setFilters -function setFilters() {} -setFilters.prototype = Expr.filters = Expr.pseudos; -Expr.setFilters = new setFilters(); - -tokenize = Sizzle.tokenize = function( selector, parseOnly ) { - var matched, match, tokens, type, - soFar, groups, preFilters, - cached = tokenCache[ selector + " " ]; - - if ( cached ) { - return parseOnly ? 0 : cached.slice( 0 ); - } - - soFar = selector; - groups = []; - preFilters = Expr.preFilter; - - while ( soFar ) { - - // Comma and first run - if ( !matched || (match = rcomma.exec( soFar )) ) { - if ( match ) { - // Don't consume trailing commas as valid - soFar = soFar.slice( match[0].length ) || soFar; - } - groups.push( (tokens = []) ); - } - - matched = false; - - // Combinators - if ( (match = rcombinators.exec( soFar )) ) { - matched = match.shift(); - tokens.push({ - value: matched, - // Cast descendant combinators to space - type: match[0].replace( rtrim, " " ) - }); - soFar = soFar.slice( matched.length ); - } - - // Filters - for ( type in Expr.filter ) { - if ( (match = matchExpr[ type ].exec( soFar )) && (!preFilters[ type ] || - (match = preFilters[ type ]( match ))) ) { - matched = match.shift(); - tokens.push({ - value: matched, - type: type, - matches: match - }); - soFar = soFar.slice( matched.length ); - } - } - - if ( !matched ) { - break; - } - } - - // Return the length of the invalid excess - // if we're just parsing - // Otherwise, throw an error or return tokens - return parseOnly ? - soFar.length : - soFar ? - Sizzle.error( selector ) : - // Cache the tokens - tokenCache( selector, groups ).slice( 0 ); -}; - -function toSelector( tokens ) { - var i = 0, - len = tokens.length, - selector = ""; - for ( ; i < len; i++ ) { - selector += tokens[i].value; - } - return selector; -} - -function addCombinator( matcher, combinator, base ) { - var dir = combinator.dir, - skip = combinator.next, - key = skip || dir, - checkNonElements = base && key === "parentNode", - doneName = done++; - - return combinator.first ? - // Check against closest ancestor/preceding element - function( elem, context, xml ) { - while ( (elem = elem[ dir ]) ) { - if ( elem.nodeType === 1 || checkNonElements ) { - return matcher( elem, context, xml ); - } - } - return false; - } : - - // Check against all ancestor/preceding elements - function( elem, context, xml ) { - var oldCache, uniqueCache, outerCache, - newCache = [ dirruns, doneName ]; - - // We can't set arbitrary data on XML nodes, so they don't benefit from combinator caching - if ( xml ) { - while ( (elem = elem[ dir ]) ) { - if ( elem.nodeType === 1 || checkNonElements ) { - if ( matcher( elem, context, xml ) ) { - return true; - } - } - } - } else { - while ( (elem = elem[ dir ]) ) { - if ( elem.nodeType === 1 || checkNonElements ) { - outerCache = elem[ expando ] || (elem[ expando ] = {}); - - // Support: IE <9 only - // Defend against cloned attroperties (jQuery gh-1709) - uniqueCache = outerCache[ elem.uniqueID ] || (outerCache[ elem.uniqueID ] = {}); - - if ( skip && skip === elem.nodeName.toLowerCase() ) { - elem = elem[ dir ] || elem; - } else if ( (oldCache = uniqueCache[ key ]) && - oldCache[ 0 ] === dirruns && oldCache[ 1 ] === doneName ) { - - // Assign to newCache so results back-propagate to previous elements - return (newCache[ 2 ] = oldCache[ 2 ]); - } else { - // Reuse newcache so results back-propagate to previous elements - uniqueCache[ key ] = newCache; - - // A match means we're done; a fail means we have to keep checking - if ( (newCache[ 2 ] = matcher( elem, context, xml )) ) { - return true; - } - } - } - } - } - return false; - }; -} - -function elementMatcher( matchers ) { - return matchers.length > 1 ? - function( elem, context, xml ) { - var i = matchers.length; - while ( i-- ) { - if ( !matchers[i]( elem, context, xml ) ) { - return false; - } - } - return true; - } : - matchers[0]; -} - -function multipleContexts( selector, contexts, results ) { - var i = 0, - len = contexts.length; - for ( ; i < len; i++ ) { - Sizzle( selector, contexts[i], results ); - } - return results; -} - -function condense( unmatched, map, filter, context, xml ) { - var elem, - newUnmatched = [], - i = 0, - len = unmatched.length, - mapped = map != null; - - for ( ; i < len; i++ ) { - if ( (elem = unmatched[i]) ) { - if ( !filter || filter( elem, context, xml ) ) { - newUnmatched.push( elem ); - if ( mapped ) { - map.push( i ); - } - } - } - } - - return newUnmatched; -} - -function setMatcher( preFilter, selector, matcher, postFilter, postFinder, postSelector ) { - if ( postFilter && !postFilter[ expando ] ) { - postFilter = setMatcher( postFilter ); - } - if ( postFinder && !postFinder[ expando ] ) { - postFinder = setMatcher( postFinder, postSelector ); - } - return markFunction(function( seed, results, context, xml ) { - var temp, i, elem, - preMap = [], - postMap = [], - preexisting = results.length, - - // Get initial elements from seed or context - elems = seed || multipleContexts( selector || "*", context.nodeType ? [ context ] : context, [] ), - - // Prefilter to get matcher input, preserving a map for seed-results synchronization - matcherIn = preFilter && ( seed || !selector ) ? - condense( elems, preMap, preFilter, context, xml ) : - elems, - - matcherOut = matcher ? - // If we have a postFinder, or filtered seed, or non-seed postFilter or preexisting results, - postFinder || ( seed ? preFilter : preexisting || postFilter ) ? - - // ...intermediate processing is necessary - [] : - - // ...otherwise use results directly - results : - matcherIn; - - // Find primary matches - if ( matcher ) { - matcher( matcherIn, matcherOut, context, xml ); - } - - // Apply postFilter - if ( postFilter ) { - temp = condense( matcherOut, postMap ); - postFilter( temp, [], context, xml ); - - // Un-match failing elements by moving them back to matcherIn - i = temp.length; - while ( i-- ) { - if ( (elem = temp[i]) ) { - matcherOut[ postMap[i] ] = !(matcherIn[ postMap[i] ] = elem); - } - } - } - - if ( seed ) { - if ( postFinder || preFilter ) { - if ( postFinder ) { - // Get the final matcherOut by condensing this intermediate into postFinder contexts - temp = []; - i = matcherOut.length; - while ( i-- ) { - if ( (elem = matcherOut[i]) ) { - // Restore matcherIn since elem is not yet a final match - temp.push( (matcherIn[i] = elem) ); - } - } - postFinder( null, (matcherOut = []), temp, xml ); - } - - // Move matched elements from seed to results to keep them synchronized - i = matcherOut.length; - while ( i-- ) { - if ( (elem = matcherOut[i]) && - (temp = postFinder ? indexOf( seed, elem ) : preMap[i]) > -1 ) { - - seed[temp] = !(results[temp] = elem); - } - } - } - - // Add elements to results, through postFinder if defined - } else { - matcherOut = condense( - matcherOut === results ? - matcherOut.splice( preexisting, matcherOut.length ) : - matcherOut - ); - if ( postFinder ) { - postFinder( null, results, matcherOut, xml ); - } else { - push.apply( results, matcherOut ); - } - } - }); -} - -function matcherFromTokens( tokens ) { - var checkContext, matcher, j, - len = tokens.length, - leadingRelative = Expr.relative[ tokens[0].type ], - implicitRelative = leadingRelative || Expr.relative[" "], - i = leadingRelative ? 1 : 0, - - // The foundational matcher ensures that elements are reachable from top-level context(s) - matchContext = addCombinator( function( elem ) { - return elem === checkContext; - }, implicitRelative, true ), - matchAnyContext = addCombinator( function( elem ) { - return indexOf( checkContext, elem ) > -1; - }, implicitRelative, true ), - matchers = [ function( elem, context, xml ) { - var ret = ( !leadingRelative && ( xml || context !== outermostContext ) ) || ( - (checkContext = context).nodeType ? - matchContext( elem, context, xml ) : - matchAnyContext( elem, context, xml ) ); - // Avoid hanging onto element (issue #299) - checkContext = null; - return ret; - } ]; - - for ( ; i < len; i++ ) { - if ( (matcher = Expr.relative[ tokens[i].type ]) ) { - matchers = [ addCombinator(elementMatcher( matchers ), matcher) ]; - } else { - matcher = Expr.filter[ tokens[i].type ].apply( null, tokens[i].matches ); - - // Return special upon seeing a positional matcher - if ( matcher[ expando ] ) { - // Find the next relative operator (if any) for proper handling - j = ++i; - for ( ; j < len; j++ ) { - if ( Expr.relative[ tokens[j].type ] ) { - break; - } - } - return setMatcher( - i > 1 && elementMatcher( matchers ), - i > 1 && toSelector( - // If the preceding token was a descendant combinator, insert an implicit any-element `*` - tokens.slice( 0, i - 1 ).concat({ value: tokens[ i - 2 ].type === " " ? "*" : "" }) - ).replace( rtrim, "$1" ), - matcher, - i < j && matcherFromTokens( tokens.slice( i, j ) ), - j < len && matcherFromTokens( (tokens = tokens.slice( j )) ), - j < len && toSelector( tokens ) - ); - } - matchers.push( matcher ); - } - } - - return elementMatcher( matchers ); -} - -function matcherFromGroupMatchers( elementMatchers, setMatchers ) { - var bySet = setMatchers.length > 0, - byElement = elementMatchers.length > 0, - superMatcher = function( seed, context, xml, results, outermost ) { - var elem, j, matcher, - matchedCount = 0, - i = "0", - unmatched = seed && [], - setMatched = [], - contextBackup = outermostContext, - // We must always have either seed elements or outermost context - elems = seed || byElement && Expr.find["TAG"]( "*", outermost ), - // Use integer dirruns iff this is the outermost matcher - dirrunsUnique = (dirruns += contextBackup == null ? 1 : Math.random() || 0.1), - len = elems.length; - - if ( outermost ) { - outermostContext = context === document || context || outermost; - } - - // Add elements passing elementMatchers directly to results - // Support: IE<9, Safari - // Tolerate NodeList properties (IE: "length"; Safari: ) matching elements by id - for ( ; i !== len && (elem = elems[i]) != null; i++ ) { - if ( byElement && elem ) { - j = 0; - if ( !context && elem.ownerDocument !== document ) { - setDocument( elem ); - xml = !documentIsHTML; - } - while ( (matcher = elementMatchers[j++]) ) { - if ( matcher( elem, context || document, xml) ) { - results.push( elem ); - break; - } - } - if ( outermost ) { - dirruns = dirrunsUnique; - } - } - - // Track unmatched elements for set filters - if ( bySet ) { - // They will have gone through all possible matchers - if ( (elem = !matcher && elem) ) { - matchedCount--; - } - - // Lengthen the array for every element, matched or not - if ( seed ) { - unmatched.push( elem ); - } - } - } - - // `i` is now the count of elements visited above, and adding it to `matchedCount` - // makes the latter nonnegative. - matchedCount += i; - - // Apply set filters to unmatched elements - // NOTE: This can be skipped if there are no unmatched elements (i.e., `matchedCount` - // equals `i`), unless we didn't visit _any_ elements in the above loop because we have - // no element matchers and no seed. - // Incrementing an initially-string "0" `i` allows `i` to remain a string only in that - // case, which will result in a "00" `matchedCount` that differs from `i` but is also - // numerically zero. - if ( bySet && i !== matchedCount ) { - j = 0; - while ( (matcher = setMatchers[j++]) ) { - matcher( unmatched, setMatched, context, xml ); - } - - if ( seed ) { - // Reintegrate element matches to eliminate the need for sorting - if ( matchedCount > 0 ) { - while ( i-- ) { - if ( !(unmatched[i] || setMatched[i]) ) { - setMatched[i] = pop.call( results ); - } - } - } - - // Discard index placeholder values to get only actual matches - setMatched = condense( setMatched ); - } - - // Add matches to results - push.apply( results, setMatched ); - - // Seedless set matches succeeding multiple successful matchers stipulate sorting - if ( outermost && !seed && setMatched.length > 0 && - ( matchedCount + setMatchers.length ) > 1 ) { - - Sizzle.uniqueSort( results ); - } - } - - // Override manipulation of globals by nested matchers - if ( outermost ) { - dirruns = dirrunsUnique; - outermostContext = contextBackup; - } - - return unmatched; - }; - - return bySet ? - markFunction( superMatcher ) : - superMatcher; -} - -compile = Sizzle.compile = function( selector, match /* Internal Use Only */ ) { - var i, - setMatchers = [], - elementMatchers = [], - cached = compilerCache[ selector + " " ]; - - if ( !cached ) { - // Generate a function of recursive functions that can be used to check each element - if ( !match ) { - match = tokenize( selector ); - } - i = match.length; - while ( i-- ) { - cached = matcherFromTokens( match[i] ); - if ( cached[ expando ] ) { - setMatchers.push( cached ); - } else { - elementMatchers.push( cached ); - } - } - - // Cache the compiled function - cached = compilerCache( selector, matcherFromGroupMatchers( elementMatchers, setMatchers ) ); - - // Save selector and tokenization - cached.selector = selector; - } - return cached; -}; - -/** - * A low-level selection function that works with Sizzle's compiled - * selector functions - * @param {String|Function} selector A selector or a pre-compiled - * selector function built with Sizzle.compile - * @param {Element} context - * @param {Array} [results] - * @param {Array} [seed] A set of elements to match against - */ -select = Sizzle.select = function( selector, context, results, seed ) { - var i, tokens, token, type, find, - compiled = typeof selector === "function" && selector, - match = !seed && tokenize( (selector = compiled.selector || selector) ); - - results = results || []; - - // Try to minimize operations if there is only one selector in the list and no seed - // (the latter of which guarantees us context) - if ( match.length === 1 ) { - - // Reduce context if the leading compound selector is an ID - tokens = match[0] = match[0].slice( 0 ); - if ( tokens.length > 2 && (token = tokens[0]).type === "ID" && - context.nodeType === 9 && documentIsHTML && Expr.relative[ tokens[1].type ] ) { - - context = ( Expr.find["ID"]( token.matches[0].replace(runescape, funescape), context ) || [] )[0]; - if ( !context ) { - return results; - - // Precompiled matchers will still verify ancestry, so step up a level - } else if ( compiled ) { - context = context.parentNode; - } - - selector = selector.slice( tokens.shift().value.length ); - } - - // Fetch a seed set for right-to-left matching - i = matchExpr["needsContext"].test( selector ) ? 0 : tokens.length; - while ( i-- ) { - token = tokens[i]; - - // Abort if we hit a combinator - if ( Expr.relative[ (type = token.type) ] ) { - break; - } - if ( (find = Expr.find[ type ]) ) { - // Search, expanding context for leading sibling combinators - if ( (seed = find( - token.matches[0].replace( runescape, funescape ), - rsibling.test( tokens[0].type ) && testContext( context.parentNode ) || context - )) ) { - - // If seed is empty or no tokens remain, we can return early - tokens.splice( i, 1 ); - selector = seed.length && toSelector( tokens ); - if ( !selector ) { - push.apply( results, seed ); - return results; - } - - break; - } - } - } - } - - // Compile and execute a filtering function if one is not provided - // Provide `match` to avoid retokenization if we modified the selector above - ( compiled || compile( selector, match ) )( - seed, - context, - !documentIsHTML, - results, - !context || rsibling.test( selector ) && testContext( context.parentNode ) || context - ); - return results; -}; - -// One-time assignments - -// Sort stability -support.sortStable = expando.split("").sort( sortOrder ).join("") === expando; - -// Support: Chrome 14-35+ -// Always assume duplicates if they aren't passed to the comparison function -support.detectDuplicates = !!hasDuplicate; - -// Initialize against the default document -setDocument(); - -// Support: Webkit<537.32 - Safari 6.0.3/Chrome 25 (fixed in Chrome 27) -// Detached nodes confoundingly follow *each other* -support.sortDetached = assert(function( el ) { - // Should return 1, but returns 4 (following) - return el.compareDocumentPosition( document.createElement("fieldset") ) & 1; -}); - -// Support: IE<8 -// Prevent attribute/property "interpolation" -// https://msdn.microsoft.com/en-us/library/ms536429%28VS.85%29.aspx -if ( !assert(function( el ) { - el.innerHTML = ""; - return el.firstChild.getAttribute("href") === "#" ; -}) ) { - addHandle( "type|href|height|width", function( elem, name, isXML ) { - if ( !isXML ) { - return elem.getAttribute( name, name.toLowerCase() === "type" ? 1 : 2 ); - } - }); -} - -// Support: IE<9 -// Use defaultValue in place of getAttribute("value") -if ( !support.attributes || !assert(function( el ) { - el.innerHTML = ""; - el.firstChild.setAttribute( "value", "" ); - return el.firstChild.getAttribute( "value" ) === ""; -}) ) { - addHandle( "value", function( elem, name, isXML ) { - if ( !isXML && elem.nodeName.toLowerCase() === "input" ) { - return elem.defaultValue; - } - }); -} - -// Support: IE<9 -// Use getAttributeNode to fetch booleans when getAttribute lies -if ( !assert(function( el ) { - return el.getAttribute("disabled") == null; -}) ) { - addHandle( booleans, function( elem, name, isXML ) { - var val; - if ( !isXML ) { - return elem[ name ] === true ? name.toLowerCase() : - (val = elem.getAttributeNode( name )) && val.specified ? - val.value : - null; - } - }); -} - -return Sizzle; - -})( window ); - - - -jQuery.find = Sizzle; -jQuery.expr = Sizzle.selectors; - -// Deprecated -jQuery.expr[ ":" ] = jQuery.expr.pseudos; -jQuery.uniqueSort = jQuery.unique = Sizzle.uniqueSort; -jQuery.text = Sizzle.getText; -jQuery.isXMLDoc = Sizzle.isXML; -jQuery.contains = Sizzle.contains; -jQuery.escapeSelector = Sizzle.escape; - - - - -var dir = function( elem, dir, until ) { - var matched = [], - truncate = until !== undefined; - - while ( ( elem = elem[ dir ] ) && elem.nodeType !== 9 ) { - if ( elem.nodeType === 1 ) { - if ( truncate && jQuery( elem ).is( until ) ) { - break; - } - matched.push( elem ); - } - } - return matched; -}; - - -var siblings = function( n, elem ) { - var matched = []; - - for ( ; n; n = n.nextSibling ) { - if ( n.nodeType === 1 && n !== elem ) { - matched.push( n ); - } - } - - return matched; -}; - - -var rneedsContext = jQuery.expr.match.needsContext; - - - -function nodeName( elem, name ) { - - return elem.nodeName && elem.nodeName.toLowerCase() === name.toLowerCase(); - -}; -var rsingleTag = ( /^<([a-z][^\/\0>:\x20\t\r\n\f]*)[\x20\t\r\n\f]*\/?>(?:<\/\1>|)$/i ); - - - -var risSimple = /^.[^:#\[\.,]*$/; - -// Implement the identical functionality for filter and not -function winnow( elements, qualifier, not ) { - if ( jQuery.isFunction( qualifier ) ) { - return jQuery.grep( elements, function( elem, i ) { - return !!qualifier.call( elem, i, elem ) !== not; - } ); - } - - // Single element - if ( qualifier.nodeType ) { - return jQuery.grep( elements, function( elem ) { - return ( elem === qualifier ) !== not; - } ); - } - - // Arraylike of elements (jQuery, arguments, Array) - if ( typeof qualifier !== "string" ) { - return jQuery.grep( elements, function( elem ) { - return ( indexOf.call( qualifier, elem ) > -1 ) !== not; - } ); - } - - // Simple selector that can be filtered directly, removing non-Elements - if ( risSimple.test( qualifier ) ) { - return jQuery.filter( qualifier, elements, not ); - } - - // Complex selector, compare the two sets, removing non-Elements - qualifier = jQuery.filter( qualifier, elements ); - return jQuery.grep( elements, function( elem ) { - return ( indexOf.call( qualifier, elem ) > -1 ) !== not && elem.nodeType === 1; - } ); -} - -jQuery.filter = function( expr, elems, not ) { - var elem = elems[ 0 ]; - - if ( not ) { - expr = ":not(" + expr + ")"; - } - - if ( elems.length === 1 && elem.nodeType === 1 ) { - return jQuery.find.matchesSelector( elem, expr ) ? [ elem ] : []; - } - - return jQuery.find.matches( expr, jQuery.grep( elems, function( elem ) { - return elem.nodeType === 1; - } ) ); -}; - -jQuery.fn.extend( { - find: function( selector ) { - var i, ret, - len = this.length, - self = this; - - if ( typeof selector !== "string" ) { - return this.pushStack( jQuery( selector ).filter( function() { - for ( i = 0; i < len; i++ ) { - if ( jQuery.contains( self[ i ], this ) ) { - return true; - } - } - } ) ); - } - - ret = this.pushStack( [] ); - - for ( i = 0; i < len; i++ ) { - jQuery.find( selector, self[ i ], ret ); - } - - return len > 1 ? jQuery.uniqueSort( ret ) : ret; - }, - filter: function( selector ) { - return this.pushStack( winnow( this, selector || [], false ) ); - }, - not: function( selector ) { - return this.pushStack( winnow( this, selector || [], true ) ); - }, - is: function( selector ) { - return !!winnow( - this, - - // If this is a positional/relative selector, check membership in the returned set - // so $("p:first").is("p:last") won't return true for a doc with two "p". - typeof selector === "string" && rneedsContext.test( selector ) ? - jQuery( selector ) : - selector || [], - false - ).length; - } -} ); - - -// Initialize a jQuery object - - -// A central reference to the root jQuery(document) -var rootjQuery, - - // A simple way to check for HTML strings - // Prioritize #id over to avoid XSS via location.hash (#9521) - // Strict HTML recognition (#11290: must start with <) - // Shortcut simple #id case for speed - rquickExpr = /^(?:\s*(<[\w\W]+>)[^>]*|#([\w-]+))$/, - - init = jQuery.fn.init = function( selector, context, root ) { - var match, elem; - - // HANDLE: $(""), $(null), $(undefined), $(false) - if ( !selector ) { - return this; - } - - // Method init() accepts an alternate rootjQuery - // so migrate can support jQuery.sub (gh-2101) - root = root || rootjQuery; - - // Handle HTML strings - if ( typeof selector === "string" ) { - if ( selector[ 0 ] === "<" && - selector[ selector.length - 1 ] === ">" && - selector.length >= 3 ) { - - // Assume that strings that start and end with <> are HTML and skip the regex check - match = [ null, selector, null ]; - - } else { - match = rquickExpr.exec( selector ); - } - - // Match html or make sure no context is specified for #id - if ( match && ( match[ 1 ] || !context ) ) { - - // HANDLE: $(html) -> $(array) - if ( match[ 1 ] ) { - context = context instanceof jQuery ? context[ 0 ] : context; - - // Option to run scripts is true for back-compat - // Intentionally let the error be thrown if parseHTML is not present - jQuery.merge( this, jQuery.parseHTML( - match[ 1 ], - context && context.nodeType ? context.ownerDocument || context : document, - true - ) ); - - // HANDLE: $(html, props) - if ( rsingleTag.test( match[ 1 ] ) && jQuery.isPlainObject( context ) ) { - for ( match in context ) { - - // Properties of context are called as methods if possible - if ( jQuery.isFunction( this[ match ] ) ) { - this[ match ]( context[ match ] ); - - // ...and otherwise set as attributes - } else { - this.attr( match, context[ match ] ); - } - } - } - - return this; - - // HANDLE: $(#id) - } else { - elem = document.getElementById( match[ 2 ] ); - - if ( elem ) { - - // Inject the element directly into the jQuery object - this[ 0 ] = elem; - this.length = 1; - } - return this; - } - - // HANDLE: $(expr, $(...)) - } else if ( !context || context.jquery ) { - return ( context || root ).find( selector ); - - // HANDLE: $(expr, context) - // (which is just equivalent to: $(context).find(expr) - } else { - return this.constructor( context ).find( selector ); - } - - // HANDLE: $(DOMElement) - } else if ( selector.nodeType ) { - this[ 0 ] = selector; - this.length = 1; - return this; - - // HANDLE: $(function) - // Shortcut for document ready - } else if ( jQuery.isFunction( selector ) ) { - return root.ready !== undefined ? - root.ready( selector ) : - - // Execute immediately if ready is not present - selector( jQuery ); - } - - return jQuery.makeArray( selector, this ); - }; - -// Give the init function the jQuery prototype for later instantiation -init.prototype = jQuery.fn; - -// Initialize central reference -rootjQuery = jQuery( document ); - - -var rparentsprev = /^(?:parents|prev(?:Until|All))/, - - // Methods guaranteed to produce a unique set when starting from a unique set - guaranteedUnique = { - children: true, - contents: true, - next: true, - prev: true - }; - -jQuery.fn.extend( { - has: function( target ) { - var targets = jQuery( target, this ), - l = targets.length; - - return this.filter( function() { - var i = 0; - for ( ; i < l; i++ ) { - if ( jQuery.contains( this, targets[ i ] ) ) { - return true; - } - } - } ); - }, - - closest: function( selectors, context ) { - var cur, - i = 0, - l = this.length, - matched = [], - targets = typeof selectors !== "string" && jQuery( selectors ); - - // Positional selectors never match, since there's no _selection_ context - if ( !rneedsContext.test( selectors ) ) { - for ( ; i < l; i++ ) { - for ( cur = this[ i ]; cur && cur !== context; cur = cur.parentNode ) { - - // Always skip document fragments - if ( cur.nodeType < 11 && ( targets ? - targets.index( cur ) > -1 : - - // Don't pass non-elements to Sizzle - cur.nodeType === 1 && - jQuery.find.matchesSelector( cur, selectors ) ) ) { - - matched.push( cur ); - break; - } - } - } - } - - return this.pushStack( matched.length > 1 ? jQuery.uniqueSort( matched ) : matched ); - }, - - // Determine the position of an element within the set - index: function( elem ) { - - // No argument, return index in parent - if ( !elem ) { - return ( this[ 0 ] && this[ 0 ].parentNode ) ? this.first().prevAll().length : -1; - } - - // Index in selector - if ( typeof elem === "string" ) { - return indexOf.call( jQuery( elem ), this[ 0 ] ); - } - - // Locate the position of the desired element - return indexOf.call( this, - - // If it receives a jQuery object, the first element is used - elem.jquery ? elem[ 0 ] : elem - ); - }, - - add: function( selector, context ) { - return this.pushStack( - jQuery.uniqueSort( - jQuery.merge( this.get(), jQuery( selector, context ) ) - ) - ); - }, - - addBack: function( selector ) { - return this.add( selector == null ? - this.prevObject : this.prevObject.filter( selector ) - ); - } -} ); - -function sibling( cur, dir ) { - while ( ( cur = cur[ dir ] ) && cur.nodeType !== 1 ) {} - return cur; -} - -jQuery.each( { - parent: function( elem ) { - var parent = elem.parentNode; - return parent && parent.nodeType !== 11 ? parent : null; - }, - parents: function( elem ) { - return dir( elem, "parentNode" ); - }, - parentsUntil: function( elem, i, until ) { - return dir( elem, "parentNode", until ); - }, - next: function( elem ) { - return sibling( elem, "nextSibling" ); - }, - prev: function( elem ) { - return sibling( elem, "previousSibling" ); - }, - nextAll: function( elem ) { - return dir( elem, "nextSibling" ); - }, - prevAll: function( elem ) { - return dir( elem, "previousSibling" ); - }, - nextUntil: function( elem, i, until ) { - return dir( elem, "nextSibling", until ); - }, - prevUntil: function( elem, i, until ) { - return dir( elem, "previousSibling", until ); - }, - siblings: function( elem ) { - return siblings( ( elem.parentNode || {} ).firstChild, elem ); - }, - children: function( elem ) { - return siblings( elem.firstChild ); - }, - contents: function( elem ) { - if ( nodeName( elem, "iframe" ) ) { - return elem.contentDocument; - } - - // Support: IE 9 - 11 only, iOS 7 only, Android Browser <=4.3 only - // Treat the template element as a regular one in browsers that - // don't support it. - if ( nodeName( elem, "template" ) ) { - elem = elem.content || elem; - } - - return jQuery.merge( [], elem.childNodes ); - } -}, function( name, fn ) { - jQuery.fn[ name ] = function( until, selector ) { - var matched = jQuery.map( this, fn, until ); - - if ( name.slice( -5 ) !== "Until" ) { - selector = until; - } - - if ( selector && typeof selector === "string" ) { - matched = jQuery.filter( selector, matched ); - } - - if ( this.length > 1 ) { - - // Remove duplicates - if ( !guaranteedUnique[ name ] ) { - jQuery.uniqueSort( matched ); - } - - // Reverse order for parents* and prev-derivatives - if ( rparentsprev.test( name ) ) { - matched.reverse(); - } - } - - return this.pushStack( matched ); - }; -} ); -var rnothtmlwhite = ( /[^\x20\t\r\n\f]+/g ); - - - -// Convert String-formatted options into Object-formatted ones -function createOptions( options ) { - var object = {}; - jQuery.each( options.match( rnothtmlwhite ) || [], function( _, flag ) { - object[ flag ] = true; - } ); - return object; -} - -/* - * Create a callback list using the following parameters: - * - * options: an optional list of space-separated options that will change how - * the callback list behaves or a more traditional option object - * - * By default a callback list will act like an event callback list and can be - * "fired" multiple times. - * - * Possible options: - * - * once: will ensure the callback list can only be fired once (like a Deferred) - * - * memory: will keep track of previous values and will call any callback added - * after the list has been fired right away with the latest "memorized" - * values (like a Deferred) - * - * unique: will ensure a callback can only be added once (no duplicate in the list) - * - * stopOnFalse: interrupt callings when a callback returns false - * - */ -jQuery.Callbacks = function( options ) { - - // Convert options from String-formatted to Object-formatted if needed - // (we check in cache first) - options = typeof options === "string" ? - createOptions( options ) : - jQuery.extend( {}, options ); - - var // Flag to know if list is currently firing - firing, - - // Last fire value for non-forgettable lists - memory, - - // Flag to know if list was already fired - fired, - - // Flag to prevent firing - locked, - - // Actual callback list - list = [], - - // Queue of execution data for repeatable lists - queue = [], - - // Index of currently firing callback (modified by add/remove as needed) - firingIndex = -1, - - // Fire callbacks - fire = function() { - - // Enforce single-firing - locked = locked || options.once; - - // Execute callbacks for all pending executions, - // respecting firingIndex overrides and runtime changes - fired = firing = true; - for ( ; queue.length; firingIndex = -1 ) { - memory = queue.shift(); - while ( ++firingIndex < list.length ) { - - // Run callback and check for early termination - if ( list[ firingIndex ].apply( memory[ 0 ], memory[ 1 ] ) === false && - options.stopOnFalse ) { - - // Jump to end and forget the data so .add doesn't re-fire - firingIndex = list.length; - memory = false; - } - } - } - - // Forget the data if we're done with it - if ( !options.memory ) { - memory = false; - } - - firing = false; - - // Clean up if we're done firing for good - if ( locked ) { - - // Keep an empty list if we have data for future add calls - if ( memory ) { - list = []; - - // Otherwise, this object is spent - } else { - list = ""; - } - } - }, - - // Actual Callbacks object - self = { - - // Add a callback or a collection of callbacks to the list - add: function() { - if ( list ) { - - // If we have memory from a past run, we should fire after adding - if ( memory && !firing ) { - firingIndex = list.length - 1; - queue.push( memory ); - } - - ( function add( args ) { - jQuery.each( args, function( _, arg ) { - if ( jQuery.isFunction( arg ) ) { - if ( !options.unique || !self.has( arg ) ) { - list.push( arg ); - } - } else if ( arg && arg.length && jQuery.type( arg ) !== "string" ) { - - // Inspect recursively - add( arg ); - } - } ); - } )( arguments ); - - if ( memory && !firing ) { - fire(); - } - } - return this; - }, - - // Remove a callback from the list - remove: function() { - jQuery.each( arguments, function( _, arg ) { - var index; - while ( ( index = jQuery.inArray( arg, list, index ) ) > -1 ) { - list.splice( index, 1 ); - - // Handle firing indexes - if ( index <= firingIndex ) { - firingIndex--; - } - } - } ); - return this; - }, - - // Check if a given callback is in the list. - // If no argument is given, return whether or not list has callbacks attached. - has: function( fn ) { - return fn ? - jQuery.inArray( fn, list ) > -1 : - list.length > 0; - }, - - // Remove all callbacks from the list - empty: function() { - if ( list ) { - list = []; - } - return this; - }, - - // Disable .fire and .add - // Abort any current/pending executions - // Clear all callbacks and values - disable: function() { - locked = queue = []; - list = memory = ""; - return this; - }, - disabled: function() { - return !list; - }, - - // Disable .fire - // Also disable .add unless we have memory (since it would have no effect) - // Abort any pending executions - lock: function() { - locked = queue = []; - if ( !memory && !firing ) { - list = memory = ""; - } - return this; - }, - locked: function() { - return !!locked; - }, - - // Call all callbacks with the given context and arguments - fireWith: function( context, args ) { - if ( !locked ) { - args = args || []; - args = [ context, args.slice ? args.slice() : args ]; - queue.push( args ); - if ( !firing ) { - fire(); - } - } - return this; - }, - - // Call all the callbacks with the given arguments - fire: function() { - self.fireWith( this, arguments ); - return this; - }, - - // To know if the callbacks have already been called at least once - fired: function() { - return !!fired; - } - }; - - return self; -}; - - -function Identity( v ) { - return v; -} -function Thrower( ex ) { - throw ex; -} - -function adoptValue( value, resolve, reject, noValue ) { - var method; - - try { - - // Check for promise aspect first to privilege synchronous behavior - if ( value && jQuery.isFunction( ( method = value.promise ) ) ) { - method.call( value ).done( resolve ).fail( reject ); - - // Other thenables - } else if ( value && jQuery.isFunction( ( method = value.then ) ) ) { - method.call( value, resolve, reject ); - - // Other non-thenables - } else { - - // Control `resolve` arguments by letting Array#slice cast boolean `noValue` to integer: - // * false: [ value ].slice( 0 ) => resolve( value ) - // * true: [ value ].slice( 1 ) => resolve() - resolve.apply( undefined, [ value ].slice( noValue ) ); - } - - // For Promises/A+, convert exceptions into rejections - // Since jQuery.when doesn't unwrap thenables, we can skip the extra checks appearing in - // Deferred#then to conditionally suppress rejection. - } catch ( value ) { - - // Support: Android 4.0 only - // Strict mode functions invoked without .call/.apply get global-object context - reject.apply( undefined, [ value ] ); - } -} - -jQuery.extend( { - - Deferred: function( func ) { - var tuples = [ - - // action, add listener, callbacks, - // ... .then handlers, argument index, [final state] - [ "notify", "progress", jQuery.Callbacks( "memory" ), - jQuery.Callbacks( "memory" ), 2 ], - [ "resolve", "done", jQuery.Callbacks( "once memory" ), - jQuery.Callbacks( "once memory" ), 0, "resolved" ], - [ "reject", "fail", jQuery.Callbacks( "once memory" ), - jQuery.Callbacks( "once memory" ), 1, "rejected" ] - ], - state = "pending", - promise = { - state: function() { - return state; - }, - always: function() { - deferred.done( arguments ).fail( arguments ); - return this; - }, - "catch": function( fn ) { - return promise.then( null, fn ); - }, - - // Keep pipe for back-compat - pipe: function( /* fnDone, fnFail, fnProgress */ ) { - var fns = arguments; - - return jQuery.Deferred( function( newDefer ) { - jQuery.each( tuples, function( i, tuple ) { - - // Map tuples (progress, done, fail) to arguments (done, fail, progress) - var fn = jQuery.isFunction( fns[ tuple[ 4 ] ] ) && fns[ tuple[ 4 ] ]; - - // deferred.progress(function() { bind to newDefer or newDefer.notify }) - // deferred.done(function() { bind to newDefer or newDefer.resolve }) - // deferred.fail(function() { bind to newDefer or newDefer.reject }) - deferred[ tuple[ 1 ] ]( function() { - var returned = fn && fn.apply( this, arguments ); - if ( returned && jQuery.isFunction( returned.promise ) ) { - returned.promise() - .progress( newDefer.notify ) - .done( newDefer.resolve ) - .fail( newDefer.reject ); - } else { - newDefer[ tuple[ 0 ] + "With" ]( - this, - fn ? [ returned ] : arguments - ); - } - } ); - } ); - fns = null; - } ).promise(); - }, - then: function( onFulfilled, onRejected, onProgress ) { - var maxDepth = 0; - function resolve( depth, deferred, handler, special ) { - return function() { - var that = this, - args = arguments, - mightThrow = function() { - var returned, then; - - // Support: Promises/A+ section 2.3.3.3.3 - // https://promisesaplus.com/#point-59 - // Ignore double-resolution attempts - if ( depth < maxDepth ) { - return; - } - - returned = handler.apply( that, args ); - - // Support: Promises/A+ section 2.3.1 - // https://promisesaplus.com/#point-48 - if ( returned === deferred.promise() ) { - throw new TypeError( "Thenable self-resolution" ); - } - - // Support: Promises/A+ sections 2.3.3.1, 3.5 - // https://promisesaplus.com/#point-54 - // https://promisesaplus.com/#point-75 - // Retrieve `then` only once - then = returned && - - // Support: Promises/A+ section 2.3.4 - // https://promisesaplus.com/#point-64 - // Only check objects and functions for thenability - ( typeof returned === "object" || - typeof returned === "function" ) && - returned.then; - - // Handle a returned thenable - if ( jQuery.isFunction( then ) ) { - - // Special processors (notify) just wait for resolution - if ( special ) { - then.call( - returned, - resolve( maxDepth, deferred, Identity, special ), - resolve( maxDepth, deferred, Thrower, special ) - ); - - // Normal processors (resolve) also hook into progress - } else { - - // ...and disregard older resolution values - maxDepth++; - - then.call( - returned, - resolve( maxDepth, deferred, Identity, special ), - resolve( maxDepth, deferred, Thrower, special ), - resolve( maxDepth, deferred, Identity, - deferred.notifyWith ) - ); - } - - // Handle all other returned values - } else { - - // Only substitute handlers pass on context - // and multiple values (non-spec behavior) - if ( handler !== Identity ) { - that = undefined; - args = [ returned ]; - } - - // Process the value(s) - // Default process is resolve - ( special || deferred.resolveWith )( that, args ); - } - }, - - // Only normal processors (resolve) catch and reject exceptions - process = special ? - mightThrow : - function() { - try { - mightThrow(); - } catch ( e ) { - - if ( jQuery.Deferred.exceptionHook ) { - jQuery.Deferred.exceptionHook( e, - process.stackTrace ); - } - - // Support: Promises/A+ section 2.3.3.3.4.1 - // https://promisesaplus.com/#point-61 - // Ignore post-resolution exceptions - if ( depth + 1 >= maxDepth ) { - - // Only substitute handlers pass on context - // and multiple values (non-spec behavior) - if ( handler !== Thrower ) { - that = undefined; - args = [ e ]; - } - - deferred.rejectWith( that, args ); - } - } - }; - - // Support: Promises/A+ section 2.3.3.3.1 - // https://promisesaplus.com/#point-57 - // Re-resolve promises immediately to dodge false rejection from - // subsequent errors - if ( depth ) { - process(); - } else { - - // Call an optional hook to record the stack, in case of exception - // since it's otherwise lost when execution goes async - if ( jQuery.Deferred.getStackHook ) { - process.stackTrace = jQuery.Deferred.getStackHook(); - } - window.setTimeout( process ); - } - }; - } - - return jQuery.Deferred( function( newDefer ) { - - // progress_handlers.add( ... ) - tuples[ 0 ][ 3 ].add( - resolve( - 0, - newDefer, - jQuery.isFunction( onProgress ) ? - onProgress : - Identity, - newDefer.notifyWith - ) - ); - - // fulfilled_handlers.add( ... ) - tuples[ 1 ][ 3 ].add( - resolve( - 0, - newDefer, - jQuery.isFunction( onFulfilled ) ? - onFulfilled : - Identity - ) - ); - - // rejected_handlers.add( ... ) - tuples[ 2 ][ 3 ].add( - resolve( - 0, - newDefer, - jQuery.isFunction( onRejected ) ? - onRejected : - Thrower - ) - ); - } ).promise(); - }, - - // Get a promise for this deferred - // If obj is provided, the promise aspect is added to the object - promise: function( obj ) { - return obj != null ? jQuery.extend( obj, promise ) : promise; - } - }, - deferred = {}; - - // Add list-specific methods - jQuery.each( tuples, function( i, tuple ) { - var list = tuple[ 2 ], - stateString = tuple[ 5 ]; - - // promise.progress = list.add - // promise.done = list.add - // promise.fail = list.add - promise[ tuple[ 1 ] ] = list.add; - - // Handle state - if ( stateString ) { - list.add( - function() { - - // state = "resolved" (i.e., fulfilled) - // state = "rejected" - state = stateString; - }, - - // rejected_callbacks.disable - // fulfilled_callbacks.disable - tuples[ 3 - i ][ 2 ].disable, - - // progress_callbacks.lock - tuples[ 0 ][ 2 ].lock - ); - } - - // progress_handlers.fire - // fulfilled_handlers.fire - // rejected_handlers.fire - list.add( tuple[ 3 ].fire ); - - // deferred.notify = function() { deferred.notifyWith(...) } - // deferred.resolve = function() { deferred.resolveWith(...) } - // deferred.reject = function() { deferred.rejectWith(...) } - deferred[ tuple[ 0 ] ] = function() { - deferred[ tuple[ 0 ] + "With" ]( this === deferred ? undefined : this, arguments ); - return this; - }; - - // deferred.notifyWith = list.fireWith - // deferred.resolveWith = list.fireWith - // deferred.rejectWith = list.fireWith - deferred[ tuple[ 0 ] + "With" ] = list.fireWith; - } ); - - // Make the deferred a promise - promise.promise( deferred ); - - // Call given func if any - if ( func ) { - func.call( deferred, deferred ); - } - - // All done! - return deferred; - }, - - // Deferred helper - when: function( singleValue ) { - var - - // count of uncompleted subordinates - remaining = arguments.length, - - // count of unprocessed arguments - i = remaining, - - // subordinate fulfillment data - resolveContexts = Array( i ), - resolveValues = slice.call( arguments ), - - // the master Deferred - master = jQuery.Deferred(), - - // subordinate callback factory - updateFunc = function( i ) { - return function( value ) { - resolveContexts[ i ] = this; - resolveValues[ i ] = arguments.length > 1 ? slice.call( arguments ) : value; - if ( !( --remaining ) ) { - master.resolveWith( resolveContexts, resolveValues ); - } - }; - }; - - // Single- and empty arguments are adopted like Promise.resolve - if ( remaining <= 1 ) { - adoptValue( singleValue, master.done( updateFunc( i ) ).resolve, master.reject, - !remaining ); - - // Use .then() to unwrap secondary thenables (cf. gh-3000) - if ( master.state() === "pending" || - jQuery.isFunction( resolveValues[ i ] && resolveValues[ i ].then ) ) { - - return master.then(); - } - } - - // Multiple arguments are aggregated like Promise.all array elements - while ( i-- ) { - adoptValue( resolveValues[ i ], updateFunc( i ), master.reject ); - } - - return master.promise(); - } -} ); - - -// These usually indicate a programmer mistake during development, -// warn about them ASAP rather than swallowing them by default. -var rerrorNames = /^(Eval|Internal|Range|Reference|Syntax|Type|URI)Error$/; - -jQuery.Deferred.exceptionHook = function( error, stack ) { - - // Support: IE 8 - 9 only - // Console exists when dev tools are open, which can happen at any time - if ( window.console && window.console.warn && error && rerrorNames.test( error.name ) ) { - window.console.warn( "jQuery.Deferred exception: " + error.message, error.stack, stack ); - } -}; - - - - -jQuery.readyException = function( error ) { - window.setTimeout( function() { - throw error; - } ); -}; - - - - -// The deferred used on DOM ready -var readyList = jQuery.Deferred(); - -jQuery.fn.ready = function( fn ) { - - readyList - .then( fn ) - - // Wrap jQuery.readyException in a function so that the lookup - // happens at the time of error handling instead of callback - // registration. - .catch( function( error ) { - jQuery.readyException( error ); - } ); - - return this; -}; - -jQuery.extend( { - - // Is the DOM ready to be used? Set to true once it occurs. - isReady: false, - - // A counter to track how many items to wait for before - // the ready event fires. See #6781 - readyWait: 1, - - // Handle when the DOM is ready - ready: function( wait ) { - - // Abort if there are pending holds or we're already ready - if ( wait === true ? --jQuery.readyWait : jQuery.isReady ) { - return; - } - - // Remember that the DOM is ready - jQuery.isReady = true; - - // If a normal DOM Ready event fired, decrement, and wait if need be - if ( wait !== true && --jQuery.readyWait > 0 ) { - return; - } - - // If there are functions bound, to execute - readyList.resolveWith( document, [ jQuery ] ); - } -} ); - -jQuery.ready.then = readyList.then; - -// The ready event handler and self cleanup method -function completed() { - document.removeEventListener( "DOMContentLoaded", completed ); - window.removeEventListener( "load", completed ); - jQuery.ready(); -} - -// Catch cases where $(document).ready() is called -// after the browser event has already occurred. -// Support: IE <=9 - 10 only -// Older IE sometimes signals "interactive" too soon -if ( document.readyState === "complete" || - ( document.readyState !== "loading" && !document.documentElement.doScroll ) ) { - - // Handle it asynchronously to allow scripts the opportunity to delay ready - window.setTimeout( jQuery.ready ); - -} else { - - // Use the handy event callback - document.addEventListener( "DOMContentLoaded", completed ); - - // A fallback to window.onload, that will always work - window.addEventListener( "load", completed ); -} - - - - -// Multifunctional method to get and set values of a collection -// The value/s can optionally be executed if it's a function -var access = function( elems, fn, key, value, chainable, emptyGet, raw ) { - var i = 0, - len = elems.length, - bulk = key == null; - - // Sets many values - if ( jQuery.type( key ) === "object" ) { - chainable = true; - for ( i in key ) { - access( elems, fn, i, key[ i ], true, emptyGet, raw ); - } - - // Sets one value - } else if ( value !== undefined ) { - chainable = true; - - if ( !jQuery.isFunction( value ) ) { - raw = true; - } - - if ( bulk ) { - - // Bulk operations run against the entire set - if ( raw ) { - fn.call( elems, value ); - fn = null; - - // ...except when executing function values - } else { - bulk = fn; - fn = function( elem, key, value ) { - return bulk.call( jQuery( elem ), value ); - }; - } - } - - if ( fn ) { - for ( ; i < len; i++ ) { - fn( - elems[ i ], key, raw ? - value : - value.call( elems[ i ], i, fn( elems[ i ], key ) ) - ); - } - } - } - - if ( chainable ) { - return elems; - } - - // Gets - if ( bulk ) { - return fn.call( elems ); - } - - return len ? fn( elems[ 0 ], key ) : emptyGet; -}; -var acceptData = function( owner ) { - - // Accepts only: - // - Node - // - Node.ELEMENT_NODE - // - Node.DOCUMENT_NODE - // - Object - // - Any - return owner.nodeType === 1 || owner.nodeType === 9 || !( +owner.nodeType ); -}; - - - - -function Data() { - this.expando = jQuery.expando + Data.uid++; -} - -Data.uid = 1; - -Data.prototype = { - - cache: function( owner ) { - - // Check if the owner object already has a cache - var value = owner[ this.expando ]; - - // If not, create one - if ( !value ) { - value = {}; - - // We can accept data for non-element nodes in modern browsers, - // but we should not, see #8335. - // Always return an empty object. - if ( acceptData( owner ) ) { - - // If it is a node unlikely to be stringify-ed or looped over - // use plain assignment - if ( owner.nodeType ) { - owner[ this.expando ] = value; - - // Otherwise secure it in a non-enumerable property - // configurable must be true to allow the property to be - // deleted when data is removed - } else { - Object.defineProperty( owner, this.expando, { - value: value, - configurable: true - } ); - } - } - } - - return value; - }, - set: function( owner, data, value ) { - var prop, - cache = this.cache( owner ); - - // Handle: [ owner, key, value ] args - // Always use camelCase key (gh-2257) - if ( typeof data === "string" ) { - cache[ jQuery.camelCase( data ) ] = value; - - // Handle: [ owner, { properties } ] args - } else { - - // Copy the properties one-by-one to the cache object - for ( prop in data ) { - cache[ jQuery.camelCase( prop ) ] = data[ prop ]; - } - } - return cache; - }, - get: function( owner, key ) { - return key === undefined ? - this.cache( owner ) : - - // Always use camelCase key (gh-2257) - owner[ this.expando ] && owner[ this.expando ][ jQuery.camelCase( key ) ]; - }, - access: function( owner, key, value ) { - - // In cases where either: - // - // 1. No key was specified - // 2. A string key was specified, but no value provided - // - // Take the "read" path and allow the get method to determine - // which value to return, respectively either: - // - // 1. The entire cache object - // 2. The data stored at the key - // - if ( key === undefined || - ( ( key && typeof key === "string" ) && value === undefined ) ) { - - return this.get( owner, key ); - } - - // When the key is not a string, or both a key and value - // are specified, set or extend (existing objects) with either: - // - // 1. An object of properties - // 2. A key and value - // - this.set( owner, key, value ); - - // Since the "set" path can have two possible entry points - // return the expected data based on which path was taken[*] - return value !== undefined ? value : key; - }, - remove: function( owner, key ) { - var i, - cache = owner[ this.expando ]; - - if ( cache === undefined ) { - return; - } - - if ( key !== undefined ) { - - // Support array or space separated string of keys - if ( Array.isArray( key ) ) { - - // If key is an array of keys... - // We always set camelCase keys, so remove that. - key = key.map( jQuery.camelCase ); - } else { - key = jQuery.camelCase( key ); - - // If a key with the spaces exists, use it. - // Otherwise, create an array by matching non-whitespace - key = key in cache ? - [ key ] : - ( key.match( rnothtmlwhite ) || [] ); - } - - i = key.length; - - while ( i-- ) { - delete cache[ key[ i ] ]; - } - } - - // Remove the expando if there's no more data - if ( key === undefined || jQuery.isEmptyObject( cache ) ) { - - // Support: Chrome <=35 - 45 - // Webkit & Blink performance suffers when deleting properties - // from DOM nodes, so set to undefined instead - // https://bugs.chromium.org/p/chromium/issues/detail?id=378607 (bug restricted) - if ( owner.nodeType ) { - owner[ this.expando ] = undefined; - } else { - delete owner[ this.expando ]; - } - } - }, - hasData: function( owner ) { - var cache = owner[ this.expando ]; - return cache !== undefined && !jQuery.isEmptyObject( cache ); - } -}; -var dataPriv = new Data(); - -var dataUser = new Data(); - - - -// Implementation Summary -// -// 1. Enforce API surface and semantic compatibility with 1.9.x branch -// 2. Improve the module's maintainability by reducing the storage -// paths to a single mechanism. -// 3. Use the same single mechanism to support "private" and "user" data. -// 4. _Never_ expose "private" data to user code (TODO: Drop _data, _removeData) -// 5. Avoid exposing implementation details on user objects (eg. expando properties) -// 6. Provide a clear path for implementation upgrade to WeakMap in 2014 - -var rbrace = /^(?:\{[\w\W]*\}|\[[\w\W]*\])$/, - rmultiDash = /[A-Z]/g; - -function getData( data ) { - if ( data === "true" ) { - return true; - } - - if ( data === "false" ) { - return false; - } - - if ( data === "null" ) { - return null; - } - - // Only convert to a number if it doesn't change the string - if ( data === +data + "" ) { - return +data; - } - - if ( rbrace.test( data ) ) { - return JSON.parse( data ); - } - - return data; -} - -function dataAttr( elem, key, data ) { - var name; - - // If nothing was found internally, try to fetch any - // data from the HTML5 data-* attribute - if ( data === undefined && elem.nodeType === 1 ) { - name = "data-" + key.replace( rmultiDash, "-$&" ).toLowerCase(); - data = elem.getAttribute( name ); - - if ( typeof data === "string" ) { - try { - data = getData( data ); - } catch ( e ) {} - - // Make sure we set the data so it isn't changed later - dataUser.set( elem, key, data ); - } else { - data = undefined; - } - } - return data; -} - -jQuery.extend( { - hasData: function( elem ) { - return dataUser.hasData( elem ) || dataPriv.hasData( elem ); - }, - - data: function( elem, name, data ) { - return dataUser.access( elem, name, data ); - }, - - removeData: function( elem, name ) { - dataUser.remove( elem, name ); - }, - - // TODO: Now that all calls to _data and _removeData have been replaced - // with direct calls to dataPriv methods, these can be deprecated. - _data: function( elem, name, data ) { - return dataPriv.access( elem, name, data ); - }, - - _removeData: function( elem, name ) { - dataPriv.remove( elem, name ); - } -} ); - -jQuery.fn.extend( { - data: function( key, value ) { - var i, name, data, - elem = this[ 0 ], - attrs = elem && elem.attributes; - - // Gets all values - if ( key === undefined ) { - if ( this.length ) { - data = dataUser.get( elem ); - - if ( elem.nodeType === 1 && !dataPriv.get( elem, "hasDataAttrs" ) ) { - i = attrs.length; - while ( i-- ) { - - // Support: IE 11 only - // The attrs elements can be null (#14894) - if ( attrs[ i ] ) { - name = attrs[ i ].name; - if ( name.indexOf( "data-" ) === 0 ) { - name = jQuery.camelCase( name.slice( 5 ) ); - dataAttr( elem, name, data[ name ] ); - } - } - } - dataPriv.set( elem, "hasDataAttrs", true ); - } - } - - return data; - } - - // Sets multiple values - if ( typeof key === "object" ) { - return this.each( function() { - dataUser.set( this, key ); - } ); - } - - return access( this, function( value ) { - var data; - - // The calling jQuery object (element matches) is not empty - // (and therefore has an element appears at this[ 0 ]) and the - // `value` parameter was not undefined. An empty jQuery object - // will result in `undefined` for elem = this[ 0 ] which will - // throw an exception if an attempt to read a data cache is made. - if ( elem && value === undefined ) { - - // Attempt to get data from the cache - // The key will always be camelCased in Data - data = dataUser.get( elem, key ); - if ( data !== undefined ) { - return data; - } - - // Attempt to "discover" the data in - // HTML5 custom data-* attrs - data = dataAttr( elem, key ); - if ( data !== undefined ) { - return data; - } - - // We tried really hard, but the data doesn't exist. - return; - } - - // Set the data... - this.each( function() { - - // We always store the camelCased key - dataUser.set( this, key, value ); - } ); - }, null, value, arguments.length > 1, null, true ); - }, - - removeData: function( key ) { - return this.each( function() { - dataUser.remove( this, key ); - } ); - } -} ); - - -jQuery.extend( { - queue: function( elem, type, data ) { - var queue; - - if ( elem ) { - type = ( type || "fx" ) + "queue"; - queue = dataPriv.get( elem, type ); - - // Speed up dequeue by getting out quickly if this is just a lookup - if ( data ) { - if ( !queue || Array.isArray( data ) ) { - queue = dataPriv.access( elem, type, jQuery.makeArray( data ) ); - } else { - queue.push( data ); - } - } - return queue || []; - } - }, - - dequeue: function( elem, type ) { - type = type || "fx"; - - var queue = jQuery.queue( elem, type ), - startLength = queue.length, - fn = queue.shift(), - hooks = jQuery._queueHooks( elem, type ), - next = function() { - jQuery.dequeue( elem, type ); - }; - - // If the fx queue is dequeued, always remove the progress sentinel - if ( fn === "inprogress" ) { - fn = queue.shift(); - startLength--; - } - - if ( fn ) { - - // Add a progress sentinel to prevent the fx queue from being - // automatically dequeued - if ( type === "fx" ) { - queue.unshift( "inprogress" ); - } - - // Clear up the last queue stop function - delete hooks.stop; - fn.call( elem, next, hooks ); - } - - if ( !startLength && hooks ) { - hooks.empty.fire(); - } - }, - - // Not public - generate a queueHooks object, or return the current one - _queueHooks: function( elem, type ) { - var key = type + "queueHooks"; - return dataPriv.get( elem, key ) || dataPriv.access( elem, key, { - empty: jQuery.Callbacks( "once memory" ).add( function() { - dataPriv.remove( elem, [ type + "queue", key ] ); - } ) - } ); - } -} ); - -jQuery.fn.extend( { - queue: function( type, data ) { - var setter = 2; - - if ( typeof type !== "string" ) { - data = type; - type = "fx"; - setter--; - } - - if ( arguments.length < setter ) { - return jQuery.queue( this[ 0 ], type ); - } - - return data === undefined ? - this : - this.each( function() { - var queue = jQuery.queue( this, type, data ); - - // Ensure a hooks for this queue - jQuery._queueHooks( this, type ); - - if ( type === "fx" && queue[ 0 ] !== "inprogress" ) { - jQuery.dequeue( this, type ); - } - } ); - }, - dequeue: function( type ) { - return this.each( function() { - jQuery.dequeue( this, type ); - } ); - }, - clearQueue: function( type ) { - return this.queue( type || "fx", [] ); - }, - - // Get a promise resolved when queues of a certain type - // are emptied (fx is the type by default) - promise: function( type, obj ) { - var tmp, - count = 1, - defer = jQuery.Deferred(), - elements = this, - i = this.length, - resolve = function() { - if ( !( --count ) ) { - defer.resolveWith( elements, [ elements ] ); - } - }; - - if ( typeof type !== "string" ) { - obj = type; - type = undefined; - } - type = type || "fx"; - - while ( i-- ) { - tmp = dataPriv.get( elements[ i ], type + "queueHooks" ); - if ( tmp && tmp.empty ) { - count++; - tmp.empty.add( resolve ); - } - } - resolve(); - return defer.promise( obj ); - } -} ); -var pnum = ( /[+-]?(?:\d*\.|)\d+(?:[eE][+-]?\d+|)/ ).source; - -var rcssNum = new RegExp( "^(?:([+-])=|)(" + pnum + ")([a-z%]*)$", "i" ); - - -var cssExpand = [ "Top", "Right", "Bottom", "Left" ]; - -var isHiddenWithinTree = function( elem, el ) { - - // isHiddenWithinTree might be called from jQuery#filter function; - // in that case, element will be second argument - elem = el || elem; - - // Inline style trumps all - return elem.style.display === "none" || - elem.style.display === "" && - - // Otherwise, check computed style - // Support: Firefox <=43 - 45 - // Disconnected elements can have computed display: none, so first confirm that elem is - // in the document. - jQuery.contains( elem.ownerDocument, elem ) && - - jQuery.css( elem, "display" ) === "none"; - }; - -var swap = function( elem, options, callback, args ) { - var ret, name, - old = {}; - - // Remember the old values, and insert the new ones - for ( name in options ) { - old[ name ] = elem.style[ name ]; - elem.style[ name ] = options[ name ]; - } - - ret = callback.apply( elem, args || [] ); - - // Revert the old values - for ( name in options ) { - elem.style[ name ] = old[ name ]; - } - - return ret; -}; - - - - -function adjustCSS( elem, prop, valueParts, tween ) { - var adjusted, - scale = 1, - maxIterations = 20, - currentValue = tween ? - function() { - return tween.cur(); - } : - function() { - return jQuery.css( elem, prop, "" ); - }, - initial = currentValue(), - unit = valueParts && valueParts[ 3 ] || ( jQuery.cssNumber[ prop ] ? "" : "px" ), - - // Starting value computation is required for potential unit mismatches - initialInUnit = ( jQuery.cssNumber[ prop ] || unit !== "px" && +initial ) && - rcssNum.exec( jQuery.css( elem, prop ) ); - - if ( initialInUnit && initialInUnit[ 3 ] !== unit ) { - - // Trust units reported by jQuery.css - unit = unit || initialInUnit[ 3 ]; - - // Make sure we update the tween properties later on - valueParts = valueParts || []; - - // Iteratively approximate from a nonzero starting point - initialInUnit = +initial || 1; - - do { - - // If previous iteration zeroed out, double until we get *something*. - // Use string for doubling so we don't accidentally see scale as unchanged below - scale = scale || ".5"; - - // Adjust and apply - initialInUnit = initialInUnit / scale; - jQuery.style( elem, prop, initialInUnit + unit ); - - // Update scale, tolerating zero or NaN from tween.cur() - // Break the loop if scale is unchanged or perfect, or if we've just had enough. - } while ( - scale !== ( scale = currentValue() / initial ) && scale !== 1 && --maxIterations - ); - } - - if ( valueParts ) { - initialInUnit = +initialInUnit || +initial || 0; - - // Apply relative offset (+=/-=) if specified - adjusted = valueParts[ 1 ] ? - initialInUnit + ( valueParts[ 1 ] + 1 ) * valueParts[ 2 ] : - +valueParts[ 2 ]; - if ( tween ) { - tween.unit = unit; - tween.start = initialInUnit; - tween.end = adjusted; - } - } - return adjusted; -} - - -var defaultDisplayMap = {}; - -function getDefaultDisplay( elem ) { - var temp, - doc = elem.ownerDocument, - nodeName = elem.nodeName, - display = defaultDisplayMap[ nodeName ]; - - if ( display ) { - return display; - } - - temp = doc.body.appendChild( doc.createElement( nodeName ) ); - display = jQuery.css( temp, "display" ); - - temp.parentNode.removeChild( temp ); - - if ( display === "none" ) { - display = "block"; - } - defaultDisplayMap[ nodeName ] = display; - - return display; -} - -function showHide( elements, show ) { - var display, elem, - values = [], - index = 0, - length = elements.length; - - // Determine new display value for elements that need to change - for ( ; index < length; index++ ) { - elem = elements[ index ]; - if ( !elem.style ) { - continue; - } - - display = elem.style.display; - if ( show ) { - - // Since we force visibility upon cascade-hidden elements, an immediate (and slow) - // check is required in this first loop unless we have a nonempty display value (either - // inline or about-to-be-restored) - if ( display === "none" ) { - values[ index ] = dataPriv.get( elem, "display" ) || null; - if ( !values[ index ] ) { - elem.style.display = ""; - } - } - if ( elem.style.display === "" && isHiddenWithinTree( elem ) ) { - values[ index ] = getDefaultDisplay( elem ); - } - } else { - if ( display !== "none" ) { - values[ index ] = "none"; - - // Remember what we're overwriting - dataPriv.set( elem, "display", display ); - } - } - } - - // Set the display of the elements in a second loop to avoid constant reflow - for ( index = 0; index < length; index++ ) { - if ( values[ index ] != null ) { - elements[ index ].style.display = values[ index ]; - } - } - - return elements; -} - -jQuery.fn.extend( { - show: function() { - return showHide( this, true ); - }, - hide: function() { - return showHide( this ); - }, - toggle: function( state ) { - if ( typeof state === "boolean" ) { - return state ? this.show() : this.hide(); - } - - return this.each( function() { - if ( isHiddenWithinTree( this ) ) { - jQuery( this ).show(); - } else { - jQuery( this ).hide(); - } - } ); - } -} ); -var rcheckableType = ( /^(?:checkbox|radio)$/i ); - -var rtagName = ( /<([a-z][^\/\0>\x20\t\r\n\f]+)/i ); - -var rscriptType = ( /^$|\/(?:java|ecma)script/i ); - - - -// We have to close these tags to support XHTML (#13200) -var wrapMap = { - - // Support: IE <=9 only - option: [ 1, "" ], - - // XHTML parsers do not magically insert elements in the - // same way that tag soup parsers do. So we cannot shorten - // this by omitting

          • ", "
            " ], - col: [ 2, "", "
            " ], - tr: [ 2, "", "
            " ], - td: [ 3, "", "
            " ], - - _default: [ 0, "", "" ] -}; - -// Support: IE <=9 only -wrapMap.optgroup = wrapMap.option; - -wrapMap.tbody = wrapMap.tfoot = wrapMap.colgroup = wrapMap.caption = wrapMap.thead; -wrapMap.th = wrapMap.td; - - -function getAll( context, tag ) { - - // Support: IE <=9 - 11 only - // Use typeof to avoid zero-argument method invocation on host objects (#15151) - var ret; - - if ( typeof context.getElementsByTagName !== "undefined" ) { - ret = context.getElementsByTagName( tag || "*" ); - - } else if ( typeof context.querySelectorAll !== "undefined" ) { - ret = context.querySelectorAll( tag || "*" ); - - } else { - ret = []; - } - - if ( tag === undefined || tag && nodeName( context, tag ) ) { - return jQuery.merge( [ context ], ret ); - } - - return ret; -} - - -// Mark scripts as having already been evaluated -function setGlobalEval( elems, refElements ) { - var i = 0, - l = elems.length; - - for ( ; i < l; i++ ) { - dataPriv.set( - elems[ i ], - "globalEval", - !refElements || dataPriv.get( refElements[ i ], "globalEval" ) - ); - } -} - - -var rhtml = /<|&#?\w+;/; - -function buildFragment( elems, context, scripts, selection, ignored ) { - var elem, tmp, tag, wrap, contains, j, - fragment = context.createDocumentFragment(), - nodes = [], - i = 0, - l = elems.length; - - for ( ; i < l; i++ ) { - elem = elems[ i ]; - - if ( elem || elem === 0 ) { - - // Add nodes directly - if ( jQuery.type( elem ) === "object" ) { - - // Support: Android <=4.0 only, PhantomJS 1 only - // push.apply(_, arraylike) throws on ancient WebKit - jQuery.merge( nodes, elem.nodeType ? [ elem ] : elem ); - - // Convert non-html into a text node - } else if ( !rhtml.test( elem ) ) { - nodes.push( context.createTextNode( elem ) ); - - // Convert html into DOM nodes - } else { - tmp = tmp || fragment.appendChild( context.createElement( "div" ) ); - - // Deserialize a standard representation - tag = ( rtagName.exec( elem ) || [ "", "" ] )[ 1 ].toLowerCase(); - wrap = wrapMap[ tag ] || wrapMap._default; - tmp.innerHTML = wrap[ 1 ] + jQuery.htmlPrefilter( elem ) + wrap[ 2 ]; - - // Descend through wrappers to the right content - j = wrap[ 0 ]; - while ( j-- ) { - tmp = tmp.lastChild; - } - - // Support: Android <=4.0 only, PhantomJS 1 only - // push.apply(_, arraylike) throws on ancient WebKit - jQuery.merge( nodes, tmp.childNodes ); - - // Remember the top-level container - tmp = fragment.firstChild; - - // Ensure the created nodes are orphaned (#12392) - tmp.textContent = ""; - } - } - } - - // Remove wrapper from fragment - fragment.textContent = ""; - - i = 0; - while ( ( elem = nodes[ i++ ] ) ) { - - // Skip elements already in the context collection (trac-4087) - if ( selection && jQuery.inArray( elem, selection ) > -1 ) { - if ( ignored ) { - ignored.push( elem ); - } - continue; - } - - contains = jQuery.contains( elem.ownerDocument, elem ); - - // Append to fragment - tmp = getAll( fragment.appendChild( elem ), "script" ); - - // Preserve script evaluation history - if ( contains ) { - setGlobalEval( tmp ); - } - - // Capture executables - if ( scripts ) { - j = 0; - while ( ( elem = tmp[ j++ ] ) ) { - if ( rscriptType.test( elem.type || "" ) ) { - scripts.push( elem ); - } - } - } - } - - return fragment; -} - - -( function() { - var fragment = document.createDocumentFragment(), - div = fragment.appendChild( document.createElement( "div" ) ), - input = document.createElement( "input" ); - - // Support: Android 4.0 - 4.3 only - // Check state lost if the name is set (#11217) - // Support: Windows Web Apps (WWA) - // `name` and `type` must use .setAttribute for WWA (#14901) - input.setAttribute( "type", "radio" ); - input.setAttribute( "checked", "checked" ); - input.setAttribute( "name", "t" ); - - div.appendChild( input ); - - // Support: Android <=4.1 only - // Older WebKit doesn't clone checked state correctly in fragments - support.checkClone = div.cloneNode( true ).cloneNode( true ).lastChild.checked; - - // Support: IE <=11 only - // Make sure textarea (and checkbox) defaultValue is properly cloned - div.innerHTML = ""; - support.noCloneChecked = !!div.cloneNode( true ).lastChild.defaultValue; -} )(); -var documentElement = document.documentElement; - - - -var - rkeyEvent = /^key/, - rmouseEvent = /^(?:mouse|pointer|contextmenu|drag|drop)|click/, - rtypenamespace = /^([^.]*)(?:\.(.+)|)/; - -function returnTrue() { - return true; -} - -function returnFalse() { - return false; -} - -// Support: IE <=9 only -// See #13393 for more info -function safeActiveElement() { - try { - return document.activeElement; - } catch ( err ) { } -} - -function on( elem, types, selector, data, fn, one ) { - var origFn, type; - - // Types can be a map of types/handlers - if ( typeof types === "object" ) { - - // ( types-Object, selector, data ) - if ( typeof selector !== "string" ) { - - // ( types-Object, data ) - data = data || selector; - selector = undefined; - } - for ( type in types ) { - on( elem, type, selector, data, types[ type ], one ); - } - return elem; - } - - if ( data == null && fn == null ) { - - // ( types, fn ) - fn = selector; - data = selector = undefined; - } else if ( fn == null ) { - if ( typeof selector === "string" ) { - - // ( types, selector, fn ) - fn = data; - data = undefined; - } else { - - // ( types, data, fn ) - fn = data; - data = selector; - selector = undefined; - } - } - if ( fn === false ) { - fn = returnFalse; - } else if ( !fn ) { - return elem; - } - - if ( one === 1 ) { - origFn = fn; - fn = function( event ) { - - // Can use an empty set, since event contains the info - jQuery().off( event ); - return origFn.apply( this, arguments ); - }; - - // Use same guid so caller can remove using origFn - fn.guid = origFn.guid || ( origFn.guid = jQuery.guid++ ); - } - return elem.each( function() { - jQuery.event.add( this, types, fn, data, selector ); - } ); -} - -/* - * Helper functions for managing events -- not part of the public interface. - * Props to Dean Edwards' addEvent library for many of the ideas. - */ -jQuery.event = { - - global: {}, - - add: function( elem, types, handler, data, selector ) { - - var handleObjIn, eventHandle, tmp, - events, t, handleObj, - special, handlers, type, namespaces, origType, - elemData = dataPriv.get( elem ); - - // Don't attach events to noData or text/comment nodes (but allow plain objects) - if ( !elemData ) { - return; - } - - // Caller can pass in an object of custom data in lieu of the handler - if ( handler.handler ) { - handleObjIn = handler; - handler = handleObjIn.handler; - selector = handleObjIn.selector; - } - - // Ensure that invalid selectors throw exceptions at attach time - // Evaluate against documentElement in case elem is a non-element node (e.g., document) - if ( selector ) { - jQuery.find.matchesSelector( documentElement, selector ); - } - - // Make sure that the handler has a unique ID, used to find/remove it later - if ( !handler.guid ) { - handler.guid = jQuery.guid++; - } - - // Init the element's event structure and main handler, if this is the first - if ( !( events = elemData.events ) ) { - events = elemData.events = {}; - } - if ( !( eventHandle = elemData.handle ) ) { - eventHandle = elemData.handle = function( e ) { - - // Discard the second event of a jQuery.event.trigger() and - // when an event is called after a page has unloaded - return typeof jQuery !== "undefined" && jQuery.event.triggered !== e.type ? - jQuery.event.dispatch.apply( elem, arguments ) : undefined; - }; - } - - // Handle multiple events separated by a space - types = ( types || "" ).match( rnothtmlwhite ) || [ "" ]; - t = types.length; - while ( t-- ) { - tmp = rtypenamespace.exec( types[ t ] ) || []; - type = origType = tmp[ 1 ]; - namespaces = ( tmp[ 2 ] || "" ).split( "." ).sort(); - - // There *must* be a type, no attaching namespace-only handlers - if ( !type ) { - continue; - } - - // If event changes its type, use the special event handlers for the changed type - special = jQuery.event.special[ type ] || {}; - - // If selector defined, determine special event api type, otherwise given type - type = ( selector ? special.delegateType : special.bindType ) || type; - - // Update special based on newly reset type - special = jQuery.event.special[ type ] || {}; - - // handleObj is passed to all event handlers - handleObj = jQuery.extend( { - type: type, - origType: origType, - data: data, - handler: handler, - guid: handler.guid, - selector: selector, - needsContext: selector && jQuery.expr.match.needsContext.test( selector ), - namespace: namespaces.join( "." ) - }, handleObjIn ); - - // Init the event handler queue if we're the first - if ( !( handlers = events[ type ] ) ) { - handlers = events[ type ] = []; - handlers.delegateCount = 0; - - // Only use addEventListener if the special events handler returns false - if ( !special.setup || - special.setup.call( elem, data, namespaces, eventHandle ) === false ) { - - if ( elem.addEventListener ) { - elem.addEventListener( type, eventHandle ); - } - } - } - - if ( special.add ) { - special.add.call( elem, handleObj ); - - if ( !handleObj.handler.guid ) { - handleObj.handler.guid = handler.guid; - } - } - - // Add to the element's handler list, delegates in front - if ( selector ) { - handlers.splice( handlers.delegateCount++, 0, handleObj ); - } else { - handlers.push( handleObj ); - } - - // Keep track of which events have ever been used, for event optimization - jQuery.event.global[ type ] = true; - } - - }, - - // Detach an event or set of events from an element - remove: function( elem, types, handler, selector, mappedTypes ) { - - var j, origCount, tmp, - events, t, handleObj, - special, handlers, type, namespaces, origType, - elemData = dataPriv.hasData( elem ) && dataPriv.get( elem ); - - if ( !elemData || !( events = elemData.events ) ) { - return; - } - - // Once for each type.namespace in types; type may be omitted - types = ( types || "" ).match( rnothtmlwhite ) || [ "" ]; - t = types.length; - while ( t-- ) { - tmp = rtypenamespace.exec( types[ t ] ) || []; - type = origType = tmp[ 1 ]; - namespaces = ( tmp[ 2 ] || "" ).split( "." ).sort(); - - // Unbind all events (on this namespace, if provided) for the element - if ( !type ) { - for ( type in events ) { - jQuery.event.remove( elem, type + types[ t ], handler, selector, true ); - } - continue; - } - - special = jQuery.event.special[ type ] || {}; - type = ( selector ? special.delegateType : special.bindType ) || type; - handlers = events[ type ] || []; - tmp = tmp[ 2 ] && - new RegExp( "(^|\\.)" + namespaces.join( "\\.(?:.*\\.|)" ) + "(\\.|$)" ); - - // Remove matching events - origCount = j = handlers.length; - while ( j-- ) { - handleObj = handlers[ j ]; - - if ( ( mappedTypes || origType === handleObj.origType ) && - ( !handler || handler.guid === handleObj.guid ) && - ( !tmp || tmp.test( handleObj.namespace ) ) && - ( !selector || selector === handleObj.selector || - selector === "**" && handleObj.selector ) ) { - handlers.splice( j, 1 ); - - if ( handleObj.selector ) { - handlers.delegateCount--; - } - if ( special.remove ) { - special.remove.call( elem, handleObj ); - } - } - } - - // Remove generic event handler if we removed something and no more handlers exist - // (avoids potential for endless recursion during removal of special event handlers) - if ( origCount && !handlers.length ) { - if ( !special.teardown || - special.teardown.call( elem, namespaces, elemData.handle ) === false ) { - - jQuery.removeEvent( elem, type, elemData.handle ); - } - - delete events[ type ]; - } - } - - // Remove data and the expando if it's no longer used - if ( jQuery.isEmptyObject( events ) ) { - dataPriv.remove( elem, "handle events" ); - } - }, - - dispatch: function( nativeEvent ) { - - // Make a writable jQuery.Event from the native event object - var event = jQuery.event.fix( nativeEvent ); - - var i, j, ret, matched, handleObj, handlerQueue, - args = new Array( arguments.length ), - handlers = ( dataPriv.get( this, "events" ) || {} )[ event.type ] || [], - special = jQuery.event.special[ event.type ] || {}; - - // Use the fix-ed jQuery.Event rather than the (read-only) native event - args[ 0 ] = event; - - for ( i = 1; i < arguments.length; i++ ) { - args[ i ] = arguments[ i ]; - } - - event.delegateTarget = this; - - // Call the preDispatch hook for the mapped type, and let it bail if desired - if ( special.preDispatch && special.preDispatch.call( this, event ) === false ) { - return; - } - - // Determine handlers - handlerQueue = jQuery.event.handlers.call( this, event, handlers ); - - // Run delegates first; they may want to stop propagation beneath us - i = 0; - while ( ( matched = handlerQueue[ i++ ] ) && !event.isPropagationStopped() ) { - event.currentTarget = matched.elem; - - j = 0; - while ( ( handleObj = matched.handlers[ j++ ] ) && - !event.isImmediatePropagationStopped() ) { - - // Triggered event must either 1) have no namespace, or 2) have namespace(s) - // a subset or equal to those in the bound event (both can have no namespace). - if ( !event.rnamespace || event.rnamespace.test( handleObj.namespace ) ) { - - event.handleObj = handleObj; - event.data = handleObj.data; - - ret = ( ( jQuery.event.special[ handleObj.origType ] || {} ).handle || - handleObj.handler ).apply( matched.elem, args ); - - if ( ret !== undefined ) { - if ( ( event.result = ret ) === false ) { - event.preventDefault(); - event.stopPropagation(); - } - } - } - } - } - - // Call the postDispatch hook for the mapped type - if ( special.postDispatch ) { - special.postDispatch.call( this, event ); - } - - return event.result; - }, - - handlers: function( event, handlers ) { - var i, handleObj, sel, matchedHandlers, matchedSelectors, - handlerQueue = [], - delegateCount = handlers.delegateCount, - cur = event.target; - - // Find delegate handlers - if ( delegateCount && - - // Support: IE <=9 - // Black-hole SVG instance trees (trac-13180) - cur.nodeType && - - // Support: Firefox <=42 - // Suppress spec-violating clicks indicating a non-primary pointer button (trac-3861) - // https://www.w3.org/TR/DOM-Level-3-Events/#event-type-click - // Support: IE 11 only - // ...but not arrow key "clicks" of radio inputs, which can have `button` -1 (gh-2343) - !( event.type === "click" && event.button >= 1 ) ) { - - for ( ; cur !== this; cur = cur.parentNode || this ) { - - // Don't check non-elements (#13208) - // Don't process clicks on disabled elements (#6911, #8165, #11382, #11764) - if ( cur.nodeType === 1 && !( event.type === "click" && cur.disabled === true ) ) { - matchedHandlers = []; - matchedSelectors = {}; - for ( i = 0; i < delegateCount; i++ ) { - handleObj = handlers[ i ]; - - // Don't conflict with Object.prototype properties (#13203) - sel = handleObj.selector + " "; - - if ( matchedSelectors[ sel ] === undefined ) { - matchedSelectors[ sel ] = handleObj.needsContext ? - jQuery( sel, this ).index( cur ) > -1 : - jQuery.find( sel, this, null, [ cur ] ).length; - } - if ( matchedSelectors[ sel ] ) { - matchedHandlers.push( handleObj ); - } - } - if ( matchedHandlers.length ) { - handlerQueue.push( { elem: cur, handlers: matchedHandlers } ); - } - } - } - } - - // Add the remaining (directly-bound) handlers - cur = this; - if ( delegateCount < handlers.length ) { - handlerQueue.push( { elem: cur, handlers: handlers.slice( delegateCount ) } ); - } - - return handlerQueue; - }, - - addProp: function( name, hook ) { - Object.defineProperty( jQuery.Event.prototype, name, { - enumerable: true, - configurable: true, - - get: jQuery.isFunction( hook ) ? - function() { - if ( this.originalEvent ) { - return hook( this.originalEvent ); - } - } : - function() { - if ( this.originalEvent ) { - return this.originalEvent[ name ]; - } - }, - - set: function( value ) { - Object.defineProperty( this, name, { - enumerable: true, - configurable: true, - writable: true, - value: value - } ); - } - } ); - }, - - fix: function( originalEvent ) { - return originalEvent[ jQuery.expando ] ? - originalEvent : - new jQuery.Event( originalEvent ); - }, - - special: { - load: { - - // Prevent triggered image.load events from bubbling to window.load - noBubble: true - }, - focus: { - - // Fire native event if possible so blur/focus sequence is correct - trigger: function() { - if ( this !== safeActiveElement() && this.focus ) { - this.focus(); - return false; - } - }, - delegateType: "focusin" - }, - blur: { - trigger: function() { - if ( this === safeActiveElement() && this.blur ) { - this.blur(); - return false; - } - }, - delegateType: "focusout" - }, - click: { - - // For checkbox, fire native event so checked state will be right - trigger: function() { - if ( this.type === "checkbox" && this.click && nodeName( this, "input" ) ) { - this.click(); - return false; - } - }, - - // For cross-browser consistency, don't fire native .click() on links - _default: function( event ) { - return nodeName( event.target, "a" ); - } - }, - - beforeunload: { - postDispatch: function( event ) { - - // Support: Firefox 20+ - // Firefox doesn't alert if the returnValue field is not set. - if ( event.result !== undefined && event.originalEvent ) { - event.originalEvent.returnValue = event.result; - } - } - } - } -}; - -jQuery.removeEvent = function( elem, type, handle ) { - - // This "if" is needed for plain objects - if ( elem.removeEventListener ) { - elem.removeEventListener( type, handle ); - } -}; - -jQuery.Event = function( src, props ) { - - // Allow instantiation without the 'new' keyword - if ( !( this instanceof jQuery.Event ) ) { - return new jQuery.Event( src, props ); - } - - // Event object - if ( src && src.type ) { - this.originalEvent = src; - this.type = src.type; - - // Events bubbling up the document may have been marked as prevented - // by a handler lower down the tree; reflect the correct value. - this.isDefaultPrevented = src.defaultPrevented || - src.defaultPrevented === undefined && - - // Support: Android <=2.3 only - src.returnValue === false ? - returnTrue : - returnFalse; - - // Create target properties - // Support: Safari <=6 - 7 only - // Target should not be a text node (#504, #13143) - this.target = ( src.target && src.target.nodeType === 3 ) ? - src.target.parentNode : - src.target; - - this.currentTarget = src.currentTarget; - this.relatedTarget = src.relatedTarget; - - // Event type - } else { - this.type = src; - } - - // Put explicitly provided properties onto the event object - if ( props ) { - jQuery.extend( this, props ); - } - - // Create a timestamp if incoming event doesn't have one - this.timeStamp = src && src.timeStamp || jQuery.now(); - - // Mark it as fixed - this[ jQuery.expando ] = true; -}; - -// jQuery.Event is based on DOM3 Events as specified by the ECMAScript Language Binding -// https://www.w3.org/TR/2003/WD-DOM-Level-3-Events-20030331/ecma-script-binding.html -jQuery.Event.prototype = { - constructor: jQuery.Event, - isDefaultPrevented: returnFalse, - isPropagationStopped: returnFalse, - isImmediatePropagationStopped: returnFalse, - isSimulated: false, - - preventDefault: function() { - var e = this.originalEvent; - - this.isDefaultPrevented = returnTrue; - - if ( e && !this.isSimulated ) { - e.preventDefault(); - } - }, - stopPropagation: function() { - var e = this.originalEvent; - - this.isPropagationStopped = returnTrue; - - if ( e && !this.isSimulated ) { - e.stopPropagation(); - } - }, - stopImmediatePropagation: function() { - var e = this.originalEvent; - - this.isImmediatePropagationStopped = returnTrue; - - if ( e && !this.isSimulated ) { - e.stopImmediatePropagation(); - } - - this.stopPropagation(); - } -}; - -// Includes all common event props including KeyEvent and MouseEvent specific props -jQuery.each( { - altKey: true, - bubbles: true, - cancelable: true, - changedTouches: true, - ctrlKey: true, - detail: true, - eventPhase: true, - metaKey: true, - pageX: true, - pageY: true, - shiftKey: true, - view: true, - "char": true, - charCode: true, - key: true, - keyCode: true, - button: true, - buttons: true, - clientX: true, - clientY: true, - offsetX: true, - offsetY: true, - pointerId: true, - pointerType: true, - screenX: true, - screenY: true, - targetTouches: true, - toElement: true, - touches: true, - - which: function( event ) { - var button = event.button; - - // Add which for key events - if ( event.which == null && rkeyEvent.test( event.type ) ) { - return event.charCode != null ? event.charCode : event.keyCode; - } - - // Add which for click: 1 === left; 2 === middle; 3 === right - if ( !event.which && button !== undefined && rmouseEvent.test( event.type ) ) { - if ( button & 1 ) { - return 1; - } - - if ( button & 2 ) { - return 3; - } - - if ( button & 4 ) { - return 2; - } - - return 0; - } - - return event.which; - } -}, jQuery.event.addProp ); - -// Create mouseenter/leave events using mouseover/out and event-time checks -// so that event delegation works in jQuery. -// Do the same for pointerenter/pointerleave and pointerover/pointerout -// -// Support: Safari 7 only -// Safari sends mouseenter too often; see: -// https://bugs.chromium.org/p/chromium/issues/detail?id=470258 -// for the description of the bug (it existed in older Chrome versions as well). -jQuery.each( { - mouseenter: "mouseover", - mouseleave: "mouseout", - pointerenter: "pointerover", - pointerleave: "pointerout" -}, function( orig, fix ) { - jQuery.event.special[ orig ] = { - delegateType: fix, - bindType: fix, - - handle: function( event ) { - var ret, - target = this, - related = event.relatedTarget, - handleObj = event.handleObj; - - // For mouseenter/leave call the handler if related is outside the target. - // NB: No relatedTarget if the mouse left/entered the browser window - if ( !related || ( related !== target && !jQuery.contains( target, related ) ) ) { - event.type = handleObj.origType; - ret = handleObj.handler.apply( this, arguments ); - event.type = fix; - } - return ret; - } - }; -} ); - -jQuery.fn.extend( { - - on: function( types, selector, data, fn ) { - return on( this, types, selector, data, fn ); - }, - one: function( types, selector, data, fn ) { - return on( this, types, selector, data, fn, 1 ); - }, - off: function( types, selector, fn ) { - var handleObj, type; - if ( types && types.preventDefault && types.handleObj ) { - - // ( event ) dispatched jQuery.Event - handleObj = types.handleObj; - jQuery( types.delegateTarget ).off( - handleObj.namespace ? - handleObj.origType + "." + handleObj.namespace : - handleObj.origType, - handleObj.selector, - handleObj.handler - ); - return this; - } - if ( typeof types === "object" ) { - - // ( types-object [, selector] ) - for ( type in types ) { - this.off( type, selector, types[ type ] ); - } - return this; - } - if ( selector === false || typeof selector === "function" ) { - - // ( types [, fn] ) - fn = selector; - selector = undefined; - } - if ( fn === false ) { - fn = returnFalse; - } - return this.each( function() { - jQuery.event.remove( this, types, fn, selector ); - } ); - } -} ); - - -var - - /* eslint-disable max-len */ - - // See https://github.com/eslint/eslint/issues/3229 - rxhtmlTag = /<(?!area|br|col|embed|hr|img|input|link|meta|param)(([a-z][^\/\0>\x20\t\r\n\f]*)[^>]*)\/>/gi, - - /* eslint-enable */ - - // Support: IE <=10 - 11, Edge 12 - 13 - // In IE/Edge using regex groups here causes severe slowdowns. - // See https://connect.microsoft.com/IE/feedback/details/1736512/ - rnoInnerhtml = /\s*$/g; - -// Prefer a tbody over its parent table for containing new rows -function manipulationTarget( elem, content ) { - if ( nodeName( elem, "table" ) && - nodeName( content.nodeType !== 11 ? content : content.firstChild, "tr" ) ) { - - return jQuery( ">tbody", elem )[ 0 ] || elem; - } - - return elem; -} - -// Replace/restore the type attribute of script elements for safe DOM manipulation -function disableScript( elem ) { - elem.type = ( elem.getAttribute( "type" ) !== null ) + "/" + elem.type; - return elem; -} -function restoreScript( elem ) { - var match = rscriptTypeMasked.exec( elem.type ); - - if ( match ) { - elem.type = match[ 1 ]; - } else { - elem.removeAttribute( "type" ); - } - - return elem; -} - -function cloneCopyEvent( src, dest ) { - var i, l, type, pdataOld, pdataCur, udataOld, udataCur, events; - - if ( dest.nodeType !== 1 ) { - return; - } - - // 1. Copy private data: events, handlers, etc. - if ( dataPriv.hasData( src ) ) { - pdataOld = dataPriv.access( src ); - pdataCur = dataPriv.set( dest, pdataOld ); - events = pdataOld.events; - - if ( events ) { - delete pdataCur.handle; - pdataCur.events = {}; - - for ( type in events ) { - for ( i = 0, l = events[ type ].length; i < l; i++ ) { - jQuery.event.add( dest, type, events[ type ][ i ] ); - } - } - } - } - - // 2. Copy user data - if ( dataUser.hasData( src ) ) { - udataOld = dataUser.access( src ); - udataCur = jQuery.extend( {}, udataOld ); - - dataUser.set( dest, udataCur ); - } -} - -// Fix IE bugs, see support tests -function fixInput( src, dest ) { - var nodeName = dest.nodeName.toLowerCase(); - - // Fails to persist the checked state of a cloned checkbox or radio button. - if ( nodeName === "input" && rcheckableType.test( src.type ) ) { - dest.checked = src.checked; - - // Fails to return the selected option to the default selected state when cloning options - } else if ( nodeName === "input" || nodeName === "textarea" ) { - dest.defaultValue = src.defaultValue; - } -} - -function domManip( collection, args, callback, ignored ) { - - // Flatten any nested arrays - args = concat.apply( [], args ); - - var fragment, first, scripts, hasScripts, node, doc, - i = 0, - l = collection.length, - iNoClone = l - 1, - value = args[ 0 ], - isFunction = jQuery.isFunction( value ); - - // We can't cloneNode fragments that contain checked, in WebKit - if ( isFunction || - ( l > 1 && typeof value === "string" && - !support.checkClone && rchecked.test( value ) ) ) { - return collection.each( function( index ) { - var self = collection.eq( index ); - if ( isFunction ) { - args[ 0 ] = value.call( this, index, self.html() ); - } - domManip( self, args, callback, ignored ); - } ); - } - - if ( l ) { - fragment = buildFragment( args, collection[ 0 ].ownerDocument, false, collection, ignored ); - first = fragment.firstChild; - - if ( fragment.childNodes.length === 1 ) { - fragment = first; - } - - // Require either new content or an interest in ignored elements to invoke the callback - if ( first || ignored ) { - scripts = jQuery.map( getAll( fragment, "script" ), disableScript ); - hasScripts = scripts.length; - - // Use the original fragment for the last item - // instead of the first because it can end up - // being emptied incorrectly in certain situations (#8070). - for ( ; i < l; i++ ) { - node = fragment; - - if ( i !== iNoClone ) { - node = jQuery.clone( node, true, true ); - - // Keep references to cloned scripts for later restoration - if ( hasScripts ) { - - // Support: Android <=4.0 only, PhantomJS 1 only - // push.apply(_, arraylike) throws on ancient WebKit - jQuery.merge( scripts, getAll( node, "script" ) ); - } - } - - callback.call( collection[ i ], node, i ); - } - - if ( hasScripts ) { - doc = scripts[ scripts.length - 1 ].ownerDocument; - - // Reenable scripts - jQuery.map( scripts, restoreScript ); - - // Evaluate executable scripts on first document insertion - for ( i = 0; i < hasScripts; i++ ) { - node = scripts[ i ]; - if ( rscriptType.test( node.type || "" ) && - !dataPriv.access( node, "globalEval" ) && - jQuery.contains( doc, node ) ) { - - if ( node.src ) { - - // Optional AJAX dependency, but won't run scripts if not present - if ( jQuery._evalUrl ) { - jQuery._evalUrl( node.src ); - } - } else { - DOMEval( node.textContent.replace( rcleanScript, "" ), doc ); - } - } - } - } - } - } - - return collection; -} - -function remove( elem, selector, keepData ) { - var node, - nodes = selector ? jQuery.filter( selector, elem ) : elem, - i = 0; - - for ( ; ( node = nodes[ i ] ) != null; i++ ) { - if ( !keepData && node.nodeType === 1 ) { - jQuery.cleanData( getAll( node ) ); - } - - if ( node.parentNode ) { - if ( keepData && jQuery.contains( node.ownerDocument, node ) ) { - setGlobalEval( getAll( node, "script" ) ); - } - node.parentNode.removeChild( node ); - } - } - - return elem; -} - -jQuery.extend( { - htmlPrefilter: function( html ) { - return html.replace( rxhtmlTag, "<$1>" ); - }, - - clone: function( elem, dataAndEvents, deepDataAndEvents ) { - var i, l, srcElements, destElements, - clone = elem.cloneNode( true ), - inPage = jQuery.contains( elem.ownerDocument, elem ); - - // Fix IE cloning issues - if ( !support.noCloneChecked && ( elem.nodeType === 1 || elem.nodeType === 11 ) && - !jQuery.isXMLDoc( elem ) ) { - - // We eschew Sizzle here for performance reasons: https://jsperf.com/getall-vs-sizzle/2 - destElements = getAll( clone ); - srcElements = getAll( elem ); - - for ( i = 0, l = srcElements.length; i < l; i++ ) { - fixInput( srcElements[ i ], destElements[ i ] ); - } - } - - // Copy the events from the original to the clone - if ( dataAndEvents ) { - if ( deepDataAndEvents ) { - srcElements = srcElements || getAll( elem ); - destElements = destElements || getAll( clone ); - - for ( i = 0, l = srcElements.length; i < l; i++ ) { - cloneCopyEvent( srcElements[ i ], destElements[ i ] ); - } - } else { - cloneCopyEvent( elem, clone ); - } - } - - // Preserve script evaluation history - destElements = getAll( clone, "script" ); - if ( destElements.length > 0 ) { - setGlobalEval( destElements, !inPage && getAll( elem, "script" ) ); - } - - // Return the cloned set - return clone; - }, - - cleanData: function( elems ) { - var data, elem, type, - special = jQuery.event.special, - i = 0; - - for ( ; ( elem = elems[ i ] ) !== undefined; i++ ) { - if ( acceptData( elem ) ) { - if ( ( data = elem[ dataPriv.expando ] ) ) { - if ( data.events ) { - for ( type in data.events ) { - if ( special[ type ] ) { - jQuery.event.remove( elem, type ); - - // This is a shortcut to avoid jQuery.event.remove's overhead - } else { - jQuery.removeEvent( elem, type, data.handle ); - } - } - } - - // Support: Chrome <=35 - 45+ - // Assign undefined instead of using delete, see Data#remove - elem[ dataPriv.expando ] = undefined; - } - if ( elem[ dataUser.expando ] ) { - - // Support: Chrome <=35 - 45+ - // Assign undefined instead of using delete, see Data#remove - elem[ dataUser.expando ] = undefined; - } - } - } - } -} ); - -jQuery.fn.extend( { - detach: function( selector ) { - return remove( this, selector, true ); - }, - - remove: function( selector ) { - return remove( this, selector ); - }, - - text: function( value ) { - return access( this, function( value ) { - return value === undefined ? - jQuery.text( this ) : - this.empty().each( function() { - if ( this.nodeType === 1 || this.nodeType === 11 || this.nodeType === 9 ) { - this.textContent = value; - } - } ); - }, null, value, arguments.length ); - }, - - append: function() { - return domManip( this, arguments, function( elem ) { - if ( this.nodeType === 1 || this.nodeType === 11 || this.nodeType === 9 ) { - var target = manipulationTarget( this, elem ); - target.appendChild( elem ); - } - } ); - }, - - prepend: function() { - return domManip( this, arguments, function( elem ) { - if ( this.nodeType === 1 || this.nodeType === 11 || this.nodeType === 9 ) { - var target = manipulationTarget( this, elem ); - target.insertBefore( elem, target.firstChild ); - } - } ); - }, - - before: function() { - return domManip( this, arguments, function( elem ) { - if ( this.parentNode ) { - this.parentNode.insertBefore( elem, this ); - } - } ); - }, - - after: function() { - return domManip( this, arguments, function( elem ) { - if ( this.parentNode ) { - this.parentNode.insertBefore( elem, this.nextSibling ); - } - } ); - }, - - empty: function() { - var elem, - i = 0; - - for ( ; ( elem = this[ i ] ) != null; i++ ) { - if ( elem.nodeType === 1 ) { - - // Prevent memory leaks - jQuery.cleanData( getAll( elem, false ) ); - - // Remove any remaining nodes - elem.textContent = ""; - } - } - - return this; - }, - - clone: function( dataAndEvents, deepDataAndEvents ) { - dataAndEvents = dataAndEvents == null ? false : dataAndEvents; - deepDataAndEvents = deepDataAndEvents == null ? dataAndEvents : deepDataAndEvents; - - return this.map( function() { - return jQuery.clone( this, dataAndEvents, deepDataAndEvents ); - } ); - }, - - html: function( value ) { - return access( this, function( value ) { - var elem = this[ 0 ] || {}, - i = 0, - l = this.length; - - if ( value === undefined && elem.nodeType === 1 ) { - return elem.innerHTML; - } - - // See if we can take a shortcut and just use innerHTML - if ( typeof value === "string" && !rnoInnerhtml.test( value ) && - !wrapMap[ ( rtagName.exec( value ) || [ "", "" ] )[ 1 ].toLowerCase() ] ) { - - value = jQuery.htmlPrefilter( value ); - - try { - for ( ; i < l; i++ ) { - elem = this[ i ] || {}; - - // Remove element nodes and prevent memory leaks - if ( elem.nodeType === 1 ) { - jQuery.cleanData( getAll( elem, false ) ); - elem.innerHTML = value; - } - } - - elem = 0; - - // If using innerHTML throws an exception, use the fallback method - } catch ( e ) {} - } - - if ( elem ) { - this.empty().append( value ); - } - }, null, value, arguments.length ); - }, - - replaceWith: function() { - var ignored = []; - - // Make the changes, replacing each non-ignored context element with the new content - return domManip( this, arguments, function( elem ) { - var parent = this.parentNode; - - if ( jQuery.inArray( this, ignored ) < 0 ) { - jQuery.cleanData( getAll( this ) ); - if ( parent ) { - parent.replaceChild( elem, this ); - } - } - - // Force callback invocation - }, ignored ); - } -} ); - -jQuery.each( { - appendTo: "append", - prependTo: "prepend", - insertBefore: "before", - insertAfter: "after", - replaceAll: "replaceWith" -}, function( name, original ) { - jQuery.fn[ name ] = function( selector ) { - var elems, - ret = [], - insert = jQuery( selector ), - last = insert.length - 1, - i = 0; - - for ( ; i <= last; i++ ) { - elems = i === last ? this : this.clone( true ); - jQuery( insert[ i ] )[ original ]( elems ); - - // Support: Android <=4.0 only, PhantomJS 1 only - // .get() because push.apply(_, arraylike) throws on ancient WebKit - push.apply( ret, elems.get() ); - } - - return this.pushStack( ret ); - }; -} ); -var rmargin = ( /^margin/ ); - -var rnumnonpx = new RegExp( "^(" + pnum + ")(?!px)[a-z%]+$", "i" ); - -var getStyles = function( elem ) { - - // Support: IE <=11 only, Firefox <=30 (#15098, #14150) - // IE throws on elements created in popups - // FF meanwhile throws on frame elements through "defaultView.getComputedStyle" - var view = elem.ownerDocument.defaultView; - - if ( !view || !view.opener ) { - view = window; - } - - return view.getComputedStyle( elem ); - }; - - - -( function() { - - // Executing both pixelPosition & boxSizingReliable tests require only one layout - // so they're executed at the same time to save the second computation. - function computeStyleTests() { - - // This is a singleton, we need to execute it only once - if ( !div ) { - return; - } - - div.style.cssText = - "box-sizing:border-box;" + - "position:relative;display:block;" + - "margin:auto;border:1px;padding:1px;" + - "top:1%;width:50%"; - div.innerHTML = ""; - documentElement.appendChild( container ); - - var divStyle = window.getComputedStyle( div ); - pixelPositionVal = divStyle.top !== "1%"; - - // Support: Android 4.0 - 4.3 only, Firefox <=3 - 44 - reliableMarginLeftVal = divStyle.marginLeft === "2px"; - boxSizingReliableVal = divStyle.width === "4px"; - - // Support: Android 4.0 - 4.3 only - // Some styles come back with percentage values, even though they shouldn't - div.style.marginRight = "50%"; - pixelMarginRightVal = divStyle.marginRight === "4px"; - - documentElement.removeChild( container ); - - // Nullify the div so it wouldn't be stored in the memory and - // it will also be a sign that checks already performed - div = null; - } - - var pixelPositionVal, boxSizingReliableVal, pixelMarginRightVal, reliableMarginLeftVal, - container = document.createElement( "div" ), - div = document.createElement( "div" ); - - // Finish early in limited (non-browser) environments - if ( !div.style ) { - return; - } - - // Support: IE <=9 - 11 only - // Style of cloned element affects source element cloned (#8908) - div.style.backgroundClip = "content-box"; - div.cloneNode( true ).style.backgroundClip = ""; - support.clearCloneStyle = div.style.backgroundClip === "content-box"; - - container.style.cssText = "border:0;width:8px;height:0;top:0;left:-9999px;" + - "padding:0;margin-top:1px;position:absolute"; - container.appendChild( div ); - - jQuery.extend( support, { - pixelPosition: function() { - computeStyleTests(); - return pixelPositionVal; - }, - boxSizingReliable: function() { - computeStyleTests(); - return boxSizingReliableVal; - }, - pixelMarginRight: function() { - computeStyleTests(); - return pixelMarginRightVal; - }, - reliableMarginLeft: function() { - computeStyleTests(); - return reliableMarginLeftVal; - } - } ); -} )(); - - -function curCSS( elem, name, computed ) { - var width, minWidth, maxWidth, ret, - - // Support: Firefox 51+ - // Retrieving style before computed somehow - // fixes an issue with getting wrong values - // on detached elements - style = elem.style; - - computed = computed || getStyles( elem ); - - // getPropertyValue is needed for: - // .css('filter') (IE 9 only, #12537) - // .css('--customProperty) (#3144) - if ( computed ) { - ret = computed.getPropertyValue( name ) || computed[ name ]; - - if ( ret === "" && !jQuery.contains( elem.ownerDocument, elem ) ) { - ret = jQuery.style( elem, name ); - } - - // A tribute to the "awesome hack by Dean Edwards" - // Android Browser returns percentage for some values, - // but width seems to be reliably pixels. - // This is against the CSSOM draft spec: - // https://drafts.csswg.org/cssom/#resolved-values - if ( !support.pixelMarginRight() && rnumnonpx.test( ret ) && rmargin.test( name ) ) { - - // Remember the original values - width = style.width; - minWidth = style.minWidth; - maxWidth = style.maxWidth; - - // Put in the new values to get a computed value out - style.minWidth = style.maxWidth = style.width = ret; - ret = computed.width; - - // Revert the changed values - style.width = width; - style.minWidth = minWidth; - style.maxWidth = maxWidth; - } - } - - return ret !== undefined ? - - // Support: IE <=9 - 11 only - // IE returns zIndex value as an integer. - ret + "" : - ret; -} - - -function addGetHookIf( conditionFn, hookFn ) { - - // Define the hook, we'll check on the first run if it's really needed. - return { - get: function() { - if ( conditionFn() ) { - - // Hook not needed (or it's not possible to use it due - // to missing dependency), remove it. - delete this.get; - return; - } - - // Hook needed; redefine it so that the support test is not executed again. - return ( this.get = hookFn ).apply( this, arguments ); - } - }; -} - - -var - - // Swappable if display is none or starts with table - // except "table", "table-cell", or "table-caption" - // See here for display values: https://developer.mozilla.org/en-US/docs/CSS/display - rdisplayswap = /^(none|table(?!-c[ea]).+)/, - rcustomProp = /^--/, - cssShow = { position: "absolute", visibility: "hidden", display: "block" }, - cssNormalTransform = { - letterSpacing: "0", - fontWeight: "400" - }, - - cssPrefixes = [ "Webkit", "Moz", "ms" ], - emptyStyle = document.createElement( "div" ).style; - -// Return a css property mapped to a potentially vendor prefixed property -function vendorPropName( name ) { - - // Shortcut for names that are not vendor prefixed - if ( name in emptyStyle ) { - return name; - } - - // Check for vendor prefixed names - var capName = name[ 0 ].toUpperCase() + name.slice( 1 ), - i = cssPrefixes.length; - - while ( i-- ) { - name = cssPrefixes[ i ] + capName; - if ( name in emptyStyle ) { - return name; - } - } -} - -// Return a property mapped along what jQuery.cssProps suggests or to -// a vendor prefixed property. -function finalPropName( name ) { - var ret = jQuery.cssProps[ name ]; - if ( !ret ) { - ret = jQuery.cssProps[ name ] = vendorPropName( name ) || name; - } - return ret; -} - -function setPositiveNumber( elem, value, subtract ) { - - // Any relative (+/-) values have already been - // normalized at this point - var matches = rcssNum.exec( value ); - return matches ? - - // Guard against undefined "subtract", e.g., when used as in cssHooks - Math.max( 0, matches[ 2 ] - ( subtract || 0 ) ) + ( matches[ 3 ] || "px" ) : - value; -} - -function augmentWidthOrHeight( elem, name, extra, isBorderBox, styles ) { - var i, - val = 0; - - // If we already have the right measurement, avoid augmentation - if ( extra === ( isBorderBox ? "border" : "content" ) ) { - i = 4; - - // Otherwise initialize for horizontal or vertical properties - } else { - i = name === "width" ? 1 : 0; - } - - for ( ; i < 4; i += 2 ) { - - // Both box models exclude margin, so add it if we want it - if ( extra === "margin" ) { - val += jQuery.css( elem, extra + cssExpand[ i ], true, styles ); - } - - if ( isBorderBox ) { - - // border-box includes padding, so remove it if we want content - if ( extra === "content" ) { - val -= jQuery.css( elem, "padding" + cssExpand[ i ], true, styles ); - } - - // At this point, extra isn't border nor margin, so remove border - if ( extra !== "margin" ) { - val -= jQuery.css( elem, "border" + cssExpand[ i ] + "Width", true, styles ); - } - } else { - - // At this point, extra isn't content, so add padding - val += jQuery.css( elem, "padding" + cssExpand[ i ], true, styles ); - - // At this point, extra isn't content nor padding, so add border - if ( extra !== "padding" ) { - val += jQuery.css( elem, "border" + cssExpand[ i ] + "Width", true, styles ); - } - } - } - - return val; -} - -function getWidthOrHeight( elem, name, extra ) { - - // Start with computed style - var valueIsBorderBox, - styles = getStyles( elem ), - val = curCSS( elem, name, styles ), - isBorderBox = jQuery.css( elem, "boxSizing", false, styles ) === "border-box"; - - // Computed unit is not pixels. Stop here and return. - if ( rnumnonpx.test( val ) ) { - return val; - } - - // Check for style in case a browser which returns unreliable values - // for getComputedStyle silently falls back to the reliable elem.style - valueIsBorderBox = isBorderBox && - ( support.boxSizingReliable() || val === elem.style[ name ] ); - - // Fall back to offsetWidth/Height when value is "auto" - // This happens for inline elements with no explicit setting (gh-3571) - if ( val === "auto" ) { - val = elem[ "offset" + name[ 0 ].toUpperCase() + name.slice( 1 ) ]; - } - - // Normalize "", auto, and prepare for extra - val = parseFloat( val ) || 0; - - // Use the active box-sizing model to add/subtract irrelevant styles - return ( val + - augmentWidthOrHeight( - elem, - name, - extra || ( isBorderBox ? "border" : "content" ), - valueIsBorderBox, - styles - ) - ) + "px"; -} - -jQuery.extend( { - - // Add in style property hooks for overriding the default - // behavior of getting and setting a style property - cssHooks: { - opacity: { - get: function( elem, computed ) { - if ( computed ) { - - // We should always get a number back from opacity - var ret = curCSS( elem, "opacity" ); - return ret === "" ? "1" : ret; - } - } - } - }, - - // Don't automatically add "px" to these possibly-unitless properties - cssNumber: { - "animationIterationCount": true, - "columnCount": true, - "fillOpacity": true, - "flexGrow": true, - "flexShrink": true, - "fontWeight": true, - "lineHeight": true, - "opacity": true, - "order": true, - "orphans": true, - "widows": true, - "zIndex": true, - "zoom": true - }, - - // Add in properties whose names you wish to fix before - // setting or getting the value - cssProps: { - "float": "cssFloat" - }, - - // Get and set the style property on a DOM Node - style: function( elem, name, value, extra ) { - - // Don't set styles on text and comment nodes - if ( !elem || elem.nodeType === 3 || elem.nodeType === 8 || !elem.style ) { - return; - } - - // Make sure that we're working with the right name - var ret, type, hooks, - origName = jQuery.camelCase( name ), - isCustomProp = rcustomProp.test( name ), - style = elem.style; - - // Make sure that we're working with the right name. We don't - // want to query the value if it is a CSS custom property - // since they are user-defined. - if ( !isCustomProp ) { - name = finalPropName( origName ); - } - - // Gets hook for the prefixed version, then unprefixed version - hooks = jQuery.cssHooks[ name ] || jQuery.cssHooks[ origName ]; - - // Check if we're setting a value - if ( value !== undefined ) { - type = typeof value; - - // Convert "+=" or "-=" to relative numbers (#7345) - if ( type === "string" && ( ret = rcssNum.exec( value ) ) && ret[ 1 ] ) { - value = adjustCSS( elem, name, ret ); - - // Fixes bug #9237 - type = "number"; - } - - // Make sure that null and NaN values aren't set (#7116) - if ( value == null || value !== value ) { - return; - } - - // If a number was passed in, add the unit (except for certain CSS properties) - if ( type === "number" ) { - value += ret && ret[ 3 ] || ( jQuery.cssNumber[ origName ] ? "" : "px" ); - } - - // background-* props affect original clone's values - if ( !support.clearCloneStyle && value === "" && name.indexOf( "background" ) === 0 ) { - style[ name ] = "inherit"; - } - - // If a hook was provided, use that value, otherwise just set the specified value - if ( !hooks || !( "set" in hooks ) || - ( value = hooks.set( elem, value, extra ) ) !== undefined ) { - - if ( isCustomProp ) { - style.setProperty( name, value ); - } else { - style[ name ] = value; - } - } - - } else { - - // If a hook was provided get the non-computed value from there - if ( hooks && "get" in hooks && - ( ret = hooks.get( elem, false, extra ) ) !== undefined ) { - - return ret; - } - - // Otherwise just get the value from the style object - return style[ name ]; - } - }, - - css: function( elem, name, extra, styles ) { - var val, num, hooks, - origName = jQuery.camelCase( name ), - isCustomProp = rcustomProp.test( name ); - - // Make sure that we're working with the right name. We don't - // want to modify the value if it is a CSS custom property - // since they are user-defined. - if ( !isCustomProp ) { - name = finalPropName( origName ); - } - - // Try prefixed name followed by the unprefixed name - hooks = jQuery.cssHooks[ name ] || jQuery.cssHooks[ origName ]; - - // If a hook was provided get the computed value from there - if ( hooks && "get" in hooks ) { - val = hooks.get( elem, true, extra ); - } - - // Otherwise, if a way to get the computed value exists, use that - if ( val === undefined ) { - val = curCSS( elem, name, styles ); - } - - // Convert "normal" to computed value - if ( val === "normal" && name in cssNormalTransform ) { - val = cssNormalTransform[ name ]; - } - - // Make numeric if forced or a qualifier was provided and val looks numeric - if ( extra === "" || extra ) { - num = parseFloat( val ); - return extra === true || isFinite( num ) ? num || 0 : val; - } - - return val; - } -} ); - -jQuery.each( [ "height", "width" ], function( i, name ) { - jQuery.cssHooks[ name ] = { - get: function( elem, computed, extra ) { - if ( computed ) { - - // Certain elements can have dimension info if we invisibly show them - // but it must have a current display style that would benefit - return rdisplayswap.test( jQuery.css( elem, "display" ) ) && - - // Support: Safari 8+ - // Table columns in Safari have non-zero offsetWidth & zero - // getBoundingClientRect().width unless display is changed. - // Support: IE <=11 only - // Running getBoundingClientRect on a disconnected node - // in IE throws an error. - ( !elem.getClientRects().length || !elem.getBoundingClientRect().width ) ? - swap( elem, cssShow, function() { - return getWidthOrHeight( elem, name, extra ); - } ) : - getWidthOrHeight( elem, name, extra ); - } - }, - - set: function( elem, value, extra ) { - var matches, - styles = extra && getStyles( elem ), - subtract = extra && augmentWidthOrHeight( - elem, - name, - extra, - jQuery.css( elem, "boxSizing", false, styles ) === "border-box", - styles - ); - - // Convert to pixels if value adjustment is needed - if ( subtract && ( matches = rcssNum.exec( value ) ) && - ( matches[ 3 ] || "px" ) !== "px" ) { - - elem.style[ name ] = value; - value = jQuery.css( elem, name ); - } - - return setPositiveNumber( elem, value, subtract ); - } - }; -} ); - -jQuery.cssHooks.marginLeft = addGetHookIf( support.reliableMarginLeft, - function( elem, computed ) { - if ( computed ) { - return ( parseFloat( curCSS( elem, "marginLeft" ) ) || - elem.getBoundingClientRect().left - - swap( elem, { marginLeft: 0 }, function() { - return elem.getBoundingClientRect().left; - } ) - ) + "px"; - } - } -); - -// These hooks are used by animate to expand properties -jQuery.each( { - margin: "", - padding: "", - border: "Width" -}, function( prefix, suffix ) { - jQuery.cssHooks[ prefix + suffix ] = { - expand: function( value ) { - var i = 0, - expanded = {}, - - // Assumes a single number if not a string - parts = typeof value === "string" ? value.split( " " ) : [ value ]; - - for ( ; i < 4; i++ ) { - expanded[ prefix + cssExpand[ i ] + suffix ] = - parts[ i ] || parts[ i - 2 ] || parts[ 0 ]; - } - - return expanded; - } - }; - - if ( !rmargin.test( prefix ) ) { - jQuery.cssHooks[ prefix + suffix ].set = setPositiveNumber; - } -} ); - -jQuery.fn.extend( { - css: function( name, value ) { - return access( this, function( elem, name, value ) { - var styles, len, - map = {}, - i = 0; - - if ( Array.isArray( name ) ) { - styles = getStyles( elem ); - len = name.length; - - for ( ; i < len; i++ ) { - map[ name[ i ] ] = jQuery.css( elem, name[ i ], false, styles ); - } - - return map; - } - - return value !== undefined ? - jQuery.style( elem, name, value ) : - jQuery.css( elem, name ); - }, name, value, arguments.length > 1 ); - } -} ); - - -function Tween( elem, options, prop, end, easing ) { - return new Tween.prototype.init( elem, options, prop, end, easing ); -} -jQuery.Tween = Tween; - -Tween.prototype = { - constructor: Tween, - init: function( elem, options, prop, end, easing, unit ) { - this.elem = elem; - this.prop = prop; - this.easing = easing || jQuery.easing._default; - this.options = options; - this.start = this.now = this.cur(); - this.end = end; - this.unit = unit || ( jQuery.cssNumber[ prop ] ? "" : "px" ); - }, - cur: function() { - var hooks = Tween.propHooks[ this.prop ]; - - return hooks && hooks.get ? - hooks.get( this ) : - Tween.propHooks._default.get( this ); - }, - run: function( percent ) { - var eased, - hooks = Tween.propHooks[ this.prop ]; - - if ( this.options.duration ) { - this.pos = eased = jQuery.easing[ this.easing ]( - percent, this.options.duration * percent, 0, 1, this.options.duration - ); - } else { - this.pos = eased = percent; - } - this.now = ( this.end - this.start ) * eased + this.start; - - if ( this.options.step ) { - this.options.step.call( this.elem, this.now, this ); - } - - if ( hooks && hooks.set ) { - hooks.set( this ); - } else { - Tween.propHooks._default.set( this ); - } - return this; - } -}; - -Tween.prototype.init.prototype = Tween.prototype; - -Tween.propHooks = { - _default: { - get: function( tween ) { - var result; - - // Use a property on the element directly when it is not a DOM element, - // or when there is no matching style property that exists. - if ( tween.elem.nodeType !== 1 || - tween.elem[ tween.prop ] != null && tween.elem.style[ tween.prop ] == null ) { - return tween.elem[ tween.prop ]; - } - - // Passing an empty string as a 3rd parameter to .css will automatically - // attempt a parseFloat and fallback to a string if the parse fails. - // Simple values such as "10px" are parsed to Float; - // complex values such as "rotate(1rad)" are returned as-is. - result = jQuery.css( tween.elem, tween.prop, "" ); - - // Empty strings, null, undefined and "auto" are converted to 0. - return !result || result === "auto" ? 0 : result; - }, - set: function( tween ) { - - // Use step hook for back compat. - // Use cssHook if its there. - // Use .style if available and use plain properties where available. - if ( jQuery.fx.step[ tween.prop ] ) { - jQuery.fx.step[ tween.prop ]( tween ); - } else if ( tween.elem.nodeType === 1 && - ( tween.elem.style[ jQuery.cssProps[ tween.prop ] ] != null || - jQuery.cssHooks[ tween.prop ] ) ) { - jQuery.style( tween.elem, tween.prop, tween.now + tween.unit ); - } else { - tween.elem[ tween.prop ] = tween.now; - } - } - } -}; - -// Support: IE <=9 only -// Panic based approach to setting things on disconnected nodes -Tween.propHooks.scrollTop = Tween.propHooks.scrollLeft = { - set: function( tween ) { - if ( tween.elem.nodeType && tween.elem.parentNode ) { - tween.elem[ tween.prop ] = tween.now; - } - } -}; - -jQuery.easing = { - linear: function( p ) { - return p; - }, - swing: function( p ) { - return 0.5 - Math.cos( p * Math.PI ) / 2; - }, - _default: "swing" -}; - -jQuery.fx = Tween.prototype.init; - -// Back compat <1.8 extension point -jQuery.fx.step = {}; - - - - -var - fxNow, inProgress, - rfxtypes = /^(?:toggle|show|hide)$/, - rrun = /queueHooks$/; - -function schedule() { - if ( inProgress ) { - if ( document.hidden === false && window.requestAnimationFrame ) { - window.requestAnimationFrame( schedule ); - } else { - window.setTimeout( schedule, jQuery.fx.interval ); - } - - jQuery.fx.tick(); - } -} - -// Animations created synchronously will run synchronously -function createFxNow() { - window.setTimeout( function() { - fxNow = undefined; - } ); - return ( fxNow = jQuery.now() ); -} - -// Generate parameters to create a standard animation -function genFx( type, includeWidth ) { - var which, - i = 0, - attrs = { height: type }; - - // If we include width, step value is 1 to do all cssExpand values, - // otherwise step value is 2 to skip over Left and Right - includeWidth = includeWidth ? 1 : 0; - for ( ; i < 4; i += 2 - includeWidth ) { - which = cssExpand[ i ]; - attrs[ "margin" + which ] = attrs[ "padding" + which ] = type; - } - - if ( includeWidth ) { - attrs.opacity = attrs.width = type; - } - - return attrs; -} - -function createTween( value, prop, animation ) { - var tween, - collection = ( Animation.tweeners[ prop ] || [] ).concat( Animation.tweeners[ "*" ] ), - index = 0, - length = collection.length; - for ( ; index < length; index++ ) { - if ( ( tween = collection[ index ].call( animation, prop, value ) ) ) { - - // We're done with this property - return tween; - } - } -} - -function defaultPrefilter( elem, props, opts ) { - var prop, value, toggle, hooks, oldfire, propTween, restoreDisplay, display, - isBox = "width" in props || "height" in props, - anim = this, - orig = {}, - style = elem.style, - hidden = elem.nodeType && isHiddenWithinTree( elem ), - dataShow = dataPriv.get( elem, "fxshow" ); - - // Queue-skipping animations hijack the fx hooks - if ( !opts.queue ) { - hooks = jQuery._queueHooks( elem, "fx" ); - if ( hooks.unqueued == null ) { - hooks.unqueued = 0; - oldfire = hooks.empty.fire; - hooks.empty.fire = function() { - if ( !hooks.unqueued ) { - oldfire(); - } - }; - } - hooks.unqueued++; - - anim.always( function() { - - // Ensure the complete handler is called before this completes - anim.always( function() { - hooks.unqueued--; - if ( !jQuery.queue( elem, "fx" ).length ) { - hooks.empty.fire(); - } - } ); - } ); - } - - // Detect show/hide animations - for ( prop in props ) { - value = props[ prop ]; - if ( rfxtypes.test( value ) ) { - delete props[ prop ]; - toggle = toggle || value === "toggle"; - if ( value === ( hidden ? "hide" : "show" ) ) { - - // Pretend to be hidden if this is a "show" and - // there is still data from a stopped show/hide - if ( value === "show" && dataShow && dataShow[ prop ] !== undefined ) { - hidden = true; - - // Ignore all other no-op show/hide data - } else { - continue; - } - } - orig[ prop ] = dataShow && dataShow[ prop ] || jQuery.style( elem, prop ); - } - } - - // Bail out if this is a no-op like .hide().hide() - propTween = !jQuery.isEmptyObject( props ); - if ( !propTween && jQuery.isEmptyObject( orig ) ) { - return; - } - - // Restrict "overflow" and "display" styles during box animations - if ( isBox && elem.nodeType === 1 ) { - - // Support: IE <=9 - 11, Edge 12 - 13 - // Record all 3 overflow attributes because IE does not infer the shorthand - // from identically-valued overflowX and overflowY - opts.overflow = [ style.overflow, style.overflowX, style.overflowY ]; - - // Identify a display type, preferring old show/hide data over the CSS cascade - restoreDisplay = dataShow && dataShow.display; - if ( restoreDisplay == null ) { - restoreDisplay = dataPriv.get( elem, "display" ); - } - display = jQuery.css( elem, "display" ); - if ( display === "none" ) { - if ( restoreDisplay ) { - display = restoreDisplay; - } else { - - // Get nonempty value(s) by temporarily forcing visibility - showHide( [ elem ], true ); - restoreDisplay = elem.style.display || restoreDisplay; - display = jQuery.css( elem, "display" ); - showHide( [ elem ] ); - } - } - - // Animate inline elements as inline-block - if ( display === "inline" || display === "inline-block" && restoreDisplay != null ) { - if ( jQuery.css( elem, "float" ) === "none" ) { - - // Restore the original display value at the end of pure show/hide animations - if ( !propTween ) { - anim.done( function() { - style.display = restoreDisplay; - } ); - if ( restoreDisplay == null ) { - display = style.display; - restoreDisplay = display === "none" ? "" : display; - } - } - style.display = "inline-block"; - } - } - } - - if ( opts.overflow ) { - style.overflow = "hidden"; - anim.always( function() { - style.overflow = opts.overflow[ 0 ]; - style.overflowX = opts.overflow[ 1 ]; - style.overflowY = opts.overflow[ 2 ]; - } ); - } - - // Implement show/hide animations - propTween = false; - for ( prop in orig ) { - - // General show/hide setup for this element animation - if ( !propTween ) { - if ( dataShow ) { - if ( "hidden" in dataShow ) { - hidden = dataShow.hidden; - } - } else { - dataShow = dataPriv.access( elem, "fxshow", { display: restoreDisplay } ); - } - - // Store hidden/visible for toggle so `.stop().toggle()` "reverses" - if ( toggle ) { - dataShow.hidden = !hidden; - } - - // Show elements before animating them - if ( hidden ) { - showHide( [ elem ], true ); - } - - /* eslint-disable no-loop-func */ - - anim.done( function() { - - /* eslint-enable no-loop-func */ - - // The final step of a "hide" animation is actually hiding the element - if ( !hidden ) { - showHide( [ elem ] ); - } - dataPriv.remove( elem, "fxshow" ); - for ( prop in orig ) { - jQuery.style( elem, prop, orig[ prop ] ); - } - } ); - } - - // Per-property setup - propTween = createTween( hidden ? dataShow[ prop ] : 0, prop, anim ); - if ( !( prop in dataShow ) ) { - dataShow[ prop ] = propTween.start; - if ( hidden ) { - propTween.end = propTween.start; - propTween.start = 0; - } - } - } -} - -function propFilter( props, specialEasing ) { - var index, name, easing, value, hooks; - - // camelCase, specialEasing and expand cssHook pass - for ( index in props ) { - name = jQuery.camelCase( index ); - easing = specialEasing[ name ]; - value = props[ index ]; - if ( Array.isArray( value ) ) { - easing = value[ 1 ]; - value = props[ index ] = value[ 0 ]; - } - - if ( index !== name ) { - props[ name ] = value; - delete props[ index ]; - } - - hooks = jQuery.cssHooks[ name ]; - if ( hooks && "expand" in hooks ) { - value = hooks.expand( value ); - delete props[ name ]; - - // Not quite $.extend, this won't overwrite existing keys. - // Reusing 'index' because we have the correct "name" - for ( index in value ) { - if ( !( index in props ) ) { - props[ index ] = value[ index ]; - specialEasing[ index ] = easing; - } - } - } else { - specialEasing[ name ] = easing; - } - } -} - -function Animation( elem, properties, options ) { - var result, - stopped, - index = 0, - length = Animation.prefilters.length, - deferred = jQuery.Deferred().always( function() { - - // Don't match elem in the :animated selector - delete tick.elem; - } ), - tick = function() { - if ( stopped ) { - return false; - } - var currentTime = fxNow || createFxNow(), - remaining = Math.max( 0, animation.startTime + animation.duration - currentTime ), - - // Support: Android 2.3 only - // Archaic crash bug won't allow us to use `1 - ( 0.5 || 0 )` (#12497) - temp = remaining / animation.duration || 0, - percent = 1 - temp, - index = 0, - length = animation.tweens.length; - - for ( ; index < length; index++ ) { - animation.tweens[ index ].run( percent ); - } - - deferred.notifyWith( elem, [ animation, percent, remaining ] ); - - // If there's more to do, yield - if ( percent < 1 && length ) { - return remaining; - } - - // If this was an empty animation, synthesize a final progress notification - if ( !length ) { - deferred.notifyWith( elem, [ animation, 1, 0 ] ); - } - - // Resolve the animation and report its conclusion - deferred.resolveWith( elem, [ animation ] ); - return false; - }, - animation = deferred.promise( { - elem: elem, - props: jQuery.extend( {}, properties ), - opts: jQuery.extend( true, { - specialEasing: {}, - easing: jQuery.easing._default - }, options ), - originalProperties: properties, - originalOptions: options, - startTime: fxNow || createFxNow(), - duration: options.duration, - tweens: [], - createTween: function( prop, end ) { - var tween = jQuery.Tween( elem, animation.opts, prop, end, - animation.opts.specialEasing[ prop ] || animation.opts.easing ); - animation.tweens.push( tween ); - return tween; - }, - stop: function( gotoEnd ) { - var index = 0, - - // If we are going to the end, we want to run all the tweens - // otherwise we skip this part - length = gotoEnd ? animation.tweens.length : 0; - if ( stopped ) { - return this; - } - stopped = true; - for ( ; index < length; index++ ) { - animation.tweens[ index ].run( 1 ); - } - - // Resolve when we played the last frame; otherwise, reject - if ( gotoEnd ) { - deferred.notifyWith( elem, [ animation, 1, 0 ] ); - deferred.resolveWith( elem, [ animation, gotoEnd ] ); - } else { - deferred.rejectWith( elem, [ animation, gotoEnd ] ); - } - return this; - } - } ), - props = animation.props; - - propFilter( props, animation.opts.specialEasing ); - - for ( ; index < length; index++ ) { - result = Animation.prefilters[ index ].call( animation, elem, props, animation.opts ); - if ( result ) { - if ( jQuery.isFunction( result.stop ) ) { - jQuery._queueHooks( animation.elem, animation.opts.queue ).stop = - jQuery.proxy( result.stop, result ); - } - return result; - } - } - - jQuery.map( props, createTween, animation ); - - if ( jQuery.isFunction( animation.opts.start ) ) { - animation.opts.start.call( elem, animation ); - } - - // Attach callbacks from options - animation - .progress( animation.opts.progress ) - .done( animation.opts.done, animation.opts.complete ) - .fail( animation.opts.fail ) - .always( animation.opts.always ); - - jQuery.fx.timer( - jQuery.extend( tick, { - elem: elem, - anim: animation, - queue: animation.opts.queue - } ) - ); - - return animation; -} - -jQuery.Animation = jQuery.extend( Animation, { - - tweeners: { - "*": [ function( prop, value ) { - var tween = this.createTween( prop, value ); - adjustCSS( tween.elem, prop, rcssNum.exec( value ), tween ); - return tween; - } ] - }, - - tweener: function( props, callback ) { - if ( jQuery.isFunction( props ) ) { - callback = props; - props = [ "*" ]; - } else { - props = props.match( rnothtmlwhite ); - } - - var prop, - index = 0, - length = props.length; - - for ( ; index < length; index++ ) { - prop = props[ index ]; - Animation.tweeners[ prop ] = Animation.tweeners[ prop ] || []; - Animation.tweeners[ prop ].unshift( callback ); - } - }, - - prefilters: [ defaultPrefilter ], - - prefilter: function( callback, prepend ) { - if ( prepend ) { - Animation.prefilters.unshift( callback ); - } else { - Animation.prefilters.push( callback ); - } - } -} ); - -jQuery.speed = function( speed, easing, fn ) { - var opt = speed && typeof speed === "object" ? jQuery.extend( {}, speed ) : { - complete: fn || !fn && easing || - jQuery.isFunction( speed ) && speed, - duration: speed, - easing: fn && easing || easing && !jQuery.isFunction( easing ) && easing - }; - - // Go to the end state if fx are off - if ( jQuery.fx.off ) { - opt.duration = 0; - - } else { - if ( typeof opt.duration !== "number" ) { - if ( opt.duration in jQuery.fx.speeds ) { - opt.duration = jQuery.fx.speeds[ opt.duration ]; - - } else { - opt.duration = jQuery.fx.speeds._default; - } - } - } - - // Normalize opt.queue - true/undefined/null -> "fx" - if ( opt.queue == null || opt.queue === true ) { - opt.queue = "fx"; - } - - // Queueing - opt.old = opt.complete; - - opt.complete = function() { - if ( jQuery.isFunction( opt.old ) ) { - opt.old.call( this ); - } - - if ( opt.queue ) { - jQuery.dequeue( this, opt.queue ); - } - }; - - return opt; -}; - -jQuery.fn.extend( { - fadeTo: function( speed, to, easing, callback ) { - - // Show any hidden elements after setting opacity to 0 - return this.filter( isHiddenWithinTree ).css( "opacity", 0 ).show() - - // Animate to the value specified - .end().animate( { opacity: to }, speed, easing, callback ); - }, - animate: function( prop, speed, easing, callback ) { - var empty = jQuery.isEmptyObject( prop ), - optall = jQuery.speed( speed, easing, callback ), - doAnimation = function() { - - // Operate on a copy of prop so per-property easing won't be lost - var anim = Animation( this, jQuery.extend( {}, prop ), optall ); - - // Empty animations, or finishing resolves immediately - if ( empty || dataPriv.get( this, "finish" ) ) { - anim.stop( true ); - } - }; - doAnimation.finish = doAnimation; - - return empty || optall.queue === false ? - this.each( doAnimation ) : - this.queue( optall.queue, doAnimation ); - }, - stop: function( type, clearQueue, gotoEnd ) { - var stopQueue = function( hooks ) { - var stop = hooks.stop; - delete hooks.stop; - stop( gotoEnd ); - }; - - if ( typeof type !== "string" ) { - gotoEnd = clearQueue; - clearQueue = type; - type = undefined; - } - if ( clearQueue && type !== false ) { - this.queue( type || "fx", [] ); - } - - return this.each( function() { - var dequeue = true, - index = type != null && type + "queueHooks", - timers = jQuery.timers, - data = dataPriv.get( this ); - - if ( index ) { - if ( data[ index ] && data[ index ].stop ) { - stopQueue( data[ index ] ); - } - } else { - for ( index in data ) { - if ( data[ index ] && data[ index ].stop && rrun.test( index ) ) { - stopQueue( data[ index ] ); - } - } - } - - for ( index = timers.length; index--; ) { - if ( timers[ index ].elem === this && - ( type == null || timers[ index ].queue === type ) ) { - - timers[ index ].anim.stop( gotoEnd ); - dequeue = false; - timers.splice( index, 1 ); - } - } - - // Start the next in the queue if the last step wasn't forced. - // Timers currently will call their complete callbacks, which - // will dequeue but only if they were gotoEnd. - if ( dequeue || !gotoEnd ) { - jQuery.dequeue( this, type ); - } - } ); - }, - finish: function( type ) { - if ( type !== false ) { - type = type || "fx"; - } - return this.each( function() { - var index, - data = dataPriv.get( this ), - queue = data[ type + "queue" ], - hooks = data[ type + "queueHooks" ], - timers = jQuery.timers, - length = queue ? queue.length : 0; - - // Enable finishing flag on private data - data.finish = true; - - // Empty the queue first - jQuery.queue( this, type, [] ); - - if ( hooks && hooks.stop ) { - hooks.stop.call( this, true ); - } - - // Look for any active animations, and finish them - for ( index = timers.length; index--; ) { - if ( timers[ index ].elem === this && timers[ index ].queue === type ) { - timers[ index ].anim.stop( true ); - timers.splice( index, 1 ); - } - } - - // Look for any animations in the old queue and finish them - for ( index = 0; index < length; index++ ) { - if ( queue[ index ] && queue[ index ].finish ) { - queue[ index ].finish.call( this ); - } - } - - // Turn off finishing flag - delete data.finish; - } ); - } -} ); - -jQuery.each( [ "toggle", "show", "hide" ], function( i, name ) { - var cssFn = jQuery.fn[ name ]; - jQuery.fn[ name ] = function( speed, easing, callback ) { - return speed == null || typeof speed === "boolean" ? - cssFn.apply( this, arguments ) : - this.animate( genFx( name, true ), speed, easing, callback ); - }; -} ); - -// Generate shortcuts for custom animations -jQuery.each( { - slideDown: genFx( "show" ), - slideUp: genFx( "hide" ), - slideToggle: genFx( "toggle" ), - fadeIn: { opacity: "show" }, - fadeOut: { opacity: "hide" }, - fadeToggle: { opacity: "toggle" } -}, function( name, props ) { - jQuery.fn[ name ] = function( speed, easing, callback ) { - return this.animate( props, speed, easing, callback ); - }; -} ); - -jQuery.timers = []; -jQuery.fx.tick = function() { - var timer, - i = 0, - timers = jQuery.timers; - - fxNow = jQuery.now(); - - for ( ; i < timers.length; i++ ) { - timer = timers[ i ]; - - // Run the timer and safely remove it when done (allowing for external removal) - if ( !timer() && timers[ i ] === timer ) { - timers.splice( i--, 1 ); - } - } - - if ( !timers.length ) { - jQuery.fx.stop(); - } - fxNow = undefined; -}; - -jQuery.fx.timer = function( timer ) { - jQuery.timers.push( timer ); - jQuery.fx.start(); -}; - -jQuery.fx.interval = 13; -jQuery.fx.start = function() { - if ( inProgress ) { - return; - } - - inProgress = true; - schedule(); -}; - -jQuery.fx.stop = function() { - inProgress = null; -}; - -jQuery.fx.speeds = { - slow: 600, - fast: 200, - - // Default speed - _default: 400 -}; - - -// Based off of the plugin by Clint Helfers, with permission. -// https://web.archive.org/web/20100324014747/http://blindsignals.com/index.php/2009/07/jquery-delay/ -jQuery.fn.delay = function( time, type ) { - time = jQuery.fx ? jQuery.fx.speeds[ time ] || time : time; - type = type || "fx"; - - return this.queue( type, function( next, hooks ) { - var timeout = window.setTimeout( next, time ); - hooks.stop = function() { - window.clearTimeout( timeout ); - }; - } ); -}; - - -( function() { - var input = document.createElement( "input" ), - select = document.createElement( "select" ), - opt = select.appendChild( document.createElement( "option" ) ); - - input.type = "checkbox"; - - // Support: Android <=4.3 only - // Default value for a checkbox should be "on" - support.checkOn = input.value !== ""; - - // Support: IE <=11 only - // Must access selectedIndex to make default options select - support.optSelected = opt.selected; - - // Support: IE <=11 only - // An input loses its value after becoming a radio - input = document.createElement( "input" ); - input.value = "t"; - input.type = "radio"; - support.radioValue = input.value === "t"; -} )(); - - -var boolHook, - attrHandle = jQuery.expr.attrHandle; - -jQuery.fn.extend( { - attr: function( name, value ) { - return access( this, jQuery.attr, name, value, arguments.length > 1 ); - }, - - removeAttr: function( name ) { - return this.each( function() { - jQuery.removeAttr( this, name ); - } ); - } -} ); - -jQuery.extend( { - attr: function( elem, name, value ) { - var ret, hooks, - nType = elem.nodeType; - - // Don't get/set attributes on text, comment and attribute nodes - if ( nType === 3 || nType === 8 || nType === 2 ) { - return; - } - - // Fallback to prop when attributes are not supported - if ( typeof elem.getAttribute === "undefined" ) { - return jQuery.prop( elem, name, value ); - } - - // Attribute hooks are determined by the lowercase version - // Grab necessary hook if one is defined - if ( nType !== 1 || !jQuery.isXMLDoc( elem ) ) { - hooks = jQuery.attrHooks[ name.toLowerCase() ] || - ( jQuery.expr.match.bool.test( name ) ? boolHook : undefined ); - } - - if ( value !== undefined ) { - if ( value === null ) { - jQuery.removeAttr( elem, name ); - return; - } - - if ( hooks && "set" in hooks && - ( ret = hooks.set( elem, value, name ) ) !== undefined ) { - return ret; - } - - elem.setAttribute( name, value + "" ); - return value; - } - - if ( hooks && "get" in hooks && ( ret = hooks.get( elem, name ) ) !== null ) { - return ret; - } - - ret = jQuery.find.attr( elem, name ); - - // Non-existent attributes return null, we normalize to undefined - return ret == null ? undefined : ret; - }, - - attrHooks: { - type: { - set: function( elem, value ) { - if ( !support.radioValue && value === "radio" && - nodeName( elem, "input" ) ) { - var val = elem.value; - elem.setAttribute( "type", value ); - if ( val ) { - elem.value = val; - } - return value; - } - } - } - }, - - removeAttr: function( elem, value ) { - var name, - i = 0, - - // Attribute names can contain non-HTML whitespace characters - // https://html.spec.whatwg.org/multipage/syntax.html#attributes-2 - attrNames = value && value.match( rnothtmlwhite ); - - if ( attrNames && elem.nodeType === 1 ) { - while ( ( name = attrNames[ i++ ] ) ) { - elem.removeAttribute( name ); - } - } - } -} ); - -// Hooks for boolean attributes -boolHook = { - set: function( elem, value, name ) { - if ( value === false ) { - - // Remove boolean attributes when set to false - jQuery.removeAttr( elem, name ); - } else { - elem.setAttribute( name, name ); - } - return name; - } -}; - -jQuery.each( jQuery.expr.match.bool.source.match( /\w+/g ), function( i, name ) { - var getter = attrHandle[ name ] || jQuery.find.attr; - - attrHandle[ name ] = function( elem, name, isXML ) { - var ret, handle, - lowercaseName = name.toLowerCase(); - - if ( !isXML ) { - - // Avoid an infinite loop by temporarily removing this function from the getter - handle = attrHandle[ lowercaseName ]; - attrHandle[ lowercaseName ] = ret; - ret = getter( elem, name, isXML ) != null ? - lowercaseName : - null; - attrHandle[ lowercaseName ] = handle; - } - return ret; - }; -} ); - - - - -var rfocusable = /^(?:input|select|textarea|button)$/i, - rclickable = /^(?:a|area)$/i; - -jQuery.fn.extend( { - prop: function( name, value ) { - return access( this, jQuery.prop, name, value, arguments.length > 1 ); - }, - - removeProp: function( name ) { - return this.each( function() { - delete this[ jQuery.propFix[ name ] || name ]; - } ); - } -} ); - -jQuery.extend( { - prop: function( elem, name, value ) { - var ret, hooks, - nType = elem.nodeType; - - // Don't get/set properties on text, comment and attribute nodes - if ( nType === 3 || nType === 8 || nType === 2 ) { - return; - } - - if ( nType !== 1 || !jQuery.isXMLDoc( elem ) ) { - - // Fix name and attach hooks - name = jQuery.propFix[ name ] || name; - hooks = jQuery.propHooks[ name ]; - } - - if ( value !== undefined ) { - if ( hooks && "set" in hooks && - ( ret = hooks.set( elem, value, name ) ) !== undefined ) { - return ret; - } - - return ( elem[ name ] = value ); - } - - if ( hooks && "get" in hooks && ( ret = hooks.get( elem, name ) ) !== null ) { - return ret; - } - - return elem[ name ]; - }, - - propHooks: { - tabIndex: { - get: function( elem ) { - - // Support: IE <=9 - 11 only - // elem.tabIndex doesn't always return the - // correct value when it hasn't been explicitly set - // https://web.archive.org/web/20141116233347/http://fluidproject.org/blog/2008/01/09/getting-setting-and-removing-tabindex-values-with-javascript/ - // Use proper attribute retrieval(#12072) - var tabindex = jQuery.find.attr( elem, "tabindex" ); - - if ( tabindex ) { - return parseInt( tabindex, 10 ); - } - - if ( - rfocusable.test( elem.nodeName ) || - rclickable.test( elem.nodeName ) && - elem.href - ) { - return 0; - } - - return -1; - } - } - }, - - propFix: { - "for": "htmlFor", - "class": "className" - } -} ); - -// Support: IE <=11 only -// Accessing the selectedIndex property -// forces the browser to respect setting selected -// on the option -// The getter ensures a default option is selected -// when in an optgroup -// eslint rule "no-unused-expressions" is disabled for this code -// since it considers such accessions noop -if ( !support.optSelected ) { - jQuery.propHooks.selected = { - get: function( elem ) { - - /* eslint no-unused-expressions: "off" */ - - var parent = elem.parentNode; - if ( parent && parent.parentNode ) { - parent.parentNode.selectedIndex; - } - return null; - }, - set: function( elem ) { - - /* eslint no-unused-expressions: "off" */ - - var parent = elem.parentNode; - if ( parent ) { - parent.selectedIndex; - - if ( parent.parentNode ) { - parent.parentNode.selectedIndex; - } - } - } - }; -} - -jQuery.each( [ - "tabIndex", - "readOnly", - "maxLength", - "cellSpacing", - "cellPadding", - "rowSpan", - "colSpan", - "useMap", - "frameBorder", - "contentEditable" -], function() { - jQuery.propFix[ this.toLowerCase() ] = this; -} ); - - - - - // Strip and collapse whitespace according to HTML spec - // https://html.spec.whatwg.org/multipage/infrastructure.html#strip-and-collapse-whitespace - function stripAndCollapse( value ) { - var tokens = value.match( rnothtmlwhite ) || []; - return tokens.join( " " ); - } - - -function getClass( elem ) { - return elem.getAttribute && elem.getAttribute( "class" ) || ""; -} - -jQuery.fn.extend( { - addClass: function( value ) { - var classes, elem, cur, curValue, clazz, j, finalValue, - i = 0; - - if ( jQuery.isFunction( value ) ) { - return this.each( function( j ) { - jQuery( this ).addClass( value.call( this, j, getClass( this ) ) ); - } ); - } - - if ( typeof value === "string" && value ) { - classes = value.match( rnothtmlwhite ) || []; - - while ( ( elem = this[ i++ ] ) ) { - curValue = getClass( elem ); - cur = elem.nodeType === 1 && ( " " + stripAndCollapse( curValue ) + " " ); - - if ( cur ) { - j = 0; - while ( ( clazz = classes[ j++ ] ) ) { - if ( cur.indexOf( " " + clazz + " " ) < 0 ) { - cur += clazz + " "; - } - } - - // Only assign if different to avoid unneeded rendering. - finalValue = stripAndCollapse( cur ); - if ( curValue !== finalValue ) { - elem.setAttribute( "class", finalValue ); - } - } - } - } - - return this; - }, - - removeClass: function( value ) { - var classes, elem, cur, curValue, clazz, j, finalValue, - i = 0; - - if ( jQuery.isFunction( value ) ) { - return this.each( function( j ) { - jQuery( this ).removeClass( value.call( this, j, getClass( this ) ) ); - } ); - } - - if ( !arguments.length ) { - return this.attr( "class", "" ); - } - - if ( typeof value === "string" && value ) { - classes = value.match( rnothtmlwhite ) || []; - - while ( ( elem = this[ i++ ] ) ) { - curValue = getClass( elem ); - - // This expression is here for better compressibility (see addClass) - cur = elem.nodeType === 1 && ( " " + stripAndCollapse( curValue ) + " " ); - - if ( cur ) { - j = 0; - while ( ( clazz = classes[ j++ ] ) ) { - - // Remove *all* instances - while ( cur.indexOf( " " + clazz + " " ) > -1 ) { - cur = cur.replace( " " + clazz + " ", " " ); - } - } - - // Only assign if different to avoid unneeded rendering. - finalValue = stripAndCollapse( cur ); - if ( curValue !== finalValue ) { - elem.setAttribute( "class", finalValue ); - } - } - } - } - - return this; - }, - - toggleClass: function( value, stateVal ) { - var type = typeof value; - - if ( typeof stateVal === "boolean" && type === "string" ) { - return stateVal ? this.addClass( value ) : this.removeClass( value ); - } - - if ( jQuery.isFunction( value ) ) { - return this.each( function( i ) { - jQuery( this ).toggleClass( - value.call( this, i, getClass( this ), stateVal ), - stateVal - ); - } ); - } - - return this.each( function() { - var className, i, self, classNames; - - if ( type === "string" ) { - - // Toggle individual class names - i = 0; - self = jQuery( this ); - classNames = value.match( rnothtmlwhite ) || []; - - while ( ( className = classNames[ i++ ] ) ) { - - // Check each className given, space separated list - if ( self.hasClass( className ) ) { - self.removeClass( className ); - } else { - self.addClass( className ); - } - } - - // Toggle whole class name - } else if ( value === undefined || type === "boolean" ) { - className = getClass( this ); - if ( className ) { - - // Store className if set - dataPriv.set( this, "__className__", className ); - } - - // If the element has a class name or if we're passed `false`, - // then remove the whole classname (if there was one, the above saved it). - // Otherwise bring back whatever was previously saved (if anything), - // falling back to the empty string if nothing was stored. - if ( this.setAttribute ) { - this.setAttribute( "class", - className || value === false ? - "" : - dataPriv.get( this, "__className__" ) || "" - ); - } - } - } ); - }, - - hasClass: function( selector ) { - var className, elem, - i = 0; - - className = " " + selector + " "; - while ( ( elem = this[ i++ ] ) ) { - if ( elem.nodeType === 1 && - ( " " + stripAndCollapse( getClass( elem ) ) + " " ).indexOf( className ) > -1 ) { - return true; - } - } - - return false; - } -} ); - - - - -var rreturn = /\r/g; - -jQuery.fn.extend( { - val: function( value ) { - var hooks, ret, isFunction, - elem = this[ 0 ]; - - if ( !arguments.length ) { - if ( elem ) { - hooks = jQuery.valHooks[ elem.type ] || - jQuery.valHooks[ elem.nodeName.toLowerCase() ]; - - if ( hooks && - "get" in hooks && - ( ret = hooks.get( elem, "value" ) ) !== undefined - ) { - return ret; - } - - ret = elem.value; - - // Handle most common string cases - if ( typeof ret === "string" ) { - return ret.replace( rreturn, "" ); - } - - // Handle cases where value is null/undef or number - return ret == null ? "" : ret; - } - - return; - } - - isFunction = jQuery.isFunction( value ); - - return this.each( function( i ) { - var val; - - if ( this.nodeType !== 1 ) { - return; - } - - if ( isFunction ) { - val = value.call( this, i, jQuery( this ).val() ); - } else { - val = value; - } - - // Treat null/undefined as ""; convert numbers to string - if ( val == null ) { - val = ""; - - } else if ( typeof val === "number" ) { - val += ""; - - } else if ( Array.isArray( val ) ) { - val = jQuery.map( val, function( value ) { - return value == null ? "" : value + ""; - } ); - } - - hooks = jQuery.valHooks[ this.type ] || jQuery.valHooks[ this.nodeName.toLowerCase() ]; - - // If set returns undefined, fall back to normal setting - if ( !hooks || !( "set" in hooks ) || hooks.set( this, val, "value" ) === undefined ) { - this.value = val; - } - } ); - } -} ); - -jQuery.extend( { - valHooks: { - option: { - get: function( elem ) { - - var val = jQuery.find.attr( elem, "value" ); - return val != null ? - val : - - // Support: IE <=10 - 11 only - // option.text throws exceptions (#14686, #14858) - // Strip and collapse whitespace - // https://html.spec.whatwg.org/#strip-and-collapse-whitespace - stripAndCollapse( jQuery.text( elem ) ); - } - }, - select: { - get: function( elem ) { - var value, option, i, - options = elem.options, - index = elem.selectedIndex, - one = elem.type === "select-one", - values = one ? null : [], - max = one ? index + 1 : options.length; - - if ( index < 0 ) { - i = max; - - } else { - i = one ? index : 0; - } - - // Loop through all the selected options - for ( ; i < max; i++ ) { - option = options[ i ]; - - // Support: IE <=9 only - // IE8-9 doesn't update selected after form reset (#2551) - if ( ( option.selected || i === index ) && - - // Don't return options that are disabled or in a disabled optgroup - !option.disabled && - ( !option.parentNode.disabled || - !nodeName( option.parentNode, "optgroup" ) ) ) { - - // Get the specific value for the option - value = jQuery( option ).val(); - - // We don't need an array for one selects - if ( one ) { - return value; - } - - // Multi-Selects return an array - values.push( value ); - } - } - - return values; - }, - - set: function( elem, value ) { - var optionSet, option, - options = elem.options, - values = jQuery.makeArray( value ), - i = options.length; - - while ( i-- ) { - option = options[ i ]; - - /* eslint-disable no-cond-assign */ - - if ( option.selected = - jQuery.inArray( jQuery.valHooks.option.get( option ), values ) > -1 - ) { - optionSet = true; - } - - /* eslint-enable no-cond-assign */ - } - - // Force browsers to behave consistently when non-matching value is set - if ( !optionSet ) { - elem.selectedIndex = -1; - } - return values; - } - } - } -} ); - -// Radios and checkboxes getter/setter -jQuery.each( [ "radio", "checkbox" ], function() { - jQuery.valHooks[ this ] = { - set: function( elem, value ) { - if ( Array.isArray( value ) ) { - return ( elem.checked = jQuery.inArray( jQuery( elem ).val(), value ) > -1 ); - } - } - }; - if ( !support.checkOn ) { - jQuery.valHooks[ this ].get = function( elem ) { - return elem.getAttribute( "value" ) === null ? "on" : elem.value; - }; - } -} ); - - - - -// Return jQuery for attributes-only inclusion - - -var rfocusMorph = /^(?:focusinfocus|focusoutblur)$/; - -jQuery.extend( jQuery.event, { - - trigger: function( event, data, elem, onlyHandlers ) { - - var i, cur, tmp, bubbleType, ontype, handle, special, - eventPath = [ elem || document ], - type = hasOwn.call( event, "type" ) ? event.type : event, - namespaces = hasOwn.call( event, "namespace" ) ? event.namespace.split( "." ) : []; - - cur = tmp = elem = elem || document; - - // Don't do events on text and comment nodes - if ( elem.nodeType === 3 || elem.nodeType === 8 ) { - return; - } - - // focus/blur morphs to focusin/out; ensure we're not firing them right now - if ( rfocusMorph.test( type + jQuery.event.triggered ) ) { - return; - } - - if ( type.indexOf( "." ) > -1 ) { - - // Namespaced trigger; create a regexp to match event type in handle() - namespaces = type.split( "." ); - type = namespaces.shift(); - namespaces.sort(); - } - ontype = type.indexOf( ":" ) < 0 && "on" + type; - - // Caller can pass in a jQuery.Event object, Object, or just an event type string - event = event[ jQuery.expando ] ? - event : - new jQuery.Event( type, typeof event === "object" && event ); - - // Trigger bitmask: & 1 for native handlers; & 2 for jQuery (always true) - event.isTrigger = onlyHandlers ? 2 : 3; - event.namespace = namespaces.join( "." ); - event.rnamespace = event.namespace ? - new RegExp( "(^|\\.)" + namespaces.join( "\\.(?:.*\\.|)" ) + "(\\.|$)" ) : - null; - - // Clean up the event in case it is being reused - event.result = undefined; - if ( !event.target ) { - event.target = elem; - } - - // Clone any incoming data and prepend the event, creating the handler arg list - data = data == null ? - [ event ] : - jQuery.makeArray( data, [ event ] ); - - // Allow special events to draw outside the lines - special = jQuery.event.special[ type ] || {}; - if ( !onlyHandlers && special.trigger && special.trigger.apply( elem, data ) === false ) { - return; - } - - // Determine event propagation path in advance, per W3C events spec (#9951) - // Bubble up to document, then to window; watch for a global ownerDocument var (#9724) - if ( !onlyHandlers && !special.noBubble && !jQuery.isWindow( elem ) ) { - - bubbleType = special.delegateType || type; - if ( !rfocusMorph.test( bubbleType + type ) ) { - cur = cur.parentNode; - } - for ( ; cur; cur = cur.parentNode ) { - eventPath.push( cur ); - tmp = cur; - } - - // Only add window if we got to document (e.g., not plain obj or detached DOM) - if ( tmp === ( elem.ownerDocument || document ) ) { - eventPath.push( tmp.defaultView || tmp.parentWindow || window ); - } - } - - // Fire handlers on the event path - i = 0; - while ( ( cur = eventPath[ i++ ] ) && !event.isPropagationStopped() ) { - - event.type = i > 1 ? - bubbleType : - special.bindType || type; - - // jQuery handler - handle = ( dataPriv.get( cur, "events" ) || {} )[ event.type ] && - dataPriv.get( cur, "handle" ); - if ( handle ) { - handle.apply( cur, data ); - } - - // Native handler - handle = ontype && cur[ ontype ]; - if ( handle && handle.apply && acceptData( cur ) ) { - event.result = handle.apply( cur, data ); - if ( event.result === false ) { - event.preventDefault(); - } - } - } - event.type = type; - - // If nobody prevented the default action, do it now - if ( !onlyHandlers && !event.isDefaultPrevented() ) { - - if ( ( !special._default || - special._default.apply( eventPath.pop(), data ) === false ) && - acceptData( elem ) ) { - - // Call a native DOM method on the target with the same name as the event. - // Don't do default actions on window, that's where global variables be (#6170) - if ( ontype && jQuery.isFunction( elem[ type ] ) && !jQuery.isWindow( elem ) ) { - - // Don't re-trigger an onFOO event when we call its FOO() method - tmp = elem[ ontype ]; - - if ( tmp ) { - elem[ ontype ] = null; - } - - // Prevent re-triggering of the same event, since we already bubbled it above - jQuery.event.triggered = type; - elem[ type ](); - jQuery.event.triggered = undefined; - - if ( tmp ) { - elem[ ontype ] = tmp; - } - } - } - } - - return event.result; - }, - - // Piggyback on a donor event to simulate a different one - // Used only for `focus(in | out)` events - simulate: function( type, elem, event ) { - var e = jQuery.extend( - new jQuery.Event(), - event, - { - type: type, - isSimulated: true - } - ); - - jQuery.event.trigger( e, null, elem ); - } - -} ); - -jQuery.fn.extend( { - - trigger: function( type, data ) { - return this.each( function() { - jQuery.event.trigger( type, data, this ); - } ); - }, - triggerHandler: function( type, data ) { - var elem = this[ 0 ]; - if ( elem ) { - return jQuery.event.trigger( type, data, elem, true ); - } - } -} ); - - -jQuery.each( ( "blur focus focusin focusout resize scroll click dblclick " + - "mousedown mouseup mousemove mouseover mouseout mouseenter mouseleave " + - "change select submit keydown keypress keyup contextmenu" ).split( " " ), - function( i, name ) { - - // Handle event binding - jQuery.fn[ name ] = function( data, fn ) { - return arguments.length > 0 ? - this.on( name, null, data, fn ) : - this.trigger( name ); - }; -} ); - -jQuery.fn.extend( { - hover: function( fnOver, fnOut ) { - return this.mouseenter( fnOver ).mouseleave( fnOut || fnOver ); - } -} ); - - - - -support.focusin = "onfocusin" in window; - - -// Support: Firefox <=44 -// Firefox doesn't have focus(in | out) events -// Related ticket - https://bugzilla.mozilla.org/show_bug.cgi?id=687787 -// -// Support: Chrome <=48 - 49, Safari <=9.0 - 9.1 -// focus(in | out) events fire after focus & blur events, -// which is spec violation - http://www.w3.org/TR/DOM-Level-3-Events/#events-focusevent-event-order -// Related ticket - https://bugs.chromium.org/p/chromium/issues/detail?id=449857 -if ( !support.focusin ) { - jQuery.each( { focus: "focusin", blur: "focusout" }, function( orig, fix ) { - - // Attach a single capturing handler on the document while someone wants focusin/focusout - var handler = function( event ) { - jQuery.event.simulate( fix, event.target, jQuery.event.fix( event ) ); - }; - - jQuery.event.special[ fix ] = { - setup: function() { - var doc = this.ownerDocument || this, - attaches = dataPriv.access( doc, fix ); - - if ( !attaches ) { - doc.addEventListener( orig, handler, true ); - } - dataPriv.access( doc, fix, ( attaches || 0 ) + 1 ); - }, - teardown: function() { - var doc = this.ownerDocument || this, - attaches = dataPriv.access( doc, fix ) - 1; - - if ( !attaches ) { - doc.removeEventListener( orig, handler, true ); - dataPriv.remove( doc, fix ); - - } else { - dataPriv.access( doc, fix, attaches ); - } - } - }; - } ); -} -var location = window.location; - -var nonce = jQuery.now(); - -var rquery = ( /\?/ ); - - - -// Cross-browser xml parsing -jQuery.parseXML = function( data ) { - var xml; - if ( !data || typeof data !== "string" ) { - return null; - } - - // Support: IE 9 - 11 only - // IE throws on parseFromString with invalid input. - try { - xml = ( new window.DOMParser() ).parseFromString( data, "text/xml" ); - } catch ( e ) { - xml = undefined; - } - - if ( !xml || xml.getElementsByTagName( "parsererror" ).length ) { - jQuery.error( "Invalid XML: " + data ); - } - return xml; -}; - - -var - rbracket = /\[\]$/, - rCRLF = /\r?\n/g, - rsubmitterTypes = /^(?:submit|button|image|reset|file)$/i, - rsubmittable = /^(?:input|select|textarea|keygen)/i; - -function buildParams( prefix, obj, traditional, add ) { - var name; - - if ( Array.isArray( obj ) ) { - - // Serialize array item. - jQuery.each( obj, function( i, v ) { - if ( traditional || rbracket.test( prefix ) ) { - - // Treat each array item as a scalar. - add( prefix, v ); - - } else { - - // Item is non-scalar (array or object), encode its numeric index. - buildParams( - prefix + "[" + ( typeof v === "object" && v != null ? i : "" ) + "]", - v, - traditional, - add - ); - } - } ); - - } else if ( !traditional && jQuery.type( obj ) === "object" ) { - - // Serialize object item. - for ( name in obj ) { - buildParams( prefix + "[" + name + "]", obj[ name ], traditional, add ); - } - - } else { - - // Serialize scalar item. - add( prefix, obj ); - } -} - -// Serialize an array of form elements or a set of -// key/values into a query string -jQuery.param = function( a, traditional ) { - var prefix, - s = [], - add = function( key, valueOrFunction ) { - - // If value is a function, invoke it and use its return value - var value = jQuery.isFunction( valueOrFunction ) ? - valueOrFunction() : - valueOrFunction; - - s[ s.length ] = encodeURIComponent( key ) + "=" + - encodeURIComponent( value == null ? "" : value ); - }; - - // If an array was passed in, assume that it is an array of form elements. - if ( Array.isArray( a ) || ( a.jquery && !jQuery.isPlainObject( a ) ) ) { - - // Serialize the form elements - jQuery.each( a, function() { - add( this.name, this.value ); - } ); - - } else { - - // If traditional, encode the "old" way (the way 1.3.2 or older - // did it), otherwise encode params recursively. - for ( prefix in a ) { - buildParams( prefix, a[ prefix ], traditional, add ); - } - } - - // Return the resulting serialization - return s.join( "&" ); -}; - -jQuery.fn.extend( { - serialize: function() { - return jQuery.param( this.serializeArray() ); - }, - serializeArray: function() { - return this.map( function() { - - // Can add propHook for "elements" to filter or add form elements - var elements = jQuery.prop( this, "elements" ); - return elements ? jQuery.makeArray( elements ) : this; - } ) - .filter( function() { - var type = this.type; - - // Use .is( ":disabled" ) so that fieldset[disabled] works - return this.name && !jQuery( this ).is( ":disabled" ) && - rsubmittable.test( this.nodeName ) && !rsubmitterTypes.test( type ) && - ( this.checked || !rcheckableType.test( type ) ); - } ) - .map( function( i, elem ) { - var val = jQuery( this ).val(); - - if ( val == null ) { - return null; - } - - if ( Array.isArray( val ) ) { - return jQuery.map( val, function( val ) { - return { name: elem.name, value: val.replace( rCRLF, "\r\n" ) }; - } ); - } - - return { name: elem.name, value: val.replace( rCRLF, "\r\n" ) }; - } ).get(); - } -} ); - - -var - r20 = /%20/g, - rhash = /#.*$/, - rantiCache = /([?&])_=[^&]*/, - rheaders = /^(.*?):[ \t]*([^\r\n]*)$/mg, - - // #7653, #8125, #8152: local protocol detection - rlocalProtocol = /^(?:about|app|app-storage|.+-extension|file|res|widget):$/, - rnoContent = /^(?:GET|HEAD)$/, - rprotocol = /^\/\//, - - /* Prefilters - * 1) They are useful to introduce custom dataTypes (see ajax/jsonp.js for an example) - * 2) These are called: - * - BEFORE asking for a transport - * - AFTER param serialization (s.data is a string if s.processData is true) - * 3) key is the dataType - * 4) the catchall symbol "*" can be used - * 5) execution will start with transport dataType and THEN continue down to "*" if needed - */ - prefilters = {}, - - /* Transports bindings - * 1) key is the dataType - * 2) the catchall symbol "*" can be used - * 3) selection will start with transport dataType and THEN go to "*" if needed - */ - transports = {}, - - // Avoid comment-prolog char sequence (#10098); must appease lint and evade compression - allTypes = "*/".concat( "*" ), - - // Anchor tag for parsing the document origin - originAnchor = document.createElement( "a" ); - originAnchor.href = location.href; - -// Base "constructor" for jQuery.ajaxPrefilter and jQuery.ajaxTransport -function addToPrefiltersOrTransports( structure ) { - - // dataTypeExpression is optional and defaults to "*" - return function( dataTypeExpression, func ) { - - if ( typeof dataTypeExpression !== "string" ) { - func = dataTypeExpression; - dataTypeExpression = "*"; - } - - var dataType, - i = 0, - dataTypes = dataTypeExpression.toLowerCase().match( rnothtmlwhite ) || []; - - if ( jQuery.isFunction( func ) ) { - - // For each dataType in the dataTypeExpression - while ( ( dataType = dataTypes[ i++ ] ) ) { - - // Prepend if requested - if ( dataType[ 0 ] === "+" ) { - dataType = dataType.slice( 1 ) || "*"; - ( structure[ dataType ] = structure[ dataType ] || [] ).unshift( func ); - - // Otherwise append - } else { - ( structure[ dataType ] = structure[ dataType ] || [] ).push( func ); - } - } - } - }; -} - -// Base inspection function for prefilters and transports -function inspectPrefiltersOrTransports( structure, options, originalOptions, jqXHR ) { - - var inspected = {}, - seekingTransport = ( structure === transports ); - - function inspect( dataType ) { - var selected; - inspected[ dataType ] = true; - jQuery.each( structure[ dataType ] || [], function( _, prefilterOrFactory ) { - var dataTypeOrTransport = prefilterOrFactory( options, originalOptions, jqXHR ); - if ( typeof dataTypeOrTransport === "string" && - !seekingTransport && !inspected[ dataTypeOrTransport ] ) { - - options.dataTypes.unshift( dataTypeOrTransport ); - inspect( dataTypeOrTransport ); - return false; - } else if ( seekingTransport ) { - return !( selected = dataTypeOrTransport ); - } - } ); - return selected; - } - - return inspect( options.dataTypes[ 0 ] ) || !inspected[ "*" ] && inspect( "*" ); -} - -// A special extend for ajax options -// that takes "flat" options (not to be deep extended) -// Fixes #9887 -function ajaxExtend( target, src ) { - var key, deep, - flatOptions = jQuery.ajaxSettings.flatOptions || {}; - - for ( key in src ) { - if ( src[ key ] !== undefined ) { - ( flatOptions[ key ] ? target : ( deep || ( deep = {} ) ) )[ key ] = src[ key ]; - } - } - if ( deep ) { - jQuery.extend( true, target, deep ); - } - - return target; -} - -/* Handles responses to an ajax request: - * - finds the right dataType (mediates between content-type and expected dataType) - * - returns the corresponding response - */ -function ajaxHandleResponses( s, jqXHR, responses ) { - - var ct, type, finalDataType, firstDataType, - contents = s.contents, - dataTypes = s.dataTypes; - - // Remove auto dataType and get content-type in the process - while ( dataTypes[ 0 ] === "*" ) { - dataTypes.shift(); - if ( ct === undefined ) { - ct = s.mimeType || jqXHR.getResponseHeader( "Content-Type" ); - } - } - - // Check if we're dealing with a known content-type - if ( ct ) { - for ( type in contents ) { - if ( contents[ type ] && contents[ type ].test( ct ) ) { - dataTypes.unshift( type ); - break; - } - } - } - - // Check to see if we have a response for the expected dataType - if ( dataTypes[ 0 ] in responses ) { - finalDataType = dataTypes[ 0 ]; - } else { - - // Try convertible dataTypes - for ( type in responses ) { - if ( !dataTypes[ 0 ] || s.converters[ type + " " + dataTypes[ 0 ] ] ) { - finalDataType = type; - break; - } - if ( !firstDataType ) { - firstDataType = type; - } - } - - // Or just use first one - finalDataType = finalDataType || firstDataType; - } - - // If we found a dataType - // We add the dataType to the list if needed - // and return the corresponding response - if ( finalDataType ) { - if ( finalDataType !== dataTypes[ 0 ] ) { - dataTypes.unshift( finalDataType ); - } - return responses[ finalDataType ]; - } -} - -/* Chain conversions given the request and the original response - * Also sets the responseXXX fields on the jqXHR instance - */ -function ajaxConvert( s, response, jqXHR, isSuccess ) { - var conv2, current, conv, tmp, prev, - converters = {}, - - // Work with a copy of dataTypes in case we need to modify it for conversion - dataTypes = s.dataTypes.slice(); - - // Create converters map with lowercased keys - if ( dataTypes[ 1 ] ) { - for ( conv in s.converters ) { - converters[ conv.toLowerCase() ] = s.converters[ conv ]; - } - } - - current = dataTypes.shift(); - - // Convert to each sequential dataType - while ( current ) { - - if ( s.responseFields[ current ] ) { - jqXHR[ s.responseFields[ current ] ] = response; - } - - // Apply the dataFilter if provided - if ( !prev && isSuccess && s.dataFilter ) { - response = s.dataFilter( response, s.dataType ); - } - - prev = current; - current = dataTypes.shift(); - - if ( current ) { - - // There's only work to do if current dataType is non-auto - if ( current === "*" ) { - - current = prev; - - // Convert response if prev dataType is non-auto and differs from current - } else if ( prev !== "*" && prev !== current ) { - - // Seek a direct converter - conv = converters[ prev + " " + current ] || converters[ "* " + current ]; - - // If none found, seek a pair - if ( !conv ) { - for ( conv2 in converters ) { - - // If conv2 outputs current - tmp = conv2.split( " " ); - if ( tmp[ 1 ] === current ) { - - // If prev can be converted to accepted input - conv = converters[ prev + " " + tmp[ 0 ] ] || - converters[ "* " + tmp[ 0 ] ]; - if ( conv ) { - - // Condense equivalence converters - if ( conv === true ) { - conv = converters[ conv2 ]; - - // Otherwise, insert the intermediate dataType - } else if ( converters[ conv2 ] !== true ) { - current = tmp[ 0 ]; - dataTypes.unshift( tmp[ 1 ] ); - } - break; - } - } - } - } - - // Apply converter (if not an equivalence) - if ( conv !== true ) { - - // Unless errors are allowed to bubble, catch and return them - if ( conv && s.throws ) { - response = conv( response ); - } else { - try { - response = conv( response ); - } catch ( e ) { - return { - state: "parsererror", - error: conv ? e : "No conversion from " + prev + " to " + current - }; - } - } - } - } - } - } - - return { state: "success", data: response }; -} - -jQuery.extend( { - - // Counter for holding the number of active queries - active: 0, - - // Last-Modified header cache for next request - lastModified: {}, - etag: {}, - - ajaxSettings: { - url: location.href, - type: "GET", - isLocal: rlocalProtocol.test( location.protocol ), - global: true, - processData: true, - async: true, - contentType: "application/x-www-form-urlencoded; charset=UTF-8", - - /* - timeout: 0, - data: null, - dataType: null, - username: null, - password: null, - cache: null, - throws: false, - traditional: false, - headers: {}, - */ - - accepts: { - "*": allTypes, - text: "text/plain", - html: "text/html", - xml: "application/xml, text/xml", - json: "application/json, text/javascript" - }, - - contents: { - xml: /\bxml\b/, - html: /\bhtml/, - json: /\bjson\b/ - }, - - responseFields: { - xml: "responseXML", - text: "responseText", - json: "responseJSON" - }, - - // Data converters - // Keys separate source (or catchall "*") and destination types with a single space - converters: { - - // Convert anything to text - "* text": String, - - // Text to html (true = no transformation) - "text html": true, - - // Evaluate text as a json expression - "text json": JSON.parse, - - // Parse text as xml - "text xml": jQuery.parseXML - }, - - // For options that shouldn't be deep extended: - // you can add your own custom options here if - // and when you create one that shouldn't be - // deep extended (see ajaxExtend) - flatOptions: { - url: true, - context: true - } - }, - - // Creates a full fledged settings object into target - // with both ajaxSettings and settings fields. - // If target is omitted, writes into ajaxSettings. - ajaxSetup: function( target, settings ) { - return settings ? - - // Building a settings object - ajaxExtend( ajaxExtend( target, jQuery.ajaxSettings ), settings ) : - - // Extending ajaxSettings - ajaxExtend( jQuery.ajaxSettings, target ); - }, - - ajaxPrefilter: addToPrefiltersOrTransports( prefilters ), - ajaxTransport: addToPrefiltersOrTransports( transports ), - - // Main method - ajax: function( url, options ) { - - // If url is an object, simulate pre-1.5 signature - if ( typeof url === "object" ) { - options = url; - url = undefined; - } - - // Force options to be an object - options = options || {}; - - var transport, - - // URL without anti-cache param - cacheURL, - - // Response headers - responseHeadersString, - responseHeaders, - - // timeout handle - timeoutTimer, - - // Url cleanup var - urlAnchor, - - // Request state (becomes false upon send and true upon completion) - completed, - - // To know if global events are to be dispatched - fireGlobals, - - // Loop variable - i, - - // uncached part of the url - uncached, - - // Create the final options object - s = jQuery.ajaxSetup( {}, options ), - - // Callbacks context - callbackContext = s.context || s, - - // Context for global events is callbackContext if it is a DOM node or jQuery collection - globalEventContext = s.context && - ( callbackContext.nodeType || callbackContext.jquery ) ? - jQuery( callbackContext ) : - jQuery.event, - - // Deferreds - deferred = jQuery.Deferred(), - completeDeferred = jQuery.Callbacks( "once memory" ), - - // Status-dependent callbacks - statusCode = s.statusCode || {}, - - // Headers (they are sent all at once) - requestHeaders = {}, - requestHeadersNames = {}, - - // Default abort message - strAbort = "canceled", - - // Fake xhr - jqXHR = { - readyState: 0, - - // Builds headers hashtable if needed - getResponseHeader: function( key ) { - var match; - if ( completed ) { - if ( !responseHeaders ) { - responseHeaders = {}; - while ( ( match = rheaders.exec( responseHeadersString ) ) ) { - responseHeaders[ match[ 1 ].toLowerCase() ] = match[ 2 ]; - } - } - match = responseHeaders[ key.toLowerCase() ]; - } - return match == null ? null : match; - }, - - // Raw string - getAllResponseHeaders: function() { - return completed ? responseHeadersString : null; - }, - - // Caches the header - setRequestHeader: function( name, value ) { - if ( completed == null ) { - name = requestHeadersNames[ name.toLowerCase() ] = - requestHeadersNames[ name.toLowerCase() ] || name; - requestHeaders[ name ] = value; - } - return this; - }, - - // Overrides response content-type header - overrideMimeType: function( type ) { - if ( completed == null ) { - s.mimeType = type; - } - return this; - }, - - // Status-dependent callbacks - statusCode: function( map ) { - var code; - if ( map ) { - if ( completed ) { - - // Execute the appropriate callbacks - jqXHR.always( map[ jqXHR.status ] ); - } else { - - // Lazy-add the new callbacks in a way that preserves old ones - for ( code in map ) { - statusCode[ code ] = [ statusCode[ code ], map[ code ] ]; - } - } - } - return this; - }, - - // Cancel the request - abort: function( statusText ) { - var finalText = statusText || strAbort; - if ( transport ) { - transport.abort( finalText ); - } - done( 0, finalText ); - return this; - } - }; - - // Attach deferreds - deferred.promise( jqXHR ); - - // Add protocol if not provided (prefilters might expect it) - // Handle falsy url in the settings object (#10093: consistency with old signature) - // We also use the url parameter if available - s.url = ( ( url || s.url || location.href ) + "" ) - .replace( rprotocol, location.protocol + "//" ); - - // Alias method option to type as per ticket #12004 - s.type = options.method || options.type || s.method || s.type; - - // Extract dataTypes list - s.dataTypes = ( s.dataType || "*" ).toLowerCase().match( rnothtmlwhite ) || [ "" ]; - - // A cross-domain request is in order when the origin doesn't match the current origin. - if ( s.crossDomain == null ) { - urlAnchor = document.createElement( "a" ); - - // Support: IE <=8 - 11, Edge 12 - 13 - // IE throws exception on accessing the href property if url is malformed, - // e.g. http://example.com:80x/ - try { - urlAnchor.href = s.url; - - // Support: IE <=8 - 11 only - // Anchor's host property isn't correctly set when s.url is relative - urlAnchor.href = urlAnchor.href; - s.crossDomain = originAnchor.protocol + "//" + originAnchor.host !== - urlAnchor.protocol + "//" + urlAnchor.host; - } catch ( e ) { - - // If there is an error parsing the URL, assume it is crossDomain, - // it can be rejected by the transport if it is invalid - s.crossDomain = true; - } - } - - // Convert data if not already a string - if ( s.data && s.processData && typeof s.data !== "string" ) { - s.data = jQuery.param( s.data, s.traditional ); - } - - // Apply prefilters - inspectPrefiltersOrTransports( prefilters, s, options, jqXHR ); - - // If request was aborted inside a prefilter, stop there - if ( completed ) { - return jqXHR; - } - - // We can fire global events as of now if asked to - // Don't fire events if jQuery.event is undefined in an AMD-usage scenario (#15118) - fireGlobals = jQuery.event && s.global; - - // Watch for a new set of requests - if ( fireGlobals && jQuery.active++ === 0 ) { - jQuery.event.trigger( "ajaxStart" ); - } - - // Uppercase the type - s.type = s.type.toUpperCase(); - - // Determine if request has content - s.hasContent = !rnoContent.test( s.type ); - - // Save the URL in case we're toying with the If-Modified-Since - // and/or If-None-Match header later on - // Remove hash to simplify url manipulation - cacheURL = s.url.replace( rhash, "" ); - - // More options handling for requests with no content - if ( !s.hasContent ) { - - // Remember the hash so we can put it back - uncached = s.url.slice( cacheURL.length ); - - // If data is available, append data to url - if ( s.data ) { - cacheURL += ( rquery.test( cacheURL ) ? "&" : "?" ) + s.data; - - // #9682: remove data so that it's not used in an eventual retry - delete s.data; - } - - // Add or update anti-cache param if needed - if ( s.cache === false ) { - cacheURL = cacheURL.replace( rantiCache, "$1" ); - uncached = ( rquery.test( cacheURL ) ? "&" : "?" ) + "_=" + ( nonce++ ) + uncached; - } - - // Put hash and anti-cache on the URL that will be requested (gh-1732) - s.url = cacheURL + uncached; - - // Change '%20' to '+' if this is encoded form body content (gh-2658) - } else if ( s.data && s.processData && - ( s.contentType || "" ).indexOf( "application/x-www-form-urlencoded" ) === 0 ) { - s.data = s.data.replace( r20, "+" ); - } - - // Set the If-Modified-Since and/or If-None-Match header, if in ifModified mode. - if ( s.ifModified ) { - if ( jQuery.lastModified[ cacheURL ] ) { - jqXHR.setRequestHeader( "If-Modified-Since", jQuery.lastModified[ cacheURL ] ); - } - if ( jQuery.etag[ cacheURL ] ) { - jqXHR.setRequestHeader( "If-None-Match", jQuery.etag[ cacheURL ] ); - } - } - - // Set the correct header, if data is being sent - if ( s.data && s.hasContent && s.contentType !== false || options.contentType ) { - jqXHR.setRequestHeader( "Content-Type", s.contentType ); - } - - // Set the Accepts header for the server, depending on the dataType - jqXHR.setRequestHeader( - "Accept", - s.dataTypes[ 0 ] && s.accepts[ s.dataTypes[ 0 ] ] ? - s.accepts[ s.dataTypes[ 0 ] ] + - ( s.dataTypes[ 0 ] !== "*" ? ", " + allTypes + "; q=0.01" : "" ) : - s.accepts[ "*" ] - ); - - // Check for headers option - for ( i in s.headers ) { - jqXHR.setRequestHeader( i, s.headers[ i ] ); - } - - // Allow custom headers/mimetypes and early abort - if ( s.beforeSend && - ( s.beforeSend.call( callbackContext, jqXHR, s ) === false || completed ) ) { - - // Abort if not done already and return - return jqXHR.abort(); - } - - // Aborting is no longer a cancellation - strAbort = "abort"; - - // Install callbacks on deferreds - completeDeferred.add( s.complete ); - jqXHR.done( s.success ); - jqXHR.fail( s.error ); - - // Get transport - transport = inspectPrefiltersOrTransports( transports, s, options, jqXHR ); - - // If no transport, we auto-abort - if ( !transport ) { - done( -1, "No Transport" ); - } else { - jqXHR.readyState = 1; - - // Send global event - if ( fireGlobals ) { - globalEventContext.trigger( "ajaxSend", [ jqXHR, s ] ); - } - - // If request was aborted inside ajaxSend, stop there - if ( completed ) { - return jqXHR; - } - - // Timeout - if ( s.async && s.timeout > 0 ) { - timeoutTimer = window.setTimeout( function() { - jqXHR.abort( "timeout" ); - }, s.timeout ); - } - - try { - completed = false; - transport.send( requestHeaders, done ); - } catch ( e ) { - - // Rethrow post-completion exceptions - if ( completed ) { - throw e; - } - - // Propagate others as results - done( -1, e ); - } - } - - // Callback for when everything is done - function done( status, nativeStatusText, responses, headers ) { - var isSuccess, success, error, response, modified, - statusText = nativeStatusText; - - // Ignore repeat invocations - if ( completed ) { - return; - } - - completed = true; - - // Clear timeout if it exists - if ( timeoutTimer ) { - window.clearTimeout( timeoutTimer ); - } - - // Dereference transport for early garbage collection - // (no matter how long the jqXHR object will be used) - transport = undefined; - - // Cache response headers - responseHeadersString = headers || ""; - - // Set readyState - jqXHR.readyState = status > 0 ? 4 : 0; - - // Determine if successful - isSuccess = status >= 200 && status < 300 || status === 304; - - // Get response data - if ( responses ) { - response = ajaxHandleResponses( s, jqXHR, responses ); - } - - // Convert no matter what (that way responseXXX fields are always set) - response = ajaxConvert( s, response, jqXHR, isSuccess ); - - // If successful, handle type chaining - if ( isSuccess ) { - - // Set the If-Modified-Since and/or If-None-Match header, if in ifModified mode. - if ( s.ifModified ) { - modified = jqXHR.getResponseHeader( "Last-Modified" ); - if ( modified ) { - jQuery.lastModified[ cacheURL ] = modified; - } - modified = jqXHR.getResponseHeader( "etag" ); - if ( modified ) { - jQuery.etag[ cacheURL ] = modified; - } - } - - // if no content - if ( status === 204 || s.type === "HEAD" ) { - statusText = "nocontent"; - - // if not modified - } else if ( status === 304 ) { - statusText = "notmodified"; - - // If we have data, let's convert it - } else { - statusText = response.state; - success = response.data; - error = response.error; - isSuccess = !error; - } - } else { - - // Extract error from statusText and normalize for non-aborts - error = statusText; - if ( status || !statusText ) { - statusText = "error"; - if ( status < 0 ) { - status = 0; - } - } - } - - // Set data for the fake xhr object - jqXHR.status = status; - jqXHR.statusText = ( nativeStatusText || statusText ) + ""; - - // Success/Error - if ( isSuccess ) { - deferred.resolveWith( callbackContext, [ success, statusText, jqXHR ] ); - } else { - deferred.rejectWith( callbackContext, [ jqXHR, statusText, error ] ); - } - - // Status-dependent callbacks - jqXHR.statusCode( statusCode ); - statusCode = undefined; - - if ( fireGlobals ) { - globalEventContext.trigger( isSuccess ? "ajaxSuccess" : "ajaxError", - [ jqXHR, s, isSuccess ? success : error ] ); - } - - // Complete - completeDeferred.fireWith( callbackContext, [ jqXHR, statusText ] ); - - if ( fireGlobals ) { - globalEventContext.trigger( "ajaxComplete", [ jqXHR, s ] ); - - // Handle the global AJAX counter - if ( !( --jQuery.active ) ) { - jQuery.event.trigger( "ajaxStop" ); - } - } - } - - return jqXHR; - }, - - getJSON: function( url, data, callback ) { - return jQuery.get( url, data, callback, "json" ); - }, - - getScript: function( url, callback ) { - return jQuery.get( url, undefined, callback, "script" ); - } -} ); - -jQuery.each( [ "get", "post" ], function( i, method ) { - jQuery[ method ] = function( url, data, callback, type ) { - - // Shift arguments if data argument was omitted - if ( jQuery.isFunction( data ) ) { - type = type || callback; - callback = data; - data = undefined; - } - - // The url can be an options object (which then must have .url) - return jQuery.ajax( jQuery.extend( { - url: url, - type: method, - dataType: type, - data: data, - success: callback - }, jQuery.isPlainObject( url ) && url ) ); - }; -} ); - - -jQuery._evalUrl = function( url ) { - return jQuery.ajax( { - url: url, - - // Make this explicit, since user can override this through ajaxSetup (#11264) - type: "GET", - dataType: "script", - cache: true, - async: false, - global: false, - "throws": true - } ); -}; - - -jQuery.fn.extend( { - wrapAll: function( html ) { - var wrap; - - if ( this[ 0 ] ) { - if ( jQuery.isFunction( html ) ) { - html = html.call( this[ 0 ] ); - } - - // The elements to wrap the target around - wrap = jQuery( html, this[ 0 ].ownerDocument ).eq( 0 ).clone( true ); - - if ( this[ 0 ].parentNode ) { - wrap.insertBefore( this[ 0 ] ); - } - - wrap.map( function() { - var elem = this; - - while ( elem.firstElementChild ) { - elem = elem.firstElementChild; - } - - return elem; - } ).append( this ); - } - - return this; - }, - - wrapInner: function( html ) { - if ( jQuery.isFunction( html ) ) { - return this.each( function( i ) { - jQuery( this ).wrapInner( html.call( this, i ) ); - } ); - } - - return this.each( function() { - var self = jQuery( this ), - contents = self.contents(); - - if ( contents.length ) { - contents.wrapAll( html ); - - } else { - self.append( html ); - } - } ); - }, - - wrap: function( html ) { - var isFunction = jQuery.isFunction( html ); - - return this.each( function( i ) { - jQuery( this ).wrapAll( isFunction ? html.call( this, i ) : html ); - } ); - }, - - unwrap: function( selector ) { - this.parent( selector ).not( "body" ).each( function() { - jQuery( this ).replaceWith( this.childNodes ); - } ); - return this; - } -} ); - - -jQuery.expr.pseudos.hidden = function( elem ) { - return !jQuery.expr.pseudos.visible( elem ); -}; -jQuery.expr.pseudos.visible = function( elem ) { - return !!( elem.offsetWidth || elem.offsetHeight || elem.getClientRects().length ); -}; - - - - -jQuery.ajaxSettings.xhr = function() { - try { - return new window.XMLHttpRequest(); - } catch ( e ) {} -}; - -var xhrSuccessStatus = { - - // File protocol always yields status code 0, assume 200 - 0: 200, - - // Support: IE <=9 only - // #1450: sometimes IE returns 1223 when it should be 204 - 1223: 204 - }, - xhrSupported = jQuery.ajaxSettings.xhr(); - -support.cors = !!xhrSupported && ( "withCredentials" in xhrSupported ); -support.ajax = xhrSupported = !!xhrSupported; - -jQuery.ajaxTransport( function( options ) { - var callback, errorCallback; - - // Cross domain only allowed if supported through XMLHttpRequest - if ( support.cors || xhrSupported && !options.crossDomain ) { - return { - send: function( headers, complete ) { - var i, - xhr = options.xhr(); - - xhr.open( - options.type, - options.url, - options.async, - options.username, - options.password - ); - - // Apply custom fields if provided - if ( options.xhrFields ) { - for ( i in options.xhrFields ) { - xhr[ i ] = options.xhrFields[ i ]; - } - } - - // Override mime type if needed - if ( options.mimeType && xhr.overrideMimeType ) { - xhr.overrideMimeType( options.mimeType ); - } - - // X-Requested-With header - // For cross-domain requests, seeing as conditions for a preflight are - // akin to a jigsaw puzzle, we simply never set it to be sure. - // (it can always be set on a per-request basis or even using ajaxSetup) - // For same-domain requests, won't change header if already provided. - if ( !options.crossDomain && !headers[ "X-Requested-With" ] ) { - headers[ "X-Requested-With" ] = "XMLHttpRequest"; - } - - // Set headers - for ( i in headers ) { - xhr.setRequestHeader( i, headers[ i ] ); - } - - // Callback - callback = function( type ) { - return function() { - if ( callback ) { - callback = errorCallback = xhr.onload = - xhr.onerror = xhr.onabort = xhr.onreadystatechange = null; - - if ( type === "abort" ) { - xhr.abort(); - } else if ( type === "error" ) { - - // Support: IE <=9 only - // On a manual native abort, IE9 throws - // errors on any property access that is not readyState - if ( typeof xhr.status !== "number" ) { - complete( 0, "error" ); - } else { - complete( - - // File: protocol always yields status 0; see #8605, #14207 - xhr.status, - xhr.statusText - ); - } - } else { - complete( - xhrSuccessStatus[ xhr.status ] || xhr.status, - xhr.statusText, - - // Support: IE <=9 only - // IE9 has no XHR2 but throws on binary (trac-11426) - // For XHR2 non-text, let the caller handle it (gh-2498) - ( xhr.responseType || "text" ) !== "text" || - typeof xhr.responseText !== "string" ? - { binary: xhr.response } : - { text: xhr.responseText }, - xhr.getAllResponseHeaders() - ); - } - } - }; - }; - - // Listen to events - xhr.onload = callback(); - errorCallback = xhr.onerror = callback( "error" ); - - // Support: IE 9 only - // Use onreadystatechange to replace onabort - // to handle uncaught aborts - if ( xhr.onabort !== undefined ) { - xhr.onabort = errorCallback; - } else { - xhr.onreadystatechange = function() { - - // Check readyState before timeout as it changes - if ( xhr.readyState === 4 ) { - - // Allow onerror to be called first, - // but that will not handle a native abort - // Also, save errorCallback to a variable - // as xhr.onerror cannot be accessed - window.setTimeout( function() { - if ( callback ) { - errorCallback(); - } - } ); - } - }; - } - - // Create the abort callback - callback = callback( "abort" ); - - try { - - // Do send the request (this may raise an exception) - xhr.send( options.hasContent && options.data || null ); - } catch ( e ) { - - // #14683: Only rethrow if this hasn't been notified as an error yet - if ( callback ) { - throw e; - } - } - }, - - abort: function() { - if ( callback ) { - callback(); - } - } - }; - } -} ); - - - - -// Prevent auto-execution of scripts when no explicit dataType was provided (See gh-2432) -jQuery.ajaxPrefilter( function( s ) { - if ( s.crossDomain ) { - s.contents.script = false; - } -} ); - -// Install script dataType -jQuery.ajaxSetup( { - accepts: { - script: "text/javascript, application/javascript, " + - "application/ecmascript, application/x-ecmascript" - }, - contents: { - script: /\b(?:java|ecma)script\b/ - }, - converters: { - "text script": function( text ) { - jQuery.globalEval( text ); - return text; - } - } -} ); - -// Handle cache's special case and crossDomain -jQuery.ajaxPrefilter( "script", function( s ) { - if ( s.cache === undefined ) { - s.cache = false; - } - if ( s.crossDomain ) { - s.type = "GET"; - } -} ); - -// Bind script tag hack transport -jQuery.ajaxTransport( "script", function( s ) { - - // This transport only deals with cross domain requests - if ( s.crossDomain ) { - var script, callback; - return { - send: function( _, complete ) { - script = jQuery( " - - - - - - - - - - - - - - - - - - - - - - - - - -
            - - - -
            - - - - - -
            - -
            - - - - - - - - - - - - - - - - - -
            - - - - -
            -
            -
            -
            - -
            -

            IOparser Package¶

            -
            -

            config_WORC Module¶

            -
            -
            -WORC.IOparser.config_WORC.load_config(config_file_path)[source]¶
            -

            Parse a WORC configuration file.

            -
            -
            Arguments:

            config_file_path: path to the configuration file to be parsed.

            -
            -
            Returns:

            settings_dict: dictionary containing all parsed settings.

            -
            -
            -
            - -
            -
            -

            config_io_classifier Module¶

            -
            -
            -WORC.IOparser.config_io_classifier.load_config(config_file_path)[source]¶
            -

            Load the config ini, parse settings to WORC

            -
            -
            Args:

            config_file_path (String): path of the .ini config file

            -
            -
            Returns:

            settings_dict (dict): dict with the loaded settings

            -
            -
            -
            - -
            -
            -

            config_preprocessing Module¶

            -
            -
            -WORC.IOparser.config_preprocessing.load_config(config_file_path)[source]¶
            -

            Parse a WORC configuration file.

            -
            -
            Arguments:

            config_file_path: path to the configuration file to be parsed.

            -
            -
            Returns:

            settings_dict: dictionary containing all parsed settings.

            -
            -
            -
            - -
            -
            -

            config_segmentix Module¶

            -
            -
            -WORC.IOparser.config_segmentix.load_config(config_file_path)[source]¶
            -

            Parse a segmentix configuration file.

            -
            -
            Arguments:

            config_file_path: path to the configuration file to be parsed.

            -
            -
            Returns:

            settings_dict: dictionary containing all parsed settings.

            -
            -
            -
            - -
            -
            -

            file_io Module¶

            -
            -
            -WORC.IOparser.file_io.load_data(featurefiles, patientinfo=None, label_names=None, modnames=[])[source]¶
            -

            Read feature files and stack the features per patient in an array. -Additionally, if a patient label file is supplied, the features from -a patient will be matched to the labels.

            -
            -
            featurefiles: list, mandatory

            List containing all paths to the .hdf5 feature files to be loaded. -The argument should contain a list per modelity, e.g. -[[features_mod1_patient1, features_mod1_patient2, …],

            -
            -

            [features_mod2_patient1, features_mod2_patient2, …]].

            -
            -
            -
            patientinfo: string, optional

            Path referring to the .txt file to be used to read patient -labels from. See the Github Wiki for the format.

            -
            -
            label_names: list, optional

            List containing all the labels that should be extracted from -the patientinfo file.

            -
            -
            -
            - -
            -
            - - -
            - -
            -
            - - - - -
            - -
            -

            - © Copyright 2016 -- 2019, Biomedical Imaging Group Rotterdam, Departments of Medical Informatics and Radiology, Erasmus MC, Rotterdam, The Netherlands - -

            -
            - Built with Sphinx using a theme provided by Read the Docs. - -
            - -
            -
            - -
            - -
            - - - - - - - - - - - - \ No newline at end of file diff --git a/build/lib/WORC/doc/_build/html/autogen/WORC.classification.html b/build/lib/WORC/doc/_build/html/autogen/WORC.classification.html deleted file mode 100644 index e1063f76..00000000 --- a/build/lib/WORC/doc/_build/html/autogen/WORC.classification.html +++ /dev/null @@ -1,700 +0,0 @@ - - - - - - - - - - - classification Package — WORC 3.0.0 documentation - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
            - - - -
            - - - - - -
            - -
            - - - - - - - - - - - - - - - - - -
            - - - - -
            -
            -
            -
            - -
            -

            classification Package¶

            -
            -

            AdvancedSampler Module¶

            -
            -
            -class WORC.classification.AdvancedSampler.AdvancedSampler(param_distributions, n_iter, random_state=None, method='Halton')[source]¶
            -

            Bases: object

            -

            Generator on parameters sampled from given distributions using -numerical sequences. Based on the sklearn ParameterSampler.

            -

            Non-deterministic iterable over random candidate combinations for hyper- -parameter search. If all parameters are presented as a list, -sampling without replacement is performed. If at least one parameter -is given as a distribution, sampling with replacement is used. -It is highly recommended to use continuous distributions for continuous -parameters.

            -

            Note that before SciPy 0.16, the scipy.stats.distributions do not -accept a custom RNG instance and always use the singleton RNG from -numpy.random. Hence setting random_state will not guarantee a -deterministic iteration whenever scipy.stats distributions are used to -define the parameter search space. Deterministic behavior is however -guaranteed from SciPy 0.16 onwards.

            -

            Read more in the User Guide.

            -
            -
            param_distributionsdict

            Dictionary where the keys are parameters and values -are distributions from which a parameter is to be sampled. -Distributions either have to provide a rvs function -to sample from them, or can be given as a list of values, -where a uniform distribution is assumed.

            -
            -
            n_iterinteger

            Number of parameter settings that are produced.

            -
            -
            random_stateint or RandomState

            Pseudo random number generator state used for random uniform sampling -from lists of possible values instead of scipy.stats distributions.

            -
            -
            -
            -
            paramsdict of string to any

            Yields dictionaries mapping each estimator parameter to -as sampled value.

            -
            -
            -
            >>> from WORC.classification.AdvancedSampler import HaltonSampler
            ->>> from scipy.stats.distributions import expon
            ->>> import numpy as np
            ->>> np.random.seed(0)
            ->>> param_grid = {'a':[1, 2], 'b': expon()}
            ->>> param_list = list(HaltonSampler(param_grid, n_iter=4))
            ->>> rounded_list = [dict((k, round(v, 6)) for (k, v) in d.items())
            -...                 for d in param_list]
            ->>> rounded_list == [{'b': 0.89856, 'a': 1},
            -...                  {'b': 0.923223, 'a': 1},
            -...                  {'b': 1.878964, 'a': 2},
            -...                  {'b': 1.038159, 'a': 2}]
            -True
            -
            -
            -
            -
            -__dict__ = mappingproxy({'__module__': 'WORC.classification.AdvancedSampler', '__doc__': "Generator on parameters sampled from given distributions using\n numerical sequences. Based on the sklearn ParameterSampler.\n\n Non-deterministic iterable over random candidate combinations for hyper-\n parameter search. If all parameters are presented as a list,\n sampling without replacement is performed. If at least one parameter\n is given as a distribution, sampling with replacement is used.\n It is highly recommended to use continuous distributions for continuous\n parameters.\n\n Note that before SciPy 0.16, the ``scipy.stats.distributions`` do not\n accept a custom RNG instance and always use the singleton RNG from\n ``numpy.random``. Hence setting ``random_state`` will not guarantee a\n deterministic iteration whenever ``scipy.stats`` distributions are used to\n define the parameter search space. Deterministic behavior is however\n guaranteed from SciPy 0.16 onwards.\n\n Read more in the :ref:`User Guide <search>`.\n\n Parameters\n ----------\n param_distributions : dict\n Dictionary where the keys are parameters and values\n are distributions from which a parameter is to be sampled.\n Distributions either have to provide a ``rvs`` function\n to sample from them, or can be given as a list of values,\n where a uniform distribution is assumed.\n\n n_iter : integer\n Number of parameter settings that are produced.\n\n random_state : int or RandomState\n Pseudo random number generator state used for random uniform sampling\n from lists of possible values instead of scipy.stats distributions.\n\n Returns\n -------\n params : dict of string to any\n **Yields** dictionaries mapping each estimator parameter to\n as sampled value.\n\n Examples\n --------\n >>> from WORC.classification.AdvancedSampler import HaltonSampler\n >>> from scipy.stats.distributions import expon\n >>> import numpy as np\n >>> np.random.seed(0)\n >>> param_grid = {'a':[1, 2], 'b': expon()}\n >>> param_list = list(HaltonSampler(param_grid, n_iter=4))\n >>> rounded_list = [dict((k, round(v, 6)) for (k, v) in d.items())\n ... for d in param_list]\n >>> rounded_list == [{'b': 0.89856, 'a': 1},\n ... {'b': 0.923223, 'a': 1},\n ... {'b': 1.878964, 'a': 2},\n ... {'b': 1.038159, 'a': 2}]\n True\n ", '__init__': <function AdvancedSampler.__init__>, '__iter__': <function AdvancedSampler.__iter__>, '__len__': <function AdvancedSampler.__len__>, '__dict__': <attribute '__dict__' of 'AdvancedSampler' objects>, '__weakref__': <attribute '__weakref__' of 'AdvancedSampler' objects>})¶
            -
            - -
            -
            -__init__(param_distributions, n_iter, random_state=None, method='Halton')[source]¶
            -

            Initialize self. See help(type(self)) for accurate signature.

            -
            - -
            -
            -__iter__()[source]¶
            -
            - -
            -
            -__len__()[source]¶
            -

            Number of points that will be sampled.

            -
            - -
            -
            -__module__ = 'WORC.classification.AdvancedSampler'¶
            -
            - -
            -
            -__weakref__¶
            -

            list of weak references to the object (if defined)

            -
            - -
            - -
            -
            -class WORC.classification.AdvancedSampler.discrete_uniform(loc=-1, scale=0)[source]¶
            -

            Bases: object

            -
            -
            -__dict__ = mappingproxy({'__module__': 'WORC.classification.AdvancedSampler', '__init__': <function discrete_uniform.__init__>, 'rvs': <function discrete_uniform.rvs>, '__dict__': <attribute '__dict__' of 'discrete_uniform' objects>, '__weakref__': <attribute '__weakref__' of 'discrete_uniform' objects>, '__doc__': None})¶
            -
            - -
            -
            -__init__(loc=-1, scale=0)[source]¶
            -

            Initialize self. See help(type(self)) for accurate signature.

            -
            - -
            -
            -__module__ = 'WORC.classification.AdvancedSampler'¶
            -
            - -
            -
            -__weakref__¶
            -

            list of weak references to the object (if defined)

            -
            - -
            -
            -rvs(size=None, random_state=None)[source]¶
            -
            - -
            - -
            -
            -class WORC.classification.AdvancedSampler.exp_uniform(loc=-1, scale=0, base=2.718281828459045)[source]¶
            -

            Bases: object

            -
            -
            -__dict__ = mappingproxy({'__module__': 'WORC.classification.AdvancedSampler', '__init__': <function exp_uniform.__init__>, 'rvs': <function exp_uniform.rvs>, '__dict__': <attribute '__dict__' of 'exp_uniform' objects>, '__weakref__': <attribute '__weakref__' of 'exp_uniform' objects>, '__doc__': None})¶
            -
            - -
            -
            -__init__(loc=-1, scale=0, base=2.718281828459045)[source]¶
            -

            Initialize self. See help(type(self)) for accurate signature.

            -
            - -
            -
            -__module__ = 'WORC.classification.AdvancedSampler'¶
            -
            - -
            -
            -__weakref__¶
            -

            list of weak references to the object (if defined)

            -
            - -
            -
            -rvs(size=None, random_state=None)[source]¶
            -
            - -
            - -
            -
            -class WORC.classification.AdvancedSampler.log_uniform(loc=-1, scale=0, base=10)[source]¶
            -

            Bases: object

            -
            -
            -__dict__ = mappingproxy({'__module__': 'WORC.classification.AdvancedSampler', '__init__': <function log_uniform.__init__>, 'rvs': <function log_uniform.rvs>, '__dict__': <attribute '__dict__' of 'log_uniform' objects>, '__weakref__': <attribute '__weakref__' of 'log_uniform' objects>, '__doc__': None})¶
            -
            - -
            -
            -__init__(loc=-1, scale=0, base=10)[source]¶
            -

            Initialize self. See help(type(self)) for accurate signature.

            -
            - -
            -
            -__module__ = 'WORC.classification.AdvancedSampler'¶
            -
            - -
            -
            -__weakref__¶
            -

            list of weak references to the object (if defined)

            -
            - -
            -
            -rvs(size=None, random_state=None)[source]¶
            -
            - -
            - -
            -
            -

            RankedSVM Module¶

            -
            -
            -WORC.classification.RankedSVM.RankSVM_test(test_data, num_class, Weights, Bias, SVs, svm='Poly', gamma=0.05, coefficient=0.05, degree=3)[source]¶
            -
            - -
            -
            -WORC.classification.RankedSVM.RankSVM_test_original(test_data, test_target, Weights, Bias, SVs, svm='Poly', gamma=0.05, coefficient=0.05, degree=3)[source]¶
            -
            - -
            -
            -WORC.classification.RankedSVM.RankSVM_train(train_data, train_target, cost=1, lambda_tol=1e-06, norm_tol=0.0001, max_iter=500, svm='Poly', gamma=0.05, coefficient=0.05, degree=3)[source]¶
            -
            - -
            -
            -WORC.classification.RankedSVM.RankSVM_train_old(train_data, train_target, cost=1, lambda_tol=1e-06, norm_tol=0.0001, max_iter=500, svm='Poly', gamma=0.05, coefficient=0.05, degree=3)[source]¶
            -
            -

            Weights,Bias,SVs = RankSVM_train(train_data,train_target,cost,lambda_tol,norm_tol,max_iter,svm,gamma,coefficient,degree)

            -
            -

            Description

            -
            -
            -
            -
            RankSVM_train takes,

            train_data - An MxN array, the ith instance of training instance is stored in train_data[i,:] -train_target - A QxM array, if the ith training instance belongs to the jth class, then train_target[j,i] equals +1, otherwise train_target(j,i) equals -1

            -
            -
            -
            svm - svm gives the type of svm used in training, which can take the value of ‘RBF’, ‘Poly’ or ‘Linear’; svm.para gives the corresponding parameters used for the svm:
            -
              -
            1. if svm is ‘RBF’, then gamma gives the value of gamma, where the kernel is exp(-Gamma*|x[i]-x[j]|^2)

            2. -
            -
            -
              -
            1. if svm is ‘Poly’, then three values are used gamma, coefficient, and degree respectively, where the kernel is (gamma*<x[i],x[j]>+coefficient)^degree.

            2. -
            3. if svm is ‘Linear’, then svm is [].

            4. -
            -
            -
            -
            -

            cost - The value of ‘C’ used in the SVM, default=1 -lambda_tol - The tolerance value for lambda described in the appendix of [1]; default value is 1e-6 -norm_tol - The tolerance value for difference between alpha(p+1) and alpha(p) described in the appendix of [1]; default value is 1e-4 -max_iter - The maximum number of iterations for RankSVM, default=500

            -
            -
            and returns,

            Weights - The value for beta[ki] as described in the appendix of [1] is stored in Weights[k,i] -Bias - The value for b[i] as described in the appendix of [1] is stored in Bias[1,i] -SVs - The ith support vector is stored in SVs[:,i]

            -
            -
            -
            -

            For more details,please refer to [1] and [2].

            -
            -
            - -
            -
            -WORC.classification.RankedSVM.is_empty(any_structure)[source]¶
            -
            - -
            -
            -WORC.classification.RankedSVM.neg_dual_func(Lambda, Alpha_old, Alpha_new, c_value, kernel, num_training, num_class, Label, not_Label, Label_size, size_alpha)[source]¶
            -
            - -
            -
            -

            SearchCV Module¶

            -
            -
            -

            construct_classifier Module¶

            -
            -
            -WORC.classification.construct_classifier.construct_SVM(config, regression=False)[source]¶
            -

            Constructs a SVM classifier

            -
            -
            Args:

            config (dict): Dictionary of the required config settings -features (pandas dataframe): A pandas dataframe containing the features

            -
            -

            to be used for classification

            -
            -
            -
            Returns:

            SVM/SVR classifier, parameter grid

            -
            -
            -
            - -
            -
            -WORC.classification.construct_classifier.construct_classifier(config)[source]¶
            -

            Interface to create classification

            -

            Different classifications can be created using this common interface

            -
            -
            -
            config: dict, mandatory

            Contains the required config settings. See the Github Wiki for -all available fields.

            -
            -
            -
            -
            -
            Returns:

            Constructed classifier

            -
            -
            -
            - -
            -
            -WORC.classification.construct_classifier.create_param_grid(config)[source]¶
            -

            Create a parameter grid for the WORC classifiers based on the -provided configuration.

            -
            - -
            -
            -

            crossval Module¶

            -
            -
            -

            estimators Module¶

            -
            -
            -class WORC.classification.estimators.RankedSVM(cost=1, lambda_tol=1e-06, norm_tol=0.0001, max_iter=500, svm='Poly', gamma=0.05, coefficient=0.05, degree=3)[source]¶
            -

            Bases: sklearn.base.BaseEstimator, sklearn.base.ClassifierMixin

            -

            An example classifier which implements a 1-NN algorithm.

            -
            -
            demo_paramstr, optional

            A parameter used for demonstation of how to pass and store paramters.

            -
            -
            -
            -
            X_array, shape = [n_samples, n_features]

            The input passed during fit()

            -
            -
            y_array, shape = [n_samples]

            The labels passed during fit()

            -
            -
            -
            -
            -__init__(cost=1, lambda_tol=1e-06, norm_tol=0.0001, max_iter=500, svm='Poly', gamma=0.05, coefficient=0.05, degree=3)[source]¶
            -

            Initialize self. See help(type(self)) for accurate signature.

            -
            - -
            -
            -__module__ = 'WORC.classification.estimators'¶
            -
            - -
            -
            -fit(X, y)[source]¶
            -

            A reference implementation of a fitting function for a classifier.

            -
            -
            Xarray-like, shape = [n_samples, n_features]

            The training input samples.

            -
            -
            yarray-like, shape = [n_samples]

            The target values. An array of int.

            -
            -
            -
            -
            selfobject

            Returns self.

            -
            -
            -
            - -
            -
            -predict(X, y=None)[source]¶
            -

            A reference implementation of a prediction for a classifier.

            -
            -
            Xarray-like of shape = [n_samples, n_features]

            The input samples.

            -
            -
            -
            -
            yarray of int of shape = [n_samples]

            The label for each sample is the label of the closest sample -seen udring fit.

            -
            -
            -
            - -
            -
            -predict_proba(X, y)[source]¶
            -

            A reference implementation of a prediction for a classifier.

            -
            -
            Xarray-like of shape = [n_samples, n_features]

            The input samples.

            -
            -
            -
            -
            yarray of int of shape = [n_samples]

            The label for each sample is the label of the closest sample -seen udring fit.

            -
            -
            -
            - -
            - -
            -
            -

            fitandscore Module¶

            -
            -
            -

            metrics Module¶

            -
            -
            -WORC.classification.metrics.ICC(M, ICCtype='inter')[source]¶
            -
            -
            Input:

            M is matrix of observations. Rows: patients, columns: observers. -type: ICC type, currently “inter†or “intraâ€.

            -
            -
            -
            - -
            -
            -WORC.classification.metrics.ICC_anova(Y, ICCtype='inter', more=False)[source]¶
            -

            Adopted from Nipype with a slight alteration to distinguish inter and intra. -the data Y are entered as a ‘table’ ie subjects are in rows and repeated -measures in columns -One Sample Repeated measure ANOVA -Y = XB + E with X = [FaTor / Subjects]

            -
            - -
            -
            -WORC.classification.metrics.check_scoring(estimator, scoring=None, allow_none=False)[source]¶
            -

            Surrogate for sklearn’s check_scoring to enable use of some other -scoring metrics.

            -
            - -
            -
            -WORC.classification.metrics.multi_class_auc(y_truth, y_score)[source]¶
            -
            - -
            -
            -WORC.classification.metrics.multi_class_auc_score(y_truth, y_score)[source]¶
            -
            - -
            -
            -WORC.classification.metrics.pairwise_auc(y_truth, y_score, class_i, class_j)[source]¶
            -
            - -
            -
            -WORC.classification.metrics.performance_multilabel(y_truth, y_prediction, y_score=None, beta=1)[source]¶
            -

            Multiclass performance metrics.

            -

            y_truth and y_prediction should both be lists with the multiclass label of each -object, e.g.

            -

            y_truth = [0, 0, 0, 0, 0, 0, 2, 2, 1, 1, 2] ### Groundtruth -y_prediction = [0, 0, 0, 0, 0, 0, 1, 2, 1, 2, 2] ### Predicted labels

            -

            Calculation of accuracy accorading to formula suggested in CAD Dementia Grand Challege http://caddementia.grand-challenge.org -Calculation of Multi Class AUC according to classpy: https://bitbucket.org/bigr_erasmusmc/classpy/src/master/classpy/multi_class_auc.py

            -
            - -
            -
            -WORC.classification.metrics.performance_singlelabel(y_truth, y_prediction, y_score, regression=False)[source]¶
            -

            Singleclass performance metrics

            -
            - -
            -
            -

            parameter_optimization Module¶

            -
            -
            -

            trainclassifier Module¶

            -
            -
            - - -
            - -
            -
            - - - - -
            - -
            -

            - © Copyright 2016 -- 2019, Biomedical Imaging Group Rotterdam, Departments of Medical Informatics and Radiology, Erasmus MC, Rotterdam, The Netherlands - -

            -
            - Built with Sphinx using a theme provided by Read the Docs. - -
            - -
            -
            - -
            - -
            - - - - - - - - - - - - \ No newline at end of file diff --git a/build/lib/WORC/doc/_build/html/autogen/WORC.featureprocessing.html b/build/lib/WORC/doc/_build/html/autogen/WORC.featureprocessing.html deleted file mode 100644 index 8bc3620e..00000000 --- a/build/lib/WORC/doc/_build/html/autogen/WORC.featureprocessing.html +++ /dev/null @@ -1,586 +0,0 @@ - - - - - - - - - - - featureprocessing Package — WORC 3.0.0 documentation - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
            - - - -
            - - - - - -
            - -
            - - - - - - - - - - - - - - - - - -
            - - - - -
            -
            -
            -
            - -
            -

            featureprocessing Package¶

            -
            -

            featureprocessing Package¶

            -
            -
            -

            Imputer Module¶

            -
            -
            -class WORC.featureprocessing.Imputer.Imputer(missing_values='nan', strategy='mean', n_neighbors=5)[source]¶
            -

            Bases: object

            -

            Module for feature imputation.

            -
            -
            -__dict__ = mappingproxy({'__module__': 'WORC.featureprocessing.Imputer', '__doc__': 'Module for feature imputation.', '__init__': <function Imputer.__init__>, 'fit': <function Imputer.fit>, 'transform': <function Imputer.transform>, '__dict__': <attribute '__dict__' of 'Imputer' objects>, '__weakref__': <attribute '__weakref__' of 'Imputer' objects>})¶
            -
            - -
            -
            -__init__(missing_values='nan', strategy='mean', n_neighbors=5)[source]¶
            -

            Imputation of feature values using either sklearn, missingpy or -(WIP) fancyimpute approaches.

            -
            -
            missing_valuesnumber, string, np.nan (default) or None

            The placeholder for the missing values. All occurrences of -missing_values will be imputed.

            -
            -
            strategystring, optional (default=â€meanâ€)

            The imputation strategy.

            -

            Supported using sklearn: -- If “meanâ€, then replace missing values using the mean along

            -
            -

            each column. Can only be used with numeric data.

            -
            -
              -
            • If “medianâ€, then replace missing values using the median along -each column. Can only be used with numeric data.

            • -
            • If “most_frequentâ€, then replace missing using the most frequent -value along each column. Can be used with strings or numeric data.

            • -
            • If “constantâ€, then replace missing values with fill_value. Can be -used with strings or numeric data.

            • -
            -

            Supported using missingpy: -- If ‘knn’, then use a nearest neighbor search. Can be

            -
            -

            used with strings or numeric data.

            -
            -

            WIP: More strategies using fancyimpute

            -
            -
            n_neighborsint, optional (default = 5)

            Number of neighboring samples to use for imputation if method -is knn.

            -
            -
            -
            - -
            -
            -__module__ = 'WORC.featureprocessing.Imputer'¶
            -
            - -
            -
            -__weakref__¶
            -

            list of weak references to the object (if defined)

            -
            - -
            -
            -fit(X, y=None)[source]¶
            -
            - -
            -
            -transform(X)[source]¶
            -
            - -
            - -
            -
            -

            Relief Module¶

            -
            -
            -class WORC.featureprocessing.Relief.SelectMulticlassRelief(n_neighbours=3, sample_size=1, distance_p=2, numf=None)[source]¶
            -

            Bases: sklearn.base.BaseEstimator, sklearn.feature_selection.base.SelectorMixin

            -

            Object to fit feature selection based on the type group the feature belongs -to. The label for the feature is used for this procedure.

            -
            -
            -__abstractmethods__ = frozenset({})¶
            -
            - -
            -
            -__init__(n_neighbours=3, sample_size=1, distance_p=2, numf=None)[source]¶
            -
            -
            n_neightbors: integer

            Number of nearest neighbours used.

            -
            -
            sample_size: float

            Percentage of samples used to calculate score

            -
            -
            distance_p: integer

            Parameter in minkov distance usde for nearest neighbour calculation

            -
            -
            numf: integer, default None

            Number of important features to be selected with respect to their -ranking. If None, all are used.

            -
            -
            -
            - -
            -
            -__module__ = 'WORC.featureprocessing.Relief'¶
            -
            - -
            -
            -fit(X, y)[source]¶
            -

            Select only features specificed by parameters per patient.

            -
            -
            feature_values: numpy array, mandatory

            Array containing feature values used for model_selection. -Number of objects on first axis, features on second axis.

            -
            -
            feature_labels: list, mandatory

            Contains the labels of all features used. The index in this -list will be used in the transform funtion to select features.

            -
            -
            -
            - -
            -
            -multi_class_relief(feature_set, label_set, nb=3, sample_size=1, distance_p=2, numf=None)[source]¶
            -
            - -
            -
            -single_class_relief(feature_set, label_set, nb=3, sample_size=1, distance_p=2, numf=None)[source]¶
            -
            - -
            -
            -transform(inputarray)[source]¶
            -

            Transform the inputarray to select only the features based on the -result from the fit function.

            -
            -
            inputarray: numpy array, mandatory

            Array containing the items to use selection on. The type of -item in this list does not matter, e.g. floats, strings etc.

            -
            -
            -
            - -
            - -
            -
            -

            SelectGroups Module¶

            -
            -
            -class WORC.featureprocessing.SelectGroups.SelectGroups(parameters)[source]¶
            -

            Bases: sklearn.base.BaseEstimator, sklearn.feature_selection.base.SelectorMixin

            -

            Object to fit feature selection based on the type group the feature belongs -to. The label for the feature is used for this procedure.

            -
            -
            -__abstractmethods__ = frozenset({})¶
            -
            - -
            -
            -__init__(parameters)[source]¶
            -
            -
            parameters: dict, mandatory

            Contains the settings for the groups to be selected. Should -contain the settings for the following groups: -- histogram_features -- shape_features -- orientation_features -- semantic_features -- patient_features -- coliage_features -- phase_features -- vessel_features -- log_features -- texture_Gabor_features -- texture_GLCM_features -- texture_GLCMMS_features -- texture_GLRLM_features -- texture_GLSZM_features -- texture_NGTDM_features -- texture_LBP_features

            -
            -
            -
            - -
            -
            -__module__ = 'WORC.featureprocessing.SelectGroups'¶
            -
            - -
            -
            -fit(feature_labels)[source]¶
            -

            Select only features specificed by parameters per patient.

            -
            -
            feature_labels: list, optional

            Contains the labels of all features used. The index in this -list will be used in the transform funtion to select features.

            -
            -
            -
            - -
            -
            -transform(inputarray)[source]¶
            -

            Transform the inputarray to select only the features based on the -result from the fit function.

            -
            -
            inputarray: numpy array, mandatory

            Array containing the items to use selection on. The type of -item in this list does not matter, e.g. floats, strings etc.

            -
            -
            -
            - -
            - -
            -
            -

            SelectIndividuals Module¶

            -
            -
            -class WORC.featureprocessing.SelectIndividuals.SelectIndividuals(parameters=['hf_mean', 'sf_compactness'])[source]¶
            -

            Bases: sklearn.base.BaseEstimator, sklearn.feature_selection.base.SelectorMixin

            -

            Object to fit feature selection based on the type group the feature belongs -to. The label for the feature is used for this procedure.

            -
            -
            -__abstractmethods__ = frozenset({})¶
            -
            - -
            -
            -__init__(parameters=['hf_mean', 'sf_compactness'])[source]¶
            -
            -
            parameters: dict, mandatory

            Contains the settings for the groups to be selected. Should -contain the settings for the following groups: -- histogram_features -- shape_features -- orientation_features -- semantic_features -- patient_features -- coliage_features -- phase_features -- vessel_features -- log_features -- texture_features

            -
            -
            -
            - -
            -
            -__module__ = 'WORC.featureprocessing.SelectIndividuals'¶
            -
            - -
            -
            -fit(feature_labels)[source]¶
            -

            Select only features specificed by parameters per patient.

            -
            -
            feature_labels: list, optional

            Contains the labels of all features used. The index in this -list will be used in the transform funtion to select features.

            -
            -
            -
            - -
            -
            -transform(inputarray)[source]¶
            -

            Transform the inputarray to select only the features based on the -result from the fit function.

            -
            -
            inputarray: numpy array, mandatory

            Array containing the items to use selection on. The type of -item in this list does not matter, e.g. floats, strings etc.

            -
            -
            -
            - -
            - -
            -
            -

            StatisticalTestFeatures Module¶

            -
            -
            -

            StatisticalTestThreshold Module¶

            -
            -
            -class WORC.featureprocessing.StatisticalTestThreshold.StatisticalTestThreshold(metric='ttest', threshold=0.05)[source]¶
            -

            Bases: sklearn.base.BaseEstimator, sklearn.feature_selection.base.SelectorMixin

            -

            Object to fit feature selection based on statistical tests.

            -
            -
            -__abstractmethods__ = frozenset({})¶
            -
            - -
            -
            -__init__(metric='ttest', threshold=0.05)[source]¶
            -
            -
            metric: string, default ‘ttest’

            Statistical test used for selection. Options are ttest, -Welch, Wilcoxon, MannWhitneyU

            -
            -
            threshold: float, default 0.05

            Threshold for p-value in order for feature to be selected

            -
            -
            -
            - -
            -
            -__module__ = 'WORC.featureprocessing.StatisticalTestThreshold'¶
            -
            - -
            -
            -fit(X_train, Y_train)[source]¶
            -

            Select only features specificed by the metric and threshold per patient.

            -
            -
            X_train: numpy array, mandatory

            Array containing feature values used for model_selection. -Number of objects on first axis, features on second axis.

            -
            -
            Y_train: numpy array, mandatory

            Array containing the binary labels for each object in X_train.

            -
            -
            -
            - -
            -
            -transform(inputarray)[source]¶
            -

            Transform the inputarray to select only the features based on the -result from the fit function.

            -
            -
            inputarray: numpy array, mandatory

            Array containing the items to use selection on. The type of -item in this list does not matter, e.g. floats, strings etc.

            -
            -
            -
            - -
            - -
            -
            -

            VarianceThreshold Module¶

            -
            -
            - - -
            - -
            -
            - - - - -
            - -
            -

            - © Copyright 2016 -- 2019, Biomedical Imaging Group Rotterdam, Departments of Medical Informatics and Radiology, Erasmus MC, Rotterdam, The Netherlands - -

            -
            - Built with Sphinx using a theme provided by Read the Docs. - -
            - -
            -
            - -
            - -
            - - - - - - - - - - - - \ No newline at end of file diff --git a/build/lib/WORC/doc/_build/html/autogen/WORC.html b/build/lib/WORC/doc/_build/html/autogen/WORC.html deleted file mode 100644 index 15f7e699..00000000 --- a/build/lib/WORC/doc/_build/html/autogen/WORC.html +++ /dev/null @@ -1,593 +0,0 @@ - - - - - - - - - - - WORC Package — WORC 3.0.0 documentation - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
            - - - -
            - - - - - -
            - -
            - - - - - - - - - - - - - - - - - -
            - - - - -
            -
            -
            -
            - -
            -

            WORC Package¶

            -
            -

            WORC Package¶

            -
            -
            -

            WORC Module¶

            -
            -
            -class WORC.WORC.Tools[source]¶
            -

            Bases: object

            -

            This object can be used to create other pipelines besides the default -Radiomics executions. Currently only includes a registratio pipeline.

            -
            -
            -__dict__ = mappingproxy({'__module__': 'WORC.WORC', '__doc__': '\n This object can be used to create other pipelines besides the default\n Radiomics executions. Currently only includes a registratio pipeline.\n ', '__init__': <function Tools.__init__>, '__dict__': <attribute '__dict__' of 'Tools' objects>, '__weakref__': <attribute '__weakref__' of 'Tools' objects>})¶
            -
            - -
            -
            -__init__()[source]¶
            -

            Initialize self. See help(type(self)) for accurate signature.

            -
            - -
            -
            -__module__ = 'WORC.WORC'¶
            -
            - -
            -
            -__weakref__¶
            -

            list of weak references to the object (if defined)

            -
            - -
            - -
            -
            -class WORC.WORC.WORC(name='WORC')[source]¶
            -

            Bases: object

            -

            A Workflow for Optimal Radiomics Classification (WORC) object that -serves as a pipeline spawner and manager for optimizating radiomics -studies. Depending on the attributes set, the object will spawn an -appropriate pipeline and manage it.

            -

            Note that many attributes are lists and can therefore contain multiple -instances. For example, when providing two sequences per patient, -the “images†list contains two items. The type of items in the lists -is described below.

            -

            All objects that serve as source for your network, i.e. refer to -actual files to be used, should be formatted as fastr sources suited for -one of the fastr plugings, see also -http://fastr.readthedocs.io/en/stable/fastr.reference.html#ioplugin-reference -The objects should be lists of these fastr sources or dictionaries with the -sample ID’s, e.g.

            -
            -
            images_train = [{‘Patient001’: vfs://input/CT001.nii.gz,
            -

            ‘Patient002’: vfs://input/CT002.nii.gz},

            -
            -
            -
            {‘Patient001’: vfs://input/MR001.nii.gz,

            ‘Patient002’: vfs://input/MR002.nii.gz}]

            -
            -
            -
            -
            -
            -
            -
            name: String, default ‘WORC’

            name of the network.

            -
            -
            configs: list, required

            Configuration parameters, either ConfigParser objects -created through the defaultconfig function or paths of config .ini -files. (list, required)

            -
            -
            labels: list, required

            Paths to files containing patient labels (.txt files).

            -
            -
            network: automatically generated

            The FASTR network generated through the “build†function.

            -
            -
            images: list, optional

            Paths refering to the images used for Radiomics computation. Images -should be of the ITK Image type.

            -
            -
            segmentations: list, optional

            Paths refering to the segmentations used for Radiomics computation. -Segmentations should be of the ITK Image type.

            -
            -
            -

            semantics: semantic features per image type (list, optional)

            -

            masks: state which pixels of images are valid (list, optional)

            -

            features: input Radiomics features for classification (list, optional)

            -

            metadata: DICOM headers belonging to images (list, optional)

            -

            Elastix_Para: parameter files for Elastix (list, optional)

            -

            fastr_plugin: plugin to use for FASTR execution

            -

            fastr_tempdir: temporary directory to use for FASTR execution

            -

            additions: additional inputs for your network (dict, optional)

            -

            source_data: data to use as sources for FASTR (dict)

            -

            sink_data: data to use as sinks for FASTR (dict)

            -
            -
            CopyMetadata: Boolean, default True

            when using elastix, copy metadata from image to segmentation or not

            -
            -
            -
            -
            -
            -__dict__ = mappingproxy({'__module__': 'WORC.WORC', '__doc__': '\n A Workflow for Optimal Radiomics Classification (WORC) object that\n serves as a pipeline spawner and manager for optimizating radiomics\n studies. Depending on the attributes set, the object will spawn an\n appropriate pipeline and manage it.\n\n Note that many attributes are lists and can therefore contain multiple\n instances. For example, when providing two sequences per patient,\n the "images" list contains two items. The type of items in the lists\n is described below.\n\n All objects that serve as source for your network, i.e. refer to\n actual files to be used, should be formatted as fastr sources suited for\n one of the fastr plugings, see also\n http://fastr.readthedocs.io/en/stable/fastr.reference.html#ioplugin-reference\n The objects should be lists of these fastr sources or dictionaries with the\n sample ID\'s, e.g.\n\n images_train = [{\'Patient001\': vfs://input/CT001.nii.gz,\n \'Patient002\': vfs://input/CT002.nii.gz},\n {\'Patient001\': vfs://input/MR001.nii.gz,\n \'Patient002\': vfs://input/MR002.nii.gz}]\n\n Attributes\n ------------------\n name: String, default \'WORC\'\n name of the network.\n\n configs: list, required\n Configuration parameters, either ConfigParser objects\n created through the defaultconfig function or paths of config .ini\n files. (list, required)\n\n labels: list, required\n Paths to files containing patient labels (.txt files).\n\n network: automatically generated\n The FASTR network generated through the "build" function.\n\n images: list, optional\n Paths refering to the images used for Radiomics computation. Images\n should be of the ITK Image type.\n\n segmentations: list, optional\n Paths refering to the segmentations used for Radiomics computation.\n Segmentations should be of the ITK Image type.\n\n semantics: semantic features per image type (list, optional)\n\n masks: state which pixels of images are valid (list, optional)\n\n features: input Radiomics features for classification (list, optional)\n\n metadata: DICOM headers belonging to images (list, optional)\n\n Elastix_Para: parameter files for Elastix (list, optional)\n\n fastr_plugin: plugin to use for FASTR execution\n\n fastr_tempdir: temporary directory to use for FASTR execution\n\n additions: additional inputs for your network (dict, optional)\n\n source_data: data to use as sources for FASTR (dict)\n\n sink_data: data to use as sinks for FASTR (dict)\n\n CopyMetadata: Boolean, default True\n when using elastix, copy metadata from image to segmentation or not\n\n\n ', '__init__': <function WORC.__init__>, 'defaultconfig': <function WORC.defaultconfig>, 'add_tools': <function WORC.add_tools>, 'build': <function WORC.build>, 'build_training': <function WORC.build_training>, 'build_testing': <function WORC.build_testing>, 'set': <function WORC.set>, 'execute': <function WORC.execute>, '__dict__': <attribute '__dict__' of 'WORC' objects>, '__weakref__': <attribute '__weakref__' of 'WORC' objects>})¶
            -
            - -
            -
            -__init__(name='WORC')[source]¶
            -
            -
            Initialize WORC object. Set the initial variables all to None,

            except for some defaults.

            -
            -
            Arguments:

            name: name of the nework (string, optional)

            -
            -
            -
            - -
            -
            -__module__ = 'WORC.WORC'¶
            -
            - -
            -
            -__weakref__¶
            -

            list of weak references to the object (if defined)

            -
            - -
            -
            -add_tools()[source]¶
            -
            - -
            -
            -build(wtype='training')[source]¶
            -

            Build the network based on the given attributes.

            -
            -
            wtype: string, default ‘training’

            Specify the WORC execution type. -- testing: use if you have a trained classifier and want to

            -
            -

            train it on some new images.

            -
            -
              -
            • training: use if you want to train a classifier from a dataset.

            • -
            -
            -
            -
            - -
            -
            -build_testing()[source]¶
            -

            todo

            -
            - -
            -
            -build_training()[source]¶
            -

            Build the training network based on the given attributes.

            -
            - -
            -
            -defaultconfig()[source]¶
            -

            Generate a configparser object holding all default configuration values.

            -
            -
            Returns:

            config: configparser configuration file

            -
            -
            -
            - -
            -
            -execute()[source]¶
            -

            Execute the network through the fastr.network.execute command.

            -
            - -
            -
            -set()[source]¶
            -

            Set the FASTR source and sink data based on the given attributes.

            -
            - -
            - -
            -
            -

            addexceptions Module¶

            -

            This module contains all WORC-related Exceptions

            -
            -
            -exception WORC.addexceptions.WORCAssertionError[source]¶
            -

            Bases: WORC.addexceptions.WORCError, AssertionError

            -

            AssertionError in the WORC system

            -
            -
            -__module__ = 'WORC.addexceptions'¶
            -
            - -
            - -
            -
            -exception WORC.addexceptions.WORCError[source]¶
            -

            Bases: Exception

            -

            This is the base class for all WORC related exceptions. Catching this -class of exceptions should ensure a proper execution of WORC.

            -
            -
            -__module__ = 'WORC.addexceptions'¶
            -
            - -
            -
            -__weakref__¶
            -

            list of weak references to the object (if defined)

            -
            - -
            - -
            -
            -exception WORC.addexceptions.WORCIOError[source]¶
            -

            Bases: WORC.addexceptions.WORCError, OSError

            -

            IOError in WORC

            -
            -
            -__module__ = 'WORC.addexceptions'¶
            -
            - -
            -
            -__weakref__¶
            -

            list of weak references to the object (if defined)

            -
            - -
            - -
            -
            -exception WORC.addexceptions.WORCIndexError[source]¶
            -

            Bases: WORC.addexceptions.WORCError, IndexError

            -

            IndexError in the WORC system

            -
            -
            -__module__ = 'WORC.addexceptions'¶
            -
            - -
            - -
            -
            -exception WORC.addexceptions.WORCKeyError[source]¶
            -

            Bases: WORC.addexceptions.WORCError, KeyError

            -

            KeyError in the WORC system

            -
            -
            -__module__ = 'WORC.addexceptions'¶
            -
            - -
            - -
            -
            -exception WORC.addexceptions.WORCNotImplementedError[source]¶
            -

            Bases: WORC.addexceptions.WORCError, NotImplementedError

            -

            This function/method has not been implemented on purpose (e.g. should be -overwritten in a sub-class)

            -
            -
            -__module__ = 'WORC.addexceptions'¶
            -
            - -
            - -
            -
            -exception WORC.addexceptions.WORCTypeError[source]¶
            -

            Bases: WORC.addexceptions.WORCError, TypeError

            -

            TypeError in the WORC system

            -
            -
            -__module__ = 'WORC.addexceptions'¶
            -
            - -
            - -
            -
            -exception WORC.addexceptions.WORCValueError[source]¶
            -

            Bases: WORC.addexceptions.WORCError, ValueError

            -

            ValueError in the WORC system

            -
            -
            -__module__ = 'WORC.addexceptions'¶
            -
            - -
            - -
            - -
            - - -
            - -
            -
            - - - - -
            - -
            -

            - © Copyright 2016 -- 2019, Biomedical Imaging Group Rotterdam, Departments of Medical Informatics and Radiology, Erasmus MC, Rotterdam, The Netherlands - -

            -
            - Built with Sphinx using a theme provided by Read the Docs. - -
            - -
            -
            - -
            - -
            - - - - - - - - - - - - \ No newline at end of file diff --git a/build/lib/WORC/doc/_build/html/autogen/WORC.plotting.html b/build/lib/WORC/doc/_build/html/autogen/WORC.plotting.html deleted file mode 100644 index e5b7d314..00000000 --- a/build/lib/WORC/doc/_build/html/autogen/WORC.plotting.html +++ /dev/null @@ -1,551 +0,0 @@ - - - - - - - - - - - plotting Package — WORC 3.0.0 documentation - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
            - - - -
            - - - - - -
            - -
            - - - - - - - - - - - - - - - - - -
            - - - - -
            -
            -
            -
            - -
            -

            plotting Package¶

            -
            -

            compute_CI Module¶

            -
            -
            -WORC.plotting.compute_CI.compute_confidence(metric, N_train, N_test, alpha=0.95)[source]¶
            -

            Function to calculate the adjusted confidence interval -metric: numpy array containing the result for a metric for the different cross validations -(e.g. If 20 cross-validations are performed it is a list of length 20 with the calculated accuracy for -each cross validation) -N_train: Integer, number of training samples -N_test: Integer, number of test_samples -alpha: float ranging from 0 to 1 to calculate the alpha*100% CI, default 95%

            -
            - -
            -
            -WORC.plotting.compute_CI.compute_confidence_logit(metric, N_train, N_test, alpha=0.95)[source]¶
            -

            Function to calculate the adjusted confidence interval -metric: numpy array containing the result for a metric for the different cross validations -(e.g. If 20 cross-validations are performed it is a list of length 20 with the calculated accuracy for -each cross validation) -N_train: Integer, number of training samples -N_test: Integer, number of test_samples -alpha: float ranging from 0 to 1 to calculate the alpha*100% CI, default 95%

            -
            - -
            -
            -

            linstretch Module¶

            -
            -
            -WORC.plotting.linstretch.linstretch(i, i_max=255, i_min=0)[source]¶
            -

            Stretch the input image i pixel values from i_min to i_max

            -
            - -
            -
            -

            plot_ROC Module¶

            -
            -
            -WORC.plotting.plot_ROC.ROC_thresholding(fprt, tprt, thresholds, nsamples=20)[source]¶
            -

            Construct FPR and TPR ratios at different thresholds for the scores of an -estimator.

            -
            - -
            -
            -WORC.plotting.plot_ROC.main()[source]¶
            -
            - -
            -
            -WORC.plotting.plot_ROC.plot_ROC(prediction, pinfo, ensemble=1, label_type=None, output_png=None, output_tex=None, output_csv=None)[source]¶
            -
            - -
            -
            -WORC.plotting.plot_ROC.plot_ROC_CIc(y_truth, y_score, N_1, N_2, plot='default', alpha=0.95, verbose=False, DEBUG=False, tsamples=20)[source]¶
            -

            Plot a Receiver Operator Characteristic (ROC) curve with confidence intervals.

            -
            -
            tsamples: number of sample points on which to determine the confidence intervals.

            The sample pointsare used on the thresholds for y_score.

            -
            -
            -
            - -
            -
            -WORC.plotting.plot_ROC.plot_single_ROC(y_truth, y_score, verbose=False)[source]¶
            -

            Get the False Positive Ratio (FPR) and True Positive Ratio (TPR) -for the ground truth and score of a single estimator. These ratios -can be used to plot a Receiver Operator Characteristic (ROC) curve.

            -
            - -
            -
            -

            plot_SVM Module¶

            -
            -
            -WORC.plotting.plot_SVM.main()[source]¶
            -
            - -
            -
            -WORC.plotting.plot_SVM.plot_SVM(prediction, label_data, label_type, show_plots=False, alpha=0.95, ensemble=False, verbose=True, ensemble_scoring=None, output='stats', modus='singlelabel')[source]¶
            -

            Plot the output of a single binary estimator, e.g. a SVM.

            -
            -
            prediction: pandas dataframe or string, mandatory

            output of trainclassifier function, either a pandas dataframe -or a HDF5 file

            -
            -
            label_data: string, mandatory

            Contains the path referring to a .txt file containing the -patient label(s) and value(s) to be used for learning. See -the Github Wiki for the format.

            -
            -
            label_type: string, mandatory

            Name of the label to extract from the label data to test the -estimator on.

            -
            -
            show_plots: Boolean, default False

            Determine whether matplotlib performance plots are made.

            -
            -
            alpha: float, default 0.95

            Significance of confidence intervals.

            -
            -
            ensemble: False, integer or ‘Caruana’

            Determine whether an ensemble will be created. If so, -either provide an integer to determine how many of the -top performing classifiers should be in the ensemble, or use -the string “Caruana†to use smart ensembling based on -Caruana et al. 2004.

            -
            -
            verbose: boolean, default True

            Plot intermedate messages.

            -
            -
            ensemble_scoring: string, default None

            Metric to be used for evaluating the ensemble. If None, -the option set in the prediction object will be used.

            -
            -
            output: string, default stats

            Determine which results are put out. If stats, the statistics of the -estimator will be returned. If scores, the scores will be returned.

            -
            -
            -

            Depending on the output parameters, the following outputs are returned:

            -

            If output == ‘stats’: -stats: dictionary

            -
            -

            Contains the confidence intervals of the performance metrics -and the number of times each patient was classifier correctly -or incorrectly.

            -
            -

            If output == ‘scores’: -y_truths: list

            -
            -

            Contains the true label for each object.

            -
            -
            -
            y_scores: list

            Contains the score (e.g. posterior) for each object.

            -
            -
            y_predictions: list

            Contains the predicted label for each object.

            -
            -
            PIDs: list

            Contains the patient ID/name for each object.

            -
            -
            -
            - -
            -
            -

            plot_SVR Module¶

            -
            -
            -

            plot_barchart Module¶

            -
            -
            -WORC.plotting.plot_barchart.count_parameters(parameters)[source]¶
            -
            - -
            -
            -WORC.plotting.plot_barchart.main()[source]¶
            -
            - -
            -
            -WORC.plotting.plot_barchart.paracheck(parameters)[source]¶
            -
            - -
            -
            -WORC.plotting.plot_barchart.plot_barchart(prediction, estimators=10, label_type=None, output_tex=None, output_png=None)[source]¶
            -

            Make a barchart of the top X hyperparameters settings of the ranked -estimators in all cross validation iterations.

            -
            -
            prediction: filepath, mandatory

            Path pointing to the .hdf5 file which was is the output of the -trainclassifier function.

            -
            -
            estimators: integer, default 10

            Number of hyperparameter settings/estimators used in each cross -validation. The settings are ranked, so when supplying e.g. 10, -the best 10 settings in each cross validation setting will be used.

            -
            -
            label_type: string, default None

            The name of the label predicted by the estimator. If None, -the first label from the prediction file will be used.

            -
            -
            output_tex: filepath, optional

            If given, the barchart will be written to this tex file.

            -
            -
            output_png: filepath, optional

            If given, the barchart will be written to this png file.

            -
            -
            -
            -
            fig: matplotlib figure

            The figure in which the barchart is plotted.

            -
            -
            -
            - -
            -
            -WORC.plotting.plot_barchart.plot_bars(params, normalization_factor=None, figwidth=20, fontsize=20)[source]¶
            -
            - -
            -
            -

            plot_boxplot Module¶

            -
            -
            -WORC.plotting.plot_boxplot.generate_boxplots(image_features, label_data, outputfolder)[source]¶
            -

            Generate boxplots of the feature values among different objects.

            -
            -
            features: list, mandatory

            List with a dictionary of the feature labels and values for each patient.

            -
            -
            label_data: pandas dataframe, mandatory

            Dataframe containing the labels of the objects.

            -
            -
            outputfolder: path, mandatory

            Folder to which the output boxplots should be written.

            -
            -
            -
            - -
            -
            -WORC.plotting.plot_boxplot.main()[source]¶
            -
            - -
            -
            -

            plot_images Module¶

            -
            -
            -WORC.plotting.plot_images.bbox_2D(img, mask, padding=[1, 1], img2=None)[source]¶
            -
            - -
            -
            -WORC.plotting.plot_images.plot_im_and_overlay(image, mask, figsize=(3, 3), alpha=0.15)[source]¶
            -

            Plot an image in a matplotlib figure and overlay with a mask.

            -
            - -
            -
            -WORC.plotting.plot_images.slicer(image, mask, output_name, output_name_zoom, thresholds=[-240, 160], zoomfactor=4)[source]¶
            -

            image and mask should both be arrays

            -
            - -
            -
            -

            plot_ranked_scores Module¶

            -
            -
            -WORC.plotting.plot_ranked_scores.example()[source]¶
            -
            - -
            -
            -WORC.plotting.plot_ranked_scores.main()[source]¶
            -
            - -
            -
            -WORC.plotting.plot_ranked_scores.plot_ranked_images(pinfo, label_type, images, segmentations, ranked_truths, ranked_scores, ranked_PIDs, output_zip=None, output_itk=None, zoomfactor=4)[source]¶
            -
            - -
            -
            -WORC.plotting.plot_ranked_scores.plot_ranked_percentages(estimator, pinfo, label_type=None, ensemble=50, output_csv=None)[source]¶
            -
            - -
            -
            -WORC.plotting.plot_ranked_scores.plot_ranked_posteriors(estimator, pinfo, label_type=None, ensemble=50, output_csv=None)[source]¶
            -
            - -
            -
            -WORC.plotting.plot_ranked_scores.plot_ranked_scores(estimator, pinfo, label_type, scores='percentages', images=[], segmentations=[], ensemble=50, output_csv=None, output_zip=None, output_itk=None)[source]¶
            -

            Rank the patients according to their average score. The score can either -be the average posterior or the percentage of times the patient was -classified correctly in the cross validations. Additionally, -the middle slice of each patient is plot and saved according to the ranking.

            -
            -
            estimator: filepath, mandatory

            Path pointing to the .hdf5 file which was is the output of the -trainclassifier function.

            -
            -
            pinfo: filepath, mandatory

            Path pointint to the .txt file which contains the patient label -information.

            -
            -
            label_type: string, default None

            The name of the label predicted by the estimator. If None, -the first label from the prediction file will be used.

            -
            -
            scores: string, default percentages

            Type of scoring to be used. Either ‘posteriors’ or ‘percentages’.

            -
            -
            images: list, optional

            List containing the filepaths to the ITKImage image files of the -patients.

            -
            -
            segmentations: list, optional

            List containing the filepaths to the ITKImage segmentation files of -the patients.

            -
            -
            ensemble: integer or string, optional

            Method to be used for ensembling. Either an integer for a fixed size -or ‘Caruana’ for the Caruana method, see the SearchCV function for more -details.

            -
            -
            output_csv: filepath, optional

            If given, the scores will be written to this csv file.

            -
            -
            output_zip: filepath, optional

            If given, the images will be plotted and the pngs saved to this -zip file.

            -
            -
            output_itk: filepath, optional

            WIP

            -
            -
            -
            - -
            -
            -

            plotminmaxresponse Module¶

            -
            -
            -

            scatterplot Module¶

            -
            -
            - - -
            - -
            -
            - - - - -
            - -
            -

            - © Copyright 2016 -- 2019, Biomedical Imaging Group Rotterdam, Departments of Medical Informatics and Radiology, Erasmus MC, Rotterdam, The Netherlands - -

            -
            - Built with Sphinx using a theme provided by Read the Docs. - -
            - -
            -
            - -
            - -
            - - - - - - - - - - - - \ No newline at end of file diff --git a/build/lib/WORC/doc/_build/html/autogen/WORC.processing.html b/build/lib/WORC/doc/_build/html/autogen/WORC.processing.html deleted file mode 100644 index 47eb55af..00000000 --- a/build/lib/WORC/doc/_build/html/autogen/WORC.processing.html +++ /dev/null @@ -1,406 +0,0 @@ - - - - - - - - - - - processing Package — WORC 3.0.0 documentation - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
            - - - -
            - - - - - -
            - -
            - - - - - - - - - - - - - - - - - -
            - - - - -
            -
            -
            -
            - -
            -

            processing Package¶

            -
            -

            ExtractNLargestBlobsn Module¶

            -
            -
            -WORC.processing.ExtractNLargestBlobsn.ExtractNLargestBlobsn(binaryImage, numberToExtract=1)[source]¶
            -

            Extract N largest blobs from binary image.

            -
            -
            Arguments:

            binaryImage: boolean numpy array one or several contours. -numberToExtract: number of blobs to extract (integer).

            -
            -
            Returns:
            -
            binaryImage: boolean numpy are containing only the N

            extracted blobs.

            -
            -
            -
            -
            -
            - -
            -
            -

            RTStructReader Module¶

            -
            -
            -

            classes Module¶

            -
            -
            -class WORC.processing.classes.switch(value)[source]¶
            -

            Bases: object

            -

            Object to mimic the MATLAB switch - case statement.

            -
            -
            -__dict__ = mappingproxy({'__module__': 'WORC.processing.classes', '__doc__': ' Object to mimic the MATLAB switch - case statement.', '__init__': <function switch.__init__>, '__iter__': <function switch.__iter__>, 'match': <function switch.match>, '__dict__': <attribute '__dict__' of 'switch' objects>, '__weakref__': <attribute '__weakref__' of 'switch' objects>})¶
            -
            - -
            -
            -__init__(value)[source]¶
            -

            Initialize self. See help(type(self)) for accurate signature.

            -
            - -
            -
            -__iter__()[source]¶
            -

            Return the match method once, then stop

            -
            - -
            -
            -__module__ = 'WORC.processing.classes'¶
            -
            - -
            -
            -__weakref__¶
            -

            list of weak references to the object (if defined)

            -
            - -
            -
            -match(*args)[source]¶
            -

            Indicate whether or not to enter a case suite

            -
            - -
            - -
            -
            -

            label_processing Module¶

            -
            -
            -WORC.processing.label_processing.findlabeldata(patientinfo, label_type, filenames, image_features_temp=None)[source]¶
            -

            Load the label data and match to the unage features.

            -
            -
            Args:

            patientinfo (string): file with patient label data -label_type (string): name of the label read out from patientinfo -filenames (list): names of the patient feature files, used for matching -image_features (np.array or list): array of the features

            -
            -
            Returns:

            label_data (dict): contains patient ids, their labels and the label name

            -
            -
            -
            - -
            -
            -WORC.processing.label_processing.load_config_XNAT(config_file_path)[source]¶
            -

            Configparser for retreiving patient data from XNAT.

            -
            - -
            -
            -WORC.processing.label_processing.load_label_XNAT(label_info)[source]¶
            -

            Load the patient IDs and label data from XNAT, Only works if you have a -file /resources/GENETICS/files/genetics.json for each patient containing -a single dictionary of all labels.

            -
            -
            Args:

            url (string): XNAT URL -project: XNAT project ID

            -
            -
            Returns:

            label_names (numpy array): Names of the different labels -patient_ID (numpy array): IDs of patients for which label data is

            -
            -

            loaded

            -
            -
            -
            label_status (numpy array): The status of the different labels

            for each patient

            -
            -
            -
            -
            -
            - -
            -
            -WORC.processing.label_processing.load_label_csv(input_file)[source]¶
            -

            Load the patient IDs and label data from the label file

            -
            -
            Args:

            input_file (string): Path of the label file

            -
            -
            Returns:

            label_names (numpy array): Names of the different labels -patient_ID (numpy array): IDs of patients for which label data is

            -
            -

            loaded

            -
            -
            -
            label_status (numpy array): The status of the different labels

            for each patient

            -
            -
            -
            -
            -
            - -
            -
            -WORC.processing.label_processing.load_label_txt(input_file)[source]¶
            -

            Load the patient IDs and label data from the label file

            -
            -
            Args:

            input_file (string): Path of the label file

            -
            -
            Returns:

            label_names (numpy array): Names of the different labels -patient_ID (numpy array): IDs of patients for which label data is

            -
            -

            loaded

            -
            -
            -
            label_status (numpy array): The status of the different labels

            for each patient

            -
            -
            -
            -
            -
            - -
            -
            -WORC.processing.label_processing.load_labels(label_file, label_type)[source]¶
            -

            Loads the label data from a label file

            -
            -
            Args:

            label_file (string): The path to the label file -label_type (list): List of the names of the labels to load

            -
            -
            Returns:
            -
            dict: A dict containing ‘patient_IDs’, ‘label’ and

            ‘label_type’

            -
            -
            -
            -
            -
            - -
            -
            - - -
            - -
            -
            - - - - -
            - -
            -

            - © Copyright 2016 -- 2019, Biomedical Imaging Group Rotterdam, Departments of Medical Informatics and Radiology, Erasmus MC, Rotterdam, The Netherlands - -

            -
            - Built with Sphinx using a theme provided by Read the Docs. - -
            - -
            -
            - -
            - -
            - - - - - - - - - - - - \ No newline at end of file diff --git a/build/lib/WORC/doc/_build/html/autogen/WORC.resources.fastr_tests.html b/build/lib/WORC/doc/_build/html/autogen/WORC.resources.fastr_tests.html deleted file mode 100644 index f5e3999e..00000000 --- a/build/lib/WORC/doc/_build/html/autogen/WORC.resources.fastr_tests.html +++ /dev/null @@ -1,273 +0,0 @@ - - - - - - - - - - - fastr_tests Package — WORC 3.0.0 documentation - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
            - - - -
            - - - - - -
            - -
            - - - - - - - - - - - - - - - - - -
            - - - - -
            -
            -
            -
            - -
            -

            fastr_tests Package¶

            -
            -

            CalcFeatures_test Module¶

            -
            -
            -WORC.resources.fastr_tests.CalcFeatures_test.create_network()[source]¶
            -
            - -
            -
            -WORC.resources.fastr_tests.CalcFeatures_test.main()[source]¶
            -
            - -
            -
            -WORC.resources.fastr_tests.CalcFeatures_test.sink_data(network)[source]¶
            -
            - -
            -
            -WORC.resources.fastr_tests.CalcFeatures_test.source_data(network)[source]¶
            -
            - -
            -
            -

            elastix_test Module¶

            -
            -
            -WORC.resources.fastr_tests.elastix_test.create_network()[source]¶
            -
            - -
            -
            -WORC.resources.fastr_tests.elastix_test.main()[source]¶
            -
            - -
            -
            -WORC.resources.fastr_tests.elastix_test.sink_data(network)[source]¶
            -
            - -
            -
            -WORC.resources.fastr_tests.elastix_test.source_data(network)[source]¶
            -
            - -
            -
            -

            segmentix_test Module¶

            -
            -
            -WORC.resources.fastr_tests.segmentix_test.create_network()[source]¶
            -
            - -
            -
            -WORC.resources.fastr_tests.segmentix_test.main()[source]¶
            -
            - -
            -
            -WORC.resources.fastr_tests.segmentix_test.sink_data(network)[source]¶
            -
            - -
            -
            -WORC.resources.fastr_tests.segmentix_test.source_data(network)[source]¶
            -
            - -
            -
            - - -
            - -
            -
            - - -
            - -
            -

            - © Copyright 2016 -- 2019, Biomedical Imaging Group Rotterdam, Departments of Medical Informatics and Radiology, Erasmus MC, Rotterdam, The Netherlands - -

            -
            - Built with Sphinx using a theme provided by Read the Docs. - -
            - -
            -
            - -
            - -
            - - - - - - - - - - - - \ No newline at end of file diff --git a/build/lib/WORC/doc/_build/html/autogen/WORC.tools.html b/build/lib/WORC/doc/_build/html/autogen/WORC.tools.html deleted file mode 100644 index c0132143..00000000 --- a/build/lib/WORC/doc/_build/html/autogen/WORC.tools.html +++ /dev/null @@ -1,441 +0,0 @@ - - - - - - - - - - - tools Package — WORC 3.0.0 documentation - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
            - - - -
            - - - - - -
            - -
            - - - - - - - - - - - - - - - - - -
            - - - - -
            -
            -
            -
            - -
            -

            tools Package¶

            -
            -

            Elastix Module¶

            -
            -
            -class WORC.tools.Elastix.Elastix[source]¶
            -

            Bases: object

            -
            -
            -__dict__ = mappingproxy({'__module__': 'WORC.tools.Elastix', '__init__': <function Elastix.__init__>, 'getparametermap': <function Elastix.getparametermap>, 'create_network': <function Elastix.create_network>, 'addchangeorder': <function Elastix.addchangeorder>, 'create_bbox': <function Elastix.create_bbox>, 'execute': <function Elastix.execute>, '__dict__': <attribute '__dict__' of 'Elastix' objects>, '__weakref__': <attribute '__weakref__' of 'Elastix' objects>, '__doc__': None})¶
            -
            - -
            -
            -__init__()[source]¶
            -

            Initialize self. See help(type(self)) for accurate signature.

            -
            - -
            -
            -__module__ = 'WORC.tools.Elastix'¶
            -
            - -
            -
            -__weakref__¶
            -

            list of weak references to the object (if defined)

            -
            - -
            -
            -addchangeorder()[source]¶
            -
            - -
            -
            -create_bbox(seg, pad=[2, 25, 25])[source]¶
            -

            Create a bounding box around an input segmentation -with a certain padding

            -
            - -
            -
            -create_network(nettype)[source]¶
            -
            - -
            -
            -execute()[source]¶
            -
            - -
            -
            -getparametermap(model='affine', size=(512, 512, 128))[source]¶
            -
            - -
            - -
            -
            -

            Evaluate Module¶

            -
            -
            -class WORC.tools.Evaluate.Evaluate(label_type, ensemble=50, scores='percentages', network=None, features=None, fastr_plugin='ProcessPoolExecution', name='Example')[source]¶
            -

            Bases: object

            -
            -
            -__dict__ = mappingproxy({'__module__': 'WORC.tools.Evaluate', '__init__': <function Evaluate.__init__>, 'create_network': <function Evaluate.create_network>, 'set': <function Evaluate.set>, 'execute': <function Evaluate.execute>, '__dict__': <attribute '__dict__' of 'Evaluate' objects>, '__weakref__': <attribute '__weakref__' of 'Evaluate' objects>, '__doc__': None})¶
            -
            - -
            -
            -__init__(label_type, ensemble=50, scores='percentages', network=None, features=None, fastr_plugin='ProcessPoolExecution', name='Example')[source]¶
            -

            Build a network that evaluates the performance of an estimator.

            -
            -
            network: fastr network, default None

            If you input a network, the evaluate network is added -to the existing network.

            -
            -
            -
            - -
            -
            -__module__ = 'WORC.tools.Evaluate'¶
            -
            - -
            -
            -__weakref__¶
            -

            list of weak references to the object (if defined)

            -
            - -
            -
            -create_network()[source]¶
            -

            Add evaluate components to network.

            -
            - -
            -
            -execute()[source]¶
            -

            Execute the network through the fastr.network.execute command.

            -
            - -
            -
            -set(estimator=None, pinfo=None, images=None, segmentations=None, config=None, features=None, sink_data={})[source]¶
            -

            Set the sources and sinks based on the provided attributes.

            -
            - -
            - -
            -
            -

            Slicer Module¶

            -
            -
            -class WORC.tools.Slicer.Slicer(images=None, segmentations=None, network=None, fastr_plugin='ProcessPoolExecution', name='Example')[source]¶
            -

            Bases: object

            -
            -
            -__dict__ = mappingproxy({'__module__': 'WORC.tools.Slicer', '__init__': <function Slicer.__init__>, 'create_network': <function Slicer.create_network>, 'set': <function Slicer.set>, 'execute': <function Slicer.execute>, '__dict__': <attribute '__dict__' of 'Slicer' objects>, '__weakref__': <attribute '__weakref__' of 'Slicer' objects>, '__doc__': None})¶
            -
            - -
            -
            -__init__(images=None, segmentations=None, network=None, fastr_plugin='ProcessPoolExecution', name='Example')[source]¶
            -

            Build a network that evaluates the performance of an estimator.

            -
            -
            network: fastr network, default None

            If you input a network, the evaluate network is added -to the existing network.

            -
            -
            -
            - -
            -
            -__module__ = 'WORC.tools.Slicer'¶
            -
            - -
            -
            -__weakref__¶
            -

            list of weak references to the object (if defined)

            -
            - -
            -
            -create_network()[source]¶
            -

            Add evaluate components to network.

            -
            - -
            -
            -execute()[source]¶
            -

            Execute the network through the fastr.network.execute command.

            -
            - -
            -
            -set(images=None, segmentations=None, sink_data={})[source]¶
            -

            Set the sources and sinks based on the provided attributes.

            -
            - -
            - -
            -
            -

            Transformix Module¶

            -
            -
            -class WORC.tools.Transformix.Transformix[source]¶
            -

            Bases: object

            -
            -
            -__dict__ = mappingproxy({'__module__': 'WORC.tools.Transformix', '__init__': <function Transformix.__init__>, 'create_network': <function Transformix.create_network>, 'execute': <function Transformix.execute>, '__dict__': <attribute '__dict__' of 'Transformix' objects>, '__weakref__': <attribute '__weakref__' of 'Transformix' objects>, '__doc__': None})¶
            -
            - -
            -
            -__init__()[source]¶
            -

            Initialize self. See help(type(self)) for accurate signature.

            -
            - -
            -
            -__module__ = 'WORC.tools.Transformix'¶
            -
            - -
            -
            -__weakref__¶
            -

            list of weak references to the object (if defined)

            -
            - -
            -
            -create_network()[source]¶
            -
            - -
            -
            -execute()[source]¶
            -
            - -
            - -
            -
            - - -
            - -
            -
            - - - - -
            - -
            -

            - © Copyright 2016 -- 2019, Biomedical Imaging Group Rotterdam, Departments of Medical Informatics and Radiology, Erasmus MC, Rotterdam, The Netherlands - -

            -
            - Built with Sphinx using a theme provided by Read the Docs. - -
            - -
            -
            - -
            - -
            - - - - - - - - - - - - \ No newline at end of file diff --git a/build/lib/WORC/doc/_build/html/genindex.html b/build/lib/WORC/doc/_build/html/genindex.html deleted file mode 100644 index e862e476..00000000 --- a/build/lib/WORC/doc/_build/html/genindex.html +++ /dev/null @@ -1,873 +0,0 @@ - - - - - - - - - - - - Index — WORC 3.0.0 documentation - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
            - - - -
            - - - - - -
            - -
            - - - - - - - - - - - - - - - - - -
            - -
              - -
            • Docs »
            • - -
            • Index
            • - - -
            • - - - -
            • - -
            - - -
            -
            -
            -
            - - -

            Index

            - -
            - _ - | A - | B - | C - | D - | E - | F - | G - | I - | L - | M - | N - | P - | R - | S - | T - | W - -
            -

            _

            - - - -
            - -

            A

            - - - -
            - -

            B

            - - - -
            - -

            C

            - - - -
            - -

            D

            - - - -
            - -

            E

            - - - -
            - -

            F

            - - -
            - -

            G

            - - - -
            - -

            I

            - - - -
            - -

            L

            - - - -
            - -

            M

            - - - -
            - -

            N

            - - -
            - -

            P

            - - - -
            - -

            R

            - - - -
            - -

            S

            - - - -
            - -

            T

            - - - -
            - -

            W

            - - - -
            - - - -
            - -
            -
            - - -
            - -
            -

            - © Copyright 2016 -- 2019, Biomedical Imaging Group Rotterdam, Departments of Medical Informatics and Radiology, Erasmus MC, Rotterdam, The Netherlands - -

            -
            - Built with Sphinx using a theme provided by Read the Docs. - -
            - -
            -
            - -
            - -
            - - - - - - - - - - - - \ No newline at end of file diff --git a/build/lib/WORC/doc/_build/html/index.html b/build/lib/WORC/doc/_build/html/index.html deleted file mode 100644 index 42b81cfb..00000000 --- a/build/lib/WORC/doc/_build/html/index.html +++ /dev/null @@ -1,435 +0,0 @@ - - - - - - - - - - - WORC — WORC 3.0.0 documentation - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
            - - - -
            - - - - - -
            - -
            - - - - - - - - - - - - - - - - - -
            - - - - -
            -
            -
            -
            - -
            -

            WORC¶

            -
            -

            Workflow for Optimal Radiomics Classification¶

            -

            WORC is an open-source python package for the easy execution of end-to-end -radiomics pipelines.

            -

            We aim to establish a general radiomics platform supporting easy -integration of other tools. With our modular build and support of -different software languages (Python, MATLAB, R, executables etc.), we want -to facilitate and stimulate collaboration, standardisation and -comparison of different radiomics approaches. By combining this in a -single framework, we hope to find an universal radiomics strategy that -can address various problems.

            -

            WORC is open-source (licensed under the Apache 2.0 license) and hosted on Github at https://github.com/MStarmans91/WORC

            -

            For support, go to the issues on the Gibhub page: https://github.com/MStarmans91/WORC/issues

            -

            To get yourself a copy, see the Installation

            -

            The official documentation can be found at WORC.readthedocs.io

            -

            For Tutorials on WORC, both for beginner and advanced WORCflows, please

            -

            see our Tutorial repository https://github.com/MStarmans91/WORCTutorial.

            -

            The article on WORC is currently in press. WORC has been presented in the following:

            -
            -

            M. P. A. Starmans, S. R. van der Voort, M. Vos, F. Incekara, J. J. Visser, M. Smits, M. G. Thomeer, W. J. Niessen and S. Klein. “Fully automatic construction of optimal radiomics workflows.†European Conference of Radiology (ECR) 2019.

            -

            Martijn P. A. Starmans, Sebastian R. van der Voort, Razvan L. Miclea, Melissa Vos, Fatih Incekara, Milea J.M. Timbergen, Maarten M.J. Wijnenga, Guillaume A. Padmos, G.H.J. van Leenders, George Kapsas, Martin J. van den Bent, Arnaud J.P.E. Vincent, Dirk J. Grünhagen, Cornelis Verhoef, Stefan Sleijfer, Jacob J. Visser, Marion Smits, Maarten, G. Thomeer, Wiro J. Niessen, and Stefan Klein. “Harmonizing radiomics among applications through adaptive workflow optimization.†European Society of Medical Imaging Informatics (EuSoMII) Annual Meeting 2019.

            -
            -

            WORC has been used in the following studies:

            -
            -

            M. P. A. Starmans, R. Miclea, S. R. van der Voort, W. J. Niessen, M. G. Thomeer and S. Klein. “Classification of malignant and benign liver tumors using a radiomics approach.†Proceedings Volume 10574, Medical Imaging 2018: Image Processing; 105741D (2018) .

            -

            Milea J.M. Timbergen*, Martijn P. A. Starmans*, Melissa Vos, Sebastian R. van der Voort, Guillaume A. Padmos, Wouter Kessels, Wiro J. Niessen, Geert J.L.H. van Leenders, Dirk J. Grünhagen, Stefan Sleijfer, Cornelis Verhoef, Stefan Klein and Jacob J. Visser. “Mutation stratification of desmoid-type fibromatosis using a Radiomics approach.†Desmoid Tumor Research Foundation (DTRF) 2018.

            -

            `Melissa Vos*, Martijn P. A. Starmans*, Milea J.M. Timbergen, Sebastian R. van der Voort, Guillaume A. Padmos, Wouter Kessels, Wiro J. Niessen, Geert J.L.H. van Leenders, Dirk J. Grünhagen, Stefan Sleijfer, Cornelis Verhoef, Stefan Klein and Jacob J. Visser. "Differentiating well-differentiated liposarcomas from lipomas using a Radiomics approach." ConnectiveTissueOncologySociety (CTOS) 2018.`_

            -

            `Milea J.M. Timbergen*, Martijn P. A. Starmans*, Melissa Vos, Sebastian R. van der Voort, Guillaume A. Padmos, Wouter Kessels, Wiro J. Niessen, Geert J.L.H. van Leenders, Dirk J. Grünhagen, Stefan Sleijfer, Cornelis Verhoef, Stefan Klein and Jacob J. Visser. "Mutation stratification of desmoid-type fibromatosis using a Radiomics approach." ConnectiveTissueOncologySociety (CTOS) 2018.`_

            -

            Martijn P. A. Starmans, Sebastian R. van der Voort, Razvan L. Miclea, Melissa Vos, Fatih Incekara, Milea J.M. Timbergen, Maarten M.J. Wijnenga, Guillaume A. Padmos, Wouter Kessels, G.H.J. van Leenders, George Kapsas, Martin J. van den Bent, Arnaud J.P.E. Vincent, Dirk J. Grünhagen, Cornelis Verhoef, Stefan Sleijfer, Jacob J. Visser, Marion Smits, Maarten, G. Thomeer, Wiro J. Niessen, and Stefan Klein. “Fully Automatic Construction of Optimal Radiomics Workflows .†Bio-Medical Engineering (BME) Conference 2019.

            -

            M. P. A. Starmans, R. Miclea, S. R. van der Voort, W. J. Niessen, S. Klein and M. G. Thomeer. “Classification of malignant and benign liver tumours using a radiomics approach.†European Conference of Radiology (ECR) 2019.

            -

            M. P. A. Starmans, A. Blazevic, S. R. van der Voort, T. Brabander, J. Hofland, W. J. Niessen, W. W. de Herder and S. Klein. “Prediction of surgery requirement in mesenteric fibrosis on CT using a radiomics approach.†European Conference of Radiology (ECR) 2019.

            -

            Jose M. Castillo T., Martijn P. A. Starmans, Ivo Schoots, Wiro J. Niessen, Stefan Klein, Jifke F. Veenland. “CLASSIFICATION OF PROSTATE CANCER: HIGH GRADE VERSUS LOW GRADE USING A RADIOMICS APPROACH.†IEEE International Symposium on Biomedical Imaging (ISBI) 2019.

            -
            -

            WORC is made possible by contributions from the following people: Martijn Starmans, and Stefan Klein

            - -
            -

            WORC User reference¶

            -
            -
            -
            - -
            -

            Indices and tables¶

            - -
            -
            -
            - - -
            - -
            -
            - - - - -
            - -
            -

            - © Copyright 2016 -- 2019, Biomedical Imaging Group Rotterdam, Departments of Medical Informatics and Radiology, Erasmus MC, Rotterdam, The Netherlands - -

            -
            - Built with Sphinx using a theme provided by Read the Docs. - -
            - -
            -
            - -
            - -
            - - - - - - - - - - - - \ No newline at end of file diff --git a/build/lib/WORC/doc/_build/html/objects.inv b/build/lib/WORC/doc/_build/html/objects.inv deleted file mode 100644 index 0ded56b5..00000000 Binary files a/build/lib/WORC/doc/_build/html/objects.inv and /dev/null differ diff --git a/build/lib/WORC/doc/_build/html/py-modindex.html b/build/lib/WORC/doc/_build/html/py-modindex.html deleted file mode 100644 index f64a8ce9..00000000 --- a/build/lib/WORC/doc/_build/html/py-modindex.html +++ /dev/null @@ -1,403 +0,0 @@ - - - - - - - - - - - Python Module Index — WORC 3.0.0 documentation - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
            - - - -
            - - - - - -
            - -
            - - - - - - - - - - - - - - - - - -
            - -
              - -
            • Docs »
            • - -
            • Python Module Index
            • - - -
            • - -
            • - -
            - - -
            -
            -
            -
            - - -

            Python Module Index

            - -
            - w -
            - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
             
            - w
            - WORC -
                - WORC.__init__ -
                - WORC.addexceptions -
                - WORC.classification.AdvancedSampler -
                - WORC.classification.construct_classifier -
                - WORC.classification.estimators -
                - WORC.classification.metrics -
                - WORC.classification.RankedSVM -
                - WORC.featureprocessing -
                - WORC.featureprocessing.Imputer -
                - WORC.featureprocessing.Relief -
                - WORC.featureprocessing.SelectGroups -
                - WORC.featureprocessing.SelectIndividuals -
                - WORC.featureprocessing.StatisticalTestThreshold -
                - WORC.IOparser.config_io_classifier -
                - WORC.IOparser.config_preprocessing -
                - WORC.IOparser.config_segmentix -
                - WORC.IOparser.config_WORC -
                - WORC.IOparser.file_io -
                - WORC.plotting.compute_CI -
                - WORC.plotting.linstretch -
                - WORC.plotting.plot_barchart -
                - WORC.plotting.plot_boxplot -
                - WORC.plotting.plot_images -
                - WORC.plotting.plot_ranked_scores -
                - WORC.plotting.plot_ROC -
                - WORC.plotting.plot_SVM -
                - WORC.processing.classes -
                - WORC.processing.ExtractNLargestBlobsn -
                - WORC.processing.label_processing -
                - WORC.resources.fastr_tests.CalcFeatures_test -
                - WORC.resources.fastr_tests.elastix_test -
                - WORC.resources.fastr_tests.segmentix_test -
                - WORC.tools.Elastix -
                - WORC.tools.Evaluate -
                - WORC.tools.Slicer -
                - WORC.tools.Transformix -
                - WORC.WORC -
            - - -
            - -
            -
            - - -
            - -
            -

            - © Copyright 2016 -- 2019, Biomedical Imaging Group Rotterdam, Departments of Medical Informatics and Radiology, Erasmus MC, Rotterdam, The Netherlands - -

            -
            - Built with Sphinx using a theme provided by Read the Docs. - -
            - -
            -
            - -
            - -
            - - - - - - - - - - - - \ No newline at end of file diff --git a/build/lib/WORC/doc/_build/html/search.html b/build/lib/WORC/doc/_build/html/search.html deleted file mode 100644 index 51bc0689..00000000 --- a/build/lib/WORC/doc/_build/html/search.html +++ /dev/null @@ -1,219 +0,0 @@ - - - - - - - - - - - Search — WORC 3.0.0 documentation - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
            - - - -
            - - - - - -
            - -
            - - - - - - - - - - - - - - - - - -
            - -
              - -
            • Docs »
            • - -
            • Search
            • - - -
            • - - - -
            • - -
            - - -
            -
            -
            -
            - - - - -
            - -
            - -
            - -
            -
            - - -
            - -
            -

            - © Copyright 2016 -- 2019, Biomedical Imaging Group Rotterdam, Departments of Medical Informatics and Radiology, Erasmus MC, Rotterdam, The Netherlands - -

            -
            - Built with Sphinx using a theme provided by Read the Docs. - -
            - -
            -
            - -
            - -
            - - - - - - - - - - - - - - - - - \ No newline at end of file diff --git a/build/lib/WORC/doc/_build/html/searchindex.js b/build/lib/WORC/doc/_build/html/searchindex.js deleted file mode 100644 index 7c1f2dbc..00000000 --- a/build/lib/WORC/doc/_build/html/searchindex.js +++ /dev/null @@ -1 +0,0 @@ -Search.setIndex({docnames:["autogen/WORC","autogen/WORC.IOparser","autogen/WORC.classification","autogen/WORC.featureprocessing","autogen/WORC.plotting","autogen/WORC.processing","autogen/WORC.resources.fastr_tests","autogen/WORC.tools","index","static/changelog","static/configuration","static/file_description","static/introduction","static/quick_start","static/user_manual"],envversion:{"sphinx.domains.c":1,"sphinx.domains.changeset":1,"sphinx.domains.cpp":1,"sphinx.domains.javascript":1,"sphinx.domains.math":2,"sphinx.domains.python":1,"sphinx.domains.rst":1,"sphinx.domains.std":1,"sphinx.ext.intersphinx":1,"sphinx.ext.todo":1,"sphinx.ext.viewcode":1,sphinx:56},filenames:["autogen/WORC.rst","autogen/WORC.IOparser.rst","autogen/WORC.classification.rst","autogen/WORC.featureprocessing.rst","autogen/WORC.plotting.rst","autogen/WORC.processing.rst","autogen/WORC.resources.fastr_tests.rst","autogen/WORC.tools.rst","index.rst","static/changelog.rst","static/configuration.rst","static/file_description.rst","static/introduction.rst","static/quick_start.rst","static/user_manual.rst"],objects:{"WORC.IOparser":{config_WORC:[1,0,0,"-"],config_io_classifier:[1,0,0,"-"],config_preprocessing:[1,0,0,"-"],config_segmentix:[1,0,0,"-"],file_io:[1,0,0,"-"]},"WORC.IOparser.config_WORC":{load_config:[1,1,1,""]},"WORC.IOparser.config_io_classifier":{load_config:[1,1,1,""]},"WORC.IOparser.config_preprocessing":{load_config:[1,1,1,""]},"WORC.IOparser.config_segmentix":{load_config:[1,1,1,""]},"WORC.IOparser.file_io":{load_data:[1,1,1,""]},"WORC.WORC":{Tools:[0,2,1,""],WORC:[0,2,1,""]},"WORC.WORC.Tools":{__dict__:[0,3,1,""],__init__:[0,4,1,""],__module__:[0,3,1,""],__weakref__:[0,3,1,""]},"WORC.WORC.WORC":{__dict__:[0,3,1,""],__init__:[0,4,1,""],__module__:[0,3,1,""],__weakref__:[0,3,1,""],add_tools:[0,4,1,""],build:[0,4,1,""],build_testing:[0,4,1,""],build_training:[0,4,1,""],defaultconfig:[0,4,1,""],execute:[0,4,1,""],set:[0,4,1,""]},"WORC.addexceptions":{WORCAssertionError:[0,5,1,""],WORCError:[0,5,1,""],WORCIOError:[0,5,1,""],WORCIndexError:[0,5,1,""],WORCKeyError:[0,5,1,""],WORCNotImplementedError:[0,5,1,""],WORCTypeError:[0,5,1,""],WORCValueError:[0,5,1,""]},"WORC.addexceptions.WORCAssertionError":{__module__:[0,3,1,""]},"WORC.addexceptions.WORCError":{__module__:[0,3,1,""],__weakref__:[0,3,1,""]},"WORC.addexceptions.WORCIOError":{__module__:[0,3,1,""],__weakref__:[0,3,1,""]},"WORC.addexceptions.WORCIndexError":{__module__:[0,3,1,""]},"WORC.addexceptions.WORCKeyError":{__module__:[0,3,1,""]},"WORC.addexceptions.WORCNotImplementedError":{__module__:[0,3,1,""]},"WORC.addexceptions.WORCTypeError":{__module__:[0,3,1,""]},"WORC.addexceptions.WORCValueError":{__module__:[0,3,1,""]},"WORC.classification":{AdvancedSampler:[2,0,0,"-"],RankedSVM:[2,0,0,"-"],construct_classifier:[2,0,0,"-"],estimators:[2,0,0,"-"],metrics:[2,0,0,"-"]},"WORC.classification.AdvancedSampler":{AdvancedSampler:[2,2,1,""],discrete_uniform:[2,2,1,""],exp_uniform:[2,2,1,""],log_uniform:[2,2,1,""]},"WORC.classification.AdvancedSampler.AdvancedSampler":{__dict__:[2,3,1,""],__init__:[2,4,1,""],__iter__:[2,4,1,""],__len__:[2,4,1,""],__module__:[2,3,1,""],__weakref__:[2,3,1,""]},"WORC.classification.AdvancedSampler.discrete_uniform":{__dict__:[2,3,1,""],__init__:[2,4,1,""],__module__:[2,3,1,""],__weakref__:[2,3,1,""],rvs:[2,4,1,""]},"WORC.classification.AdvancedSampler.exp_uniform":{__dict__:[2,3,1,""],__init__:[2,4,1,""],__module__:[2,3,1,""],__weakref__:[2,3,1,""],rvs:[2,4,1,""]},"WORC.classification.AdvancedSampler.log_uniform":{__dict__:[2,3,1,""],__init__:[2,4,1,""],__module__:[2,3,1,""],__weakref__:[2,3,1,""],rvs:[2,4,1,""]},"WORC.classification.RankedSVM":{RankSVM_test:[2,1,1,""],RankSVM_test_original:[2,1,1,""],RankSVM_train:[2,1,1,""],RankSVM_train_old:[2,1,1,""],is_empty:[2,1,1,""],neg_dual_func:[2,1,1,""]},"WORC.classification.construct_classifier":{construct_SVM:[2,1,1,""],construct_classifier:[2,1,1,""],create_param_grid:[2,1,1,""]},"WORC.classification.estimators":{RankedSVM:[2,2,1,""]},"WORC.classification.estimators.RankedSVM":{__init__:[2,4,1,""],__module__:[2,3,1,""],fit:[2,4,1,""],predict:[2,4,1,""],predict_proba:[2,4,1,""]},"WORC.classification.metrics":{ICC:[2,1,1,""],ICC_anova:[2,1,1,""],check_scoring:[2,1,1,""],multi_class_auc:[2,1,1,""],multi_class_auc_score:[2,1,1,""],pairwise_auc:[2,1,1,""],performance_multilabel:[2,1,1,""],performance_singlelabel:[2,1,1,""]},"WORC.featureprocessing":{Imputer:[3,0,0,"-"],Relief:[3,0,0,"-"],SelectGroups:[3,0,0,"-"],SelectIndividuals:[3,0,0,"-"],StatisticalTestThreshold:[3,0,0,"-"]},"WORC.featureprocessing.Imputer":{Imputer:[3,2,1,""]},"WORC.featureprocessing.Imputer.Imputer":{__dict__:[3,3,1,""],__init__:[3,4,1,""],__module__:[3,3,1,""],__weakref__:[3,3,1,""],fit:[3,4,1,""],transform:[3,4,1,""]},"WORC.featureprocessing.Relief":{SelectMulticlassRelief:[3,2,1,""]},"WORC.featureprocessing.Relief.SelectMulticlassRelief":{__abstractmethods__:[3,3,1,""],__init__:[3,4,1,""],__module__:[3,3,1,""],fit:[3,4,1,""],multi_class_relief:[3,4,1,""],single_class_relief:[3,4,1,""],transform:[3,4,1,""]},"WORC.featureprocessing.SelectGroups":{SelectGroups:[3,2,1,""]},"WORC.featureprocessing.SelectGroups.SelectGroups":{__abstractmethods__:[3,3,1,""],__init__:[3,4,1,""],__module__:[3,3,1,""],fit:[3,4,1,""],transform:[3,4,1,""]},"WORC.featureprocessing.SelectIndividuals":{SelectIndividuals:[3,2,1,""]},"WORC.featureprocessing.SelectIndividuals.SelectIndividuals":{__abstractmethods__:[3,3,1,""],__init__:[3,4,1,""],__module__:[3,3,1,""],fit:[3,4,1,""],transform:[3,4,1,""]},"WORC.featureprocessing.StatisticalTestThreshold":{StatisticalTestThreshold:[3,2,1,""]},"WORC.featureprocessing.StatisticalTestThreshold.StatisticalTestThreshold":{__abstractmethods__:[3,3,1,""],__init__:[3,4,1,""],__module__:[3,3,1,""],fit:[3,4,1,""],transform:[3,4,1,""]},"WORC.plotting":{compute_CI:[4,0,0,"-"],linstretch:[4,0,0,"-"],plot_ROC:[4,0,0,"-"],plot_SVM:[4,0,0,"-"],plot_barchart:[4,0,0,"-"],plot_boxplot:[4,0,0,"-"],plot_images:[4,0,0,"-"],plot_ranked_scores:[4,0,0,"-"]},"WORC.plotting.compute_CI":{compute_confidence:[4,1,1,""],compute_confidence_logit:[4,1,1,""]},"WORC.plotting.linstretch":{linstretch:[4,1,1,""]},"WORC.plotting.plot_ROC":{ROC_thresholding:[4,1,1,""],main:[4,1,1,""],plot_ROC:[4,1,1,""],plot_ROC_CIc:[4,1,1,""],plot_single_ROC:[4,1,1,""]},"WORC.plotting.plot_SVM":{main:[4,1,1,""],plot_SVM:[4,1,1,""]},"WORC.plotting.plot_barchart":{count_parameters:[4,1,1,""],main:[4,1,1,""],paracheck:[4,1,1,""],plot_barchart:[4,1,1,""],plot_bars:[4,1,1,""]},"WORC.plotting.plot_boxplot":{generate_boxplots:[4,1,1,""],main:[4,1,1,""]},"WORC.plotting.plot_images":{bbox_2D:[4,1,1,""],plot_im_and_overlay:[4,1,1,""],slicer:[4,1,1,""]},"WORC.plotting.plot_ranked_scores":{example:[4,1,1,""],main:[4,1,1,""],plot_ranked_images:[4,1,1,""],plot_ranked_percentages:[4,1,1,""],plot_ranked_posteriors:[4,1,1,""],plot_ranked_scores:[4,1,1,""]},"WORC.processing":{ExtractNLargestBlobsn:[5,0,0,"-"],classes:[5,0,0,"-"],label_processing:[5,0,0,"-"]},"WORC.processing.ExtractNLargestBlobsn":{ExtractNLargestBlobsn:[5,1,1,""]},"WORC.processing.classes":{"switch":[5,2,1,""]},"WORC.processing.classes.switch":{__dict__:[5,3,1,""],__init__:[5,4,1,""],__iter__:[5,4,1,""],__module__:[5,3,1,""],__weakref__:[5,3,1,""],match:[5,4,1,""]},"WORC.processing.label_processing":{findlabeldata:[5,1,1,""],load_config_XNAT:[5,1,1,""],load_label_XNAT:[5,1,1,""],load_label_csv:[5,1,1,""],load_label_txt:[5,1,1,""],load_labels:[5,1,1,""]},"WORC.resources.fastr_tests":{CalcFeatures_test:[6,0,0,"-"],elastix_test:[6,0,0,"-"],segmentix_test:[6,0,0,"-"]},"WORC.resources.fastr_tests.CalcFeatures_test":{create_network:[6,1,1,""],main:[6,1,1,""],sink_data:[6,1,1,""],source_data:[6,1,1,""]},"WORC.resources.fastr_tests.elastix_test":{create_network:[6,1,1,""],main:[6,1,1,""],sink_data:[6,1,1,""],source_data:[6,1,1,""]},"WORC.resources.fastr_tests.segmentix_test":{create_network:[6,1,1,""],main:[6,1,1,""],sink_data:[6,1,1,""],source_data:[6,1,1,""]},"WORC.tools":{Elastix:[7,0,0,"-"],Evaluate:[7,0,0,"-"],Slicer:[7,0,0,"-"],Transformix:[7,0,0,"-"]},"WORC.tools.Elastix":{Elastix:[7,2,1,""]},"WORC.tools.Elastix.Elastix":{__dict__:[7,3,1,""],__init__:[7,4,1,""],__module__:[7,3,1,""],__weakref__:[7,3,1,""],addchangeorder:[7,4,1,""],create_bbox:[7,4,1,""],create_network:[7,4,1,""],execute:[7,4,1,""],getparametermap:[7,4,1,""]},"WORC.tools.Evaluate":{Evaluate:[7,2,1,""]},"WORC.tools.Evaluate.Evaluate":{__dict__:[7,3,1,""],__init__:[7,4,1,""],__module__:[7,3,1,""],__weakref__:[7,3,1,""],create_network:[7,4,1,""],execute:[7,4,1,""],set:[7,4,1,""]},"WORC.tools.Slicer":{Slicer:[7,2,1,""]},"WORC.tools.Slicer.Slicer":{__dict__:[7,3,1,""],__init__:[7,4,1,""],__module__:[7,3,1,""],__weakref__:[7,3,1,""],create_network:[7,4,1,""],execute:[7,4,1,""],set:[7,4,1,""]},"WORC.tools.Transformix":{Transformix:[7,2,1,""]},"WORC.tools.Transformix.Transformix":{__dict__:[7,3,1,""],__init__:[7,4,1,""],__module__:[7,3,1,""],__weakref__:[7,3,1,""],create_network:[7,4,1,""],execute:[7,4,1,""]},WORC:{WORC:[0,0,0,"-"],__init__:[0,0,0,"-"],addexceptions:[0,0,0,"-"],featureprocessing:[3,0,0,"-"]}},objnames:{"0":["py","module","Python module"],"1":["py","function","Python function"],"2":["py","class","Python class"],"3":["py","attribute","Python attribute"],"4":["py","method","Python method"],"5":["py","exception","Python exception"]},objtypes:{"0":"py:module","1":"py:function","2":"py:class","3":"py:attribute","4":"py:method","5":"py:exception"},terms:{"04t10":[],"0rc1":8,"0x7fc950fa87d0":[],"0x7fc950fa8850":[],"0x7fc9661ccfd0":[],"105741d":8,"1st":[],"2nd":[],"58_umwemv":[],"5_interface__priority__enum__":[],"8_interface__priority__enum__":[],"95varianc":[],"abstract":[],"boolean":[0,4,5,9],"case":[5,14],"catch":0,"class":[0,2,3,7,8],"default":[0,2,3,4,7,9,10,13,14],"enum":[],"export":12,"final":[10,14],"float":[3,4],"function":[0,2,3,4,5,7,8,9,10,11],"gr\u00fcnhagen":8,"import":[2,3,10,12,14],"int":[2,3],"long":[],"new":[0,9,12],"public":[],"return":[0,1,2,4,5],"short":[],"static":[],"switch":[5,9],"throw":[],"true":[0,2,4],"try":12,"while":[],Added:8,Adding:[],For:[0,2,8,9,10,12,13,14],IDs:5,Not:12,One:2,PCs:[],ROS:[],SVs:2,That:[],The:[0,1,2,3,4,5,8,9,10,11,12],Then:[],There:[9,14],These:[4,10,14],USING:8,Use:9,Used:[],Using:12,Vos:8,With:8,__abstractmethods__:3,__add__:[],__contains__:[],__delitem__:[],__dict__:[0,2,3,5,7],__doc__:[0,2,3,5,7],__elastix_4:[],__fastr_result__:[],__getitem__:[],__getstate__:[],__iadd__:[],__init__:[0,2,3,5,7],__iter__:[2,5],__len__:2,__lshift__:[],__module__:[0,2,3,5,7],__radd__:[],__rrshift__:[],__setitem__:[],__sink_data__:[],__weakref__:[0,2,3,5,7],_init_provid:[],_train:[],abbrevi:[],abc:[],abort:[],about:[],abov:[12,14],acceler:[],accept:[2,9],access:[],accorad:2,accord:[2,4],account:[],accur:[0,2,5,7],accuraci:[2,4],achiev:[],achterberg:[],acquisit:12,across:[],act:10,action:[],activ:[],actual:[0,10,12,14],acycl:[],adapt:[8,12],add:[7,9,11,14],add_int:[],add_tool:0,addchangeord:7,added:[7,10,14],addexcept:8,addimag:[],adding:10,addint:[],addit:[0,9,14],addition:[1,4,10,13],address:8,adher:9,adjust:[4,9,10],adopt:[2,9],advanc:[8,13,14],advancedsampl:[0,8],advantag:10,advic:[],affect:[],affin:7,after:[9,14],again:[10,12],against:[],age:14,agent:[],aggreg:[],agre:[],aim:8,algorithm:[2,10,12],align:14,alingn:14,all:[0,1,2,3,4,5,9,10,12,13,14],allow:11,allow_non:2,almost:10,along:[3,12],alpha:[2,4],alpha_new:2,alpha_old:2,alphabet:[],alreadi:[12,13,14],also:[0,9,10,12,14],alt:[],alter:[2,13],altern:14,although:12,alwai:[2,12,14],among:[4,8,10],amount:12,analys:[],analysi:[],analyz:[],angl:[],ani:[2,12,13,14],annual:8,anoth:[12,14],anova:2,any_structur:2,anymor:9,anyon:[],anyth:12,apach:8,apart:[],api:[],app:[],appear:[],append:[9,10,14],appendix:2,appli:[9,10,12,14],applic:[8,12],approach:[3,8,10,12],appropri:0,arch:[],architectur:[],archiv:[],arg:[1,2,5],argument:[0,1,5],argv:[],arithmet:[],arnaud:8,around:[7,14],arrai:[1,2,3,4,5],articl:[8,12],ask:[],assertionerror:0,assign:[],associ:[],assum:[2,12,14],assumpt:[],ation:[],atla:[],attach:[],attempt:[],attribut:[0,2,3,5,7,8,9],auc:2,authent:[],author:[],autom:[],automat:[0,8,9,12,14],avail:[2,12],averag:4,avoid:[],awar:[],axi:3,back:[],backend:10,background:[],backward:[],barchart:[4,9],base:[0,2,3,4,5,7,9,10],basedatatyp:[],baseestim:[2,3],baseinput:[],baselin:12,baseoutput:[],basesearchcv:[],basesearchcvfastr:[],basesearchcvjoblib:[],bash:[],basic:12,bbox_2d:4,becaus:[],becom:[],been:[0,8,12],befor:[2,9,10,12,14],beginn:8,behav:[],behavior:2,behaviour:9,behind:[],beihang:[],being:[],bellow:[],belong:[0,2,3],below:[0,10,12,14],benefit:12,benign:8,bent:8,besid:[0,13],best:[4,10,12],best_estim:[],best_estimator_:[],best_index_:[],best_params_:[],best_score_:[],beta:2,better:[],between:2,bia:2,bibtext:[],big:9,bigr:10,bigr_erasmusmc:2,bin:[],binari:[3,4,5],binaryimag:5,bio:8,biomark:12,biomed:8,bitbucket:2,bitwise_xor:9,blazev:8,blob:5,block:[],blue:[],bme2019:[],bme:8,boil:[],bool:[],borrow:[],both:[2,4,8,9,12,14],bound:7,boundari:[],box:[7,13],boxplot:4,braband:8,brain_extract:[],brain_tissue_segment:[],brainextractiontool:[],branch:[],broadcast:[],brought:12,bug:9,build:[0,7,8,12,14],build_test:0,build_train:0,bundl:[],c_valu:2,cache_s:[],cad:2,caddementia:2,calcfeatur:[9,14],calcul:[2,3,4],call:14,callabl:[],callback:[],can:[0,2,3,4,8,9,10,12,13,14],cancel:[],cancer:8,candid:2,cannot:9,capac:[],capit:[],caption:[],cardin:9,cardinalti:[],caruana:4,cash:[10,12],castillo:8,categori:14,caus:[],certain:[7,10,14],cf_pyradio:[],challeg:2,challeng:2,chang:[8,10],changelog:8,chapter:[11,14],characterist:4,check:14,check_scor:2,choic:12,choos:[],chose:[],chosen:10,chunk:[],chunksdict:[],citat:[],cite:[],class_i:2,class_j:2,class_weight:[],classfic:[],classif:[0,9,14],classifi:[0,2,4,9,10],classifier_data:[],classifiermixin:2,classmethod:[],classpi:2,clear:[],clearer:[],clearli:[],clf:[],clinic:12,clone:13,close:[],closest:2,cluster:[10,12],cnb_alpha:[],code:8,coef0:[],coeffici:2,coliag:[],coliage_featur:3,collabor:8,collaps:[],colleagu:12,collect:[],color:[],column:[2,3,14],com:[8,13],combin:[2,8,9,10,12],combine_dimens:[],combine_sampl:[],come:[],comma:10,command:[0,7,8,10,12,13],command_vers:[],commandlin:[],common:2,compar:12,comparison:8,compat:9,complementnb:[],complementnd:[],complet:[13,14],complex:[],compon:[7,12],compress:[],comput:[0,9,10,12,14],compute_ci:[0,8],compute_confid:4,compute_confidence_logit:4,concaten:[],concept:12,conceptu:[],concern:12,concur:[],confer:8,conffid:9,confid:4,config:[0,1,2,7,9,10,13,14],config_file_path:[1,5],config_io_classifi:[0,8],config_preprocess:[0,8],config_segmentix:[0,8],config_worc:[0,8],configpars:[0,5,10,14],configur:[0,1,2,8,9,11,14],conflict:[],connect:[],connectivetissueoncologysocieti:8,consid:13,consist:14,consol:[],consolid:[],consortium:[],const_:[],const__addint__right_hand:[],const_addint__right_hand_0:[],constant1:[],constant:[3,12],constantnod:[],constraint:[],construct:[2,4,8,13],construct_classifi:[0,8],construct_svm:2,consum:[],consumpt:[],contact:[],contain:[0,1,2,3,4,5,9,10,14],containingfor:[],containssampl:[],contantnod:[],content:[],continu:2,contour:5,contrast:[],contribut:8,control:[],conveni:[],convent:[],convert:14,copi:[0,8,9,14],copymetadata:[0,14],copyright:[],core:10,corn:8,correct:14,correctli:[4,9],correl:12,correspond:[2,14],cosin:14,cost:2,could:12,couldnotdeletecredenti:[],couldnotretrievecredenti:[],couldnotsetcredenti:[],count_paramet:4,counter:[],coupl:14,cours:14,cpu:[],crash:[],creat:[0,2,4,7,10,12,14],create_:[],create_bbox:7,create_const:[],create_ensembl:[],create_link:[],create_macro:[],create_network:[6,7],create_network_copi:[],create_nod:[],create_param_grid:2,create_sink:[],create_sourc:10,creation:9,credenti:[],criterion:[],crop:12,cross:[4,9,10,14],cross_valid:[],crossval:[0,8],crossvalid:8,crypto:[],csv:[4,9,14],ct001:0,ct002:0,cto:8,current:[0,2,8,9,10,12,13,14],curv:4,custom:2,cut:[],cv_iter:[],cv_results_:[],dag:[],darwin:[],data:[0,2,3,4,5,9,10,12],datafil:9,datafram:[2,4],dataset:[0,12,14],datatyp:[9,11],datatypemanag:[],datayp:9,datetim:[],dbu:[],debug:[4,13],decent:12,decid:12,decis:[],decision_funct:[],decision_function_shap:[],def:[],defaultconfig:[0,10,14],defer:[],defin:[0,2,3,5,7,12,14],definit:[],degre:2,del_password_for_us:[],delai:[],delet:[],delete_cc_para:[],delete_nonestimator_paramet:[],demand:[],dementia:2,demo:[],demo_param:2,demonst:2,den:8,depend:[0,4,12,14],depict:[],deprec:[],depth:[],der:8,deriv:[],describ:[0,2,11,14],descript:[2,10],design:12,desir:[],desmoid:8,detail:[2,4,10,14],detect:[],determin:[4,10,12],determinist:2,dev:[],develop:[12,13,14],deviat:[],diagram:[],dicom:[0,10,14],dict:[0,1,2,3,5],dict_valu:[],dictionari:[0,1,2,4,5,10,14],did:[12,14],die:[],die_sid:[],differ:[2,4,5,8,9,12],differenti:8,difficult:12,dilat:14,dim1:[],dim2:[],dimens:[],dimension:12,dimnam:[],dir:[],direct:14,directli:[12,14],directori:[0,10,13,14],dirk:8,disambigu:[],discret:[],discrete_uniform:2,discuss:14,dispatch:[],displai:[],dist:13,distanc:3,distance_p:3,distinguish:2,distribut:2,distrubit:[],divers:12,divid:12,doc:[],doctest:[],document:9,doe:3,doing:[],don:[],done:[12,14],down:[],download:[],draw:[],draw_dimens:[],draw_network:14,drawn:10,dti:9,dti_post:[],dtrf:8,due:[9,12],dummi:9,dump:[],dure:2,each:[2,3,4,5,9,10,12,14],earlier:[],easi:[8,12],easier:12,easili:[10,12,14],ecr:8,edg:[],edit:[13,14],editelastixtransformfil:9,effect:[],effici:[],effort:12,eigen:[],either:[0,2,3,4,10,13,14],elabor:[],elasticnet:[],elasticnet_alpha:[],elasticnet_l1_ratio:[],elastix:[0,8,9,14],elastix_para:[0,8],elastixlogfil:[],elastixparameterfil:[],elastixtransformfil:[],element:14,ellipsi:[],els:[],email:[],emploi:[],empti:[],enabl:[2,10],encount:[],end:8,engin:[8,12],enhanc:[],enough:[],ensembl:[4,7,8,12],ensemble_scor:4,ensur:0,enter:[2,5],entir:[],entiti:[],enumtyp:[],env:[],environ:13,envis:[],equal:2,equival:[],erasmu:12,ercim:[],error:9,error_scor:[],especi:9,establish:8,estim:[0,4,7,8,10],etc:[3,8],european:8,eusomii:8,evalu:[0,4,8,9,14],even:[],event:[],everi:12,everyth:[],evolv:[],exact:[],exampl:[0,2,4,7,9,10,12,13,14],example_network_rerun:[],example_tool:[],except:0,exclud:[],exe:[],execu:[],execut:[0,7,8,10,12,13],execute_job:[],execution_fail:[],execution_plugin:[],executionplugin:14,executionpluginmanag:[],executionscript:[],exhaust:[],exist:[7,12],exp:2,exp_uniform:2,expand:[],expand_macro:[],expect:12,experi:[],explain:[],explan:14,explicit:[],explicitli:[],explor:[],explos:[],expon:2,express:[],ext:[],extend:[],extens:[10,12],extern:[],extra:[],extract:[1,4,5,10,12],extractnlargestblobsn:[0,8],f1_weight:[],facilit:[8,12],fail:[],fail_1:[],fail_2:[],failing_network:[],failing_network_2017:[],failing_network___step_1___sample_1_1:[],failur:[],fals:[2,4],famili:[],familiar:12,fancyimput:3,fas:[],fast:[],fastr3:9,fastr:[0,7,8,9,10,13],fastr_bug:8,fastr_failing_network_2017:[],fastr_plugin:[0,7,14],fastr_result_:[],fastr_result_s1:[],fastr_result_s2:[],fastr_result_s3:[],fastr_result_s4:[],fastr_run_dump:[],fastr_tempdir:[0,10,14],fastr_tmpdir:14,fastrconfig:[10,14],fastrhom:13,fastrinterfac:[],fastroutputvalidationerror:[],fastrtemp:[],fastrvalueerror:[],fatih:8,fator:2,feasibl:[],feat:[],feat_test:[],feat_train:[],featsel:8,featur:[0,1,2,3,4,5,7,8,9,10,12],feature_label:3,feature_select:3,feature_set:3,feature_valu:3,featurecalc:[],featurefil:1,featureprocess:[0,8],features_mod1_patient1:1,features_mod1_patient2:1,features_mod2_patient1:1,features_mod2_patient2:1,features_test:14,features_train:14,featuresc:8,fed:[],feed:[],feel:[12,13],fellow:12,felt:12,ferenc:[],fetch:[],few:12,fibromatosi:8,fibrosi:8,fict:12,field:[2,10,12],fier:[],fig:4,figsiz:4,figur:[4,12],figwidth:4,file1:[],file2:[],file3:[],file:[0,1,4,5,8,9,10,13,14],file_io:[0,8],file_path:[],filenam:[5,14],filepath:4,fill:[],fill_valu:3,fillhol:[],filter:12,finalbsplineinterpolationord:9,find:[8,12],find_password_for_us:[],findlabeldata:5,finish:[],first:[3,4,9,10,12,13,14],fit:[2,3,10],fit_and_scor:[],fit_param:[],fit_tim:[],fitandscor:[0,8],fitfailedwarn:[],fittd:[],five:12,fix:[4,8,12],fixed_imag:[],fixed_mask:[],fixedsplit:[],flag:[],flexibl:[9,12],float_valu:[],flow:[],flownod:[],focu:[],fold:[],folder:[4,9,10,13,14],follow:[3,4,8,10,12,13,14],font_siz:[],fontsiz:4,footnot:[],forc:[],foresight:12,form:[],format:[0,1,4,8,9,10,14],formula:2,forum:[],forward:12,forwardssampl:[],found:[8,10,12,13],foundat:8,four:12,fpr:4,fprt:4,framework:[8,9,12],frangi:[],free:13,freedesktop:[],freeli:14,frequenc:[],frequent:3,from:[0,1,2,3,4,5,8,9,12,14],froma:[],frontier:[],frontiersin:12,frozenset:3,fsl:[],fslmath:[],fulfil:[],full:12,fulli:8,fullnam:[],fun:12,funtion:3,further:9,furthermor:[],futur:9,gabor:[],gabor_angl:[],gabor_frequ:[],gamma:2,gaussiannb:[],gave:[],geert:8,gener:[0,2,4,8,9,12,14],generate_boxplot:4,genet:[5,10],georg:8,get:[4,8,12,13],get_password_for_us:[],getparametermap:7,gibhub:8,git:13,github:[1,2,4,8,13],give:[2,9,12,14],given:[0,2,4,9,14],glcm:[],glcm_angl:[],glcm_distanc:[],glcm_level:[],global:[],glrlm:[],glszm:[],glu:[],gnome:[],goe:[],going:12,googl:[],got:[],gotten:[],govern:[],gpl:[],grade:8,grand:2,graph:[],graphic:[],graphviz:[],grayscal:[],grid:2,grid_scores_:[],gridsearch:10,gridsearchcv:[],gridsearchcvfastr:[],gridsearchcvjoblib:[],ground:4,groundtruth:2,group:[3,10,12],groupsel:[],groupwis:[],groupwisesearch:[],gsout:[],guarante:2,gui:[],guid:[2,8],guidelin:[],guillaum:8,gzip:[],hachterberg:[],had:[9,12],hakim:[],halton:2,haltonsampl:2,hand:12,handl:[],happen:[],harmon:8,has:[0,8,10,12,13],hasdimens:[],hassampl:[],have:[0,2,5,9,10,12,14],hdf5:[1,4,14],head:14,header:[0,14],held:[],help:[0,2,5,7],henc:[2,9,10,12,14],herder:8,here:[10,14],hf_mean:3,hide:[],hide_unconnect:[],high:[8,12],higher:[],highest:[],highli:[2,12],hing:[],histogram:[],histogram_featur:3,histori:12,hofland:8,hold:0,hole:[],home:[],homogen:[],hope:8,host:8,hounsfield:10,how:[2,4,10,12,13,14],howev:[2,10,12,13],html:[0,14],http:[0,2,8,12,13,14],human:[],hyper:2,hyperoptim:8,hyperparamat:[],hyperparamet:[4,9,10,12],i_max:4,i_min:4,icc:2,icc_anova:2,icctyp:2,ict:[],id3:[],id4:[],id_:[],idea:[12,14],ident:[],identifi:[],ids:5,ieee:8,ignor:13,iid:[],illustr:12,imag:[0,4,5,7,8,9,10,12],image_featur:[4,5],image_features_temp:5,image_features_test:[],image_features_train:[],image_typ:[],imagefeatur:[8,14],images1:14,images_test:14,images_train:[0,14],imagin:[],img2:4,img:4,immedi:[],implement:[0,2,10,12,14],impli:[],implicitli:12,importerror:[],imposs:[],improv:[],imput:[0,8,9,12],imputat:[],in1:[],in2:[],in_1:[],in_2:[],in_:[],in_imag:[],incekara:8,includ:[0,9,10,12,14],incorrect:9,incorrectli:4,increas:[],indent:[],indep:[],independ:12,index:[3,8],index_to_sourc:[],index_to_target:[],indexerror:0,indic:5,individu:[],ineffici:12,infinit:9,influenc:[],info:[10,14],inform:[4,12],informat:8,inherit:[],ini:[0,1,9,10],init:[],initi:[0,2,5,7],initial_transform:[],inner:[],input:[0,2,4,7,9,12,13,14],input_fil:5,input_group:[],inputarrai:3,inputgroup:[],inputid_:[],inputmap:[],inputparameterdescript:[],insid:[],inspect:[],instal:8,instanc:[0,2],instanti:[],instead:[2,9,10,14],instruct:13,int_valu:[],integ:[2,3,4,5],integr:[8,12],inter:2,interact:[],interest:[],interfac:2,interfaceresult:[],intermed:4,intermedi:[],intern:8,interpret:12,intersect:[],interv:[4,9],intra:2,introduct:8,introductori:12,invalid:[],invalid_network:[],inverse_transform:[],involv:[],ioerror:0,ionnod:[],iopars:[0,8],ioplugin:[0,14],ipynb:13,iri:[],is_empti:2,is_valid:[],isbi:8,isi:14,isn:9,issu:[8,9,12,13],item:[0,2,3],iter:[2,4],iteritem:[],ith:2,itk:[0,9],itkimag:4,itkimagefil:[],its:12,itself:12,ivo:8,jacob:8,jifk:8,job:[],jobdag:[],joblib:[9,10],joblib_backend:[],joblib_ncor:[],jobstat:[],john:[],join:[],jose:8,journal:12,json:5,json_schema:[],jsoncollector:[],jth:2,jupyt:13,just:[9,14],kapsa:8,keep:[9,12],kei:[2,14],keio:[],kept:[],kernel:2,kessel:8,keychain:[],keyerror:0,keyr:[],keyringprovid:[],keyword:[],kfold:[],kill:[],kind:[12,14],klein:8,knn:3,know:[],known:[],koek:[],kwallet:[],label1:[10,14],label2:[10,14],label:[0,1,2,3,4,5,8,9,12],label_data:[4,5],label_data_test:[],label_data_train:[],label_fil:5,label_info:5,label_nam:[1,5,10],label_process:[0,8],label_s:2,label_set:3,label_statu:5,label_typ:[4,5,7],labels_test:14,labels_train:14,lambda:2,lambda_tol:2,lan:[],languag:[8,12],lanuag:[],laptop:12,larg:12,larger:9,largest:5,lasso:[],last:[9,12],lastli:[],later:10,launch:[],layer:[],layout:[],lbp:[],lbp_npoint:[],lbp_radiu:[],lda:[],lda_shrinkag:[],lda_solv:[],lear:[],learn:[4,12],least:[2,12],leav:[],leender:8,left:[],left_hand:[],legal:[],len:[],length:4,less:[],let:14,level:[],lgpl:[],lib:13,libari:[],librari:13,licens:8,lightweight:[],like:[2,9,10,12],limit:[],line:[12,13],linear:2,link1:[],link2:[],link:14,link_0:[],linstretch:[0,8],linux:9,lipoma:8,liposarcoma:8,list:[0,1,2,3,4,5,7,10,14],list_valu:[],littl:12,liver:[8,14],load:[1,5],load_config:1,load_config_xnat:5,load_data:1,load_featur:[],load_iri:[],load_label:5,load_label_csv:5,load_label_fil:[],load_label_txt:5,load_label_xnat:5,loc:2,local:13,localbinarytarget:[],locat:13,log:12,log_featur:3,log_fil:[],log_sigma:[],log_uniform:2,logic:[],login:[],longer:9,look:[10,12,14],loop:[],loss:[],lot:12,low:8,lower:[],lower_case_with_underscor:[],lower_threshold:[],lrc:[],lrpenalti:[],lsqr:[],luckili:12,maarten:8,mac:[],machin:12,maco:[],macro:[],macronod:[],made:[4,8,9,10,12,14],mai:[12,13],main:[4,6,13,14],major:9,make:[4,10,12,14],make_scor:[],malign:8,manag:0,mandatori:[1,2,3,4],mani:[0,4,9,10,12],manipul:14,mannwhitneyu:3,manual:[8,12,13],map:[2,14],mappingproxi:[0,2,3,5,7],marcel:[],marion:8,martijn:8,martin:8,mask:[0,4,8,9,12],masked_arrai:[],masks_test:14,masks_train:14,master:2,match:[1,5,10,14],match_typ:[],math:[],matlab:[5,8,12],matplotlib:4,matrix:2,matter:3,max:[],max_it:2,max_thread:[],maxim:[],maximum:2,maxlen:[],mean:[3,9,10],mean_fit_tim:[],mean_score_tim:[],mean_test_scor:[],mean_train_scor:[],meant:[],measur:2,median:3,medic:[8,12],meet:8,melissa:8,member:[],memori:9,mention:[],mercuri:[],merg:[],mesenter:8,messag:4,metadata:[0,8,9],metadata_test:14,metadata_train:14,method:[0,2,3,4,5,10,12,14],metric:[0,3,4,8],mhd:14,mic:[],miclea:8,micro:12,middl:4,might:13,milea:8,mimic:5,min:[],mind:[],mine:12,mini:[],minim:14,minimum:9,minkov:3,minm:[],minmax:[],minor:[9,10],miss:3,missing_valu:3,missingpi:3,mit:[],mixin:[],mobview:[],modal:[9,14],modalityname1:[],modalityname2:[],model:[1,7,10,12],model_evaluatio:[],model_select:3,modifi:[],modified_hub:[],modnam:1,modu:4,modul:14,modular:8,moment:[],more:[2,3,4,9,10,12,13,14],moreov:12,most:[3,10,12],most_frequ:3,mostli:10,mount:[],move:9,moving_imag:[],moving_mask:[],mr001:0,mr002:0,mstarmans91:[8,13],much:[9,13],multi:2,multi_class_auc:2,multi_class_auc_scor:2,multi_class_relief:3,multiclass:2,multicor:[],multilabel:9,multimod:9,multipl:[0,9,10,12,14],multipli:[],multiprocess:[],must:10,mutat:8,mutlicor:[],mutlipl:[],mxn:2,n_1:4,n_2:4,n_blob:[],n_core:[],n_featur:2,n_iter:2,n_job:[],n_jobspercor:[],n_jobsperscor:[],n_neighbor:3,n_neighbour:3,n_neightbor:3,n_output:[],n_sampl:2,n_split:[],n_splits_:[],n_test:4,n_train:4,naiv:12,name:[0,4,5,7,9,10,13,14],namespac:[],nan:3,ndarrai:[],nearest:3,neccesari:9,necessari:[],need:[9,10,12,14],neg_dual_func:2,neighbor:3,neighbour:3,nest:[],netrc:[],nettyp:7,network:[0,6,7,9,10,12,13,14],network_nam:[],network_st:[],networkrun:[],neuro:[],newbas:[],newest:[],newli:[],nework:0,next:14,ngtdm:[],nice:12,niessen:8,nifti:14,niftiimagefil:[],niftiimagefilecompress:[],nii:[0,14],nipyp:2,nnode:[],nocrossv:[],node1:[],node2:[],node:[9,10,12,14],node_group:[],nodeid:[],nodeid__:[],nodelist:[],noderun:[],nomean:[],non:[2,12],none:[0,1,2,3,4,5,7,10],norm_tol:2,normal:[10,12],normalization_factor:4,normalize_whitespac:[],nospac:[],not_label:2,notabl:9,notat:[],note:[0,2,9,10,12,14],notebook:13,notimpl:[],notimplementederror:0,now:9,nrrd:14,nsampl:4,num_class:2,num_train:2,number:[2,3,4,5,12],number_of_class:[],number_of_level:[],number_of_sid:[],numbertoextract:5,numer:[2,3,14],numf:3,numpi:[2,3,4,5,9],object:[0,2,3,4,5,7,8,9,10],obscur:[],observ:2,obtain:[],occur:[],occurr:3,off:14,offici:8,often:12,onc:5,one:[0,2,5,9,10,12,14],onevsrestclassifi:[],onli:[0,3,5,9,10,12,14],onlin:12,ontolog:12,onward:2,open:[8,9,12],oper:4,opim:[],optim:[0,10],optimiz:0,option:[0,1,2,3,4,9,13,14],orang:[],order:[3,12],ordinari:[],org:[2,12],organ:12,orient:[],orientation_featur:3,origin:[],oserror:0,other:[0,2,8,10,12,14],other_dict_valu:[],other_list_valu:[],other_str_valu:[],otherwis:2,ouput:[],our:[8,10],out:[4,5,12,13,14],out_1:[],out_2:[],out_:[],out_imag:[],outcom:12,output:[4,9,12,13],output_csv:4,output_hdf:[],output_itk:4,output_json:[],output_nam:4,output_name_zoom:4,output_png:4,output_tex:4,output_zip:4,outputfold:4,outputid:[],outputmap:[],oval:[],over:[2,10,12],overlai:4,overrid:[],oversampl:[9,10,12],overview:[13,14],overwritten:0,own:[10,12],packag:[8,9,13],pad:[4,7],padmo:8,page:[8,12,14],pair:[],pairwis:[],pairwise_auc:2,panda:[2,4],panda_data:[],paper:[],para:2,paracheck:4,paragraph:[],parallel:[9,10,13],param:[2,4],param_c:[],param_degre:[],param_distribut:2,param_gamma:[],param_grid:2,param_kernel:[],param_list:2,paramet:[0,2,3,4,9,10,12,14],parameter_optim:[0,8],parametergrid:[],parameters_al:[],parameters_est:[],parametersampl:2,paramt:2,parent:[],pars:[1,10,13],part:[10,12,14],particular:[],pass:[2,9,14],password:[],past:[],path:[0,1,4,5,9],patient001:0,patient002:0,patient1:[10,14],patient2:[10,14],patient3:[10,14],patient:[0,1,2,3,4,5,10,14],patient_featur:[3,14],patient_id:5,patientclass:[9,10],patientinfo:[1,5],patientinfo_test:[],patientinfo_train:[],payload:[],pca:9,pcatyp:[],pce:9,penalti:[],pentagon:[],peopl:8,pep8:[],pep:[],per:[0,1,3,9,10,14],percentag:[3,4,7],perform:[2,4,7,10,12,14],performance_multilabel:2,performance_singlelabel:2,phase:[],phase_featur:3,phase_minwavelength:[],phase_nscal:[],phd:12,philosophi:[],pick:[],pickl:[],pictur:[],pid:4,pilot:[],pinfo:[4,7,9],pink:[],pinpoint:[],pip:8,pipelin:[0,8,12,14],pixel:[0,4],place:[],placehold:3,plai:[],plaintext:[],plan:[],platform:[8,12],pleas:[2,8],plot:[0,8,9],plot_bar:4,plot_barchart:[0,8],plot_boxplot:[0,8],plot_im_and_overlai:4,plot_imag:[0,8],plot_ranked_imag:4,plot_ranked_percentag:4,plot_ranked_posterior:4,plot_ranked_scor:[0,8],plot_roc:[0,8],plot_roc_c:4,plot_single_roc:4,plot_single_svr:[],plot_svm:[0,8],plot_svr:[0,8],plotminmaxrespons:[0,8],plu:14,pluge:0,plugin:[0,12,14],png:[4,9],point:[2,4],pointer:[],pointint:4,pointsar:4,poli:2,polynomi:[],popul:[],port:9,posit:4,possibl:[2,8,12],post:13,posterior:4,power:[],practic:12,pre_dispatch:[],predefin:[],predict:[2,4,8,9,10,12,14],predict_log_proba:[],predict_proba:2,predictgener:8,prefer:[],preferred_typ:[],prefix:[],prepend:[],preprocess:[8,9,12,14],preprocessi:[],preprocss:[],present:[2,8,9],press:8,prevent:9,previou:[12,14],previous:[10,12],principl:12,print:14,priorit:[],prioriti:[],privat:[],probability_imag:[],probabl:[],problem:[8,12],procedur:[3,10,14],proceed:8,process:[0,8,12],process_fit:[],processpollexecut:14,processpoolexecut:7,produc:2,profil:[],program:12,progress:[],project:[5,9],projectid:[],prompt:[],prone:[],proper:[0,9],properli:[],properti:[],propos:[],prostat:8,prov:[],provdocu:[],proven:12,provid:[0,2,4,7,10],pseudo:2,publish:[],pull:[],purpos:0,push:[],put:[4,9,10,13,14],pxcastconvert:9,pycrypto:[],python3:[9,13],python:[8,9,10,12,13],qda:[],qda_reg_param:[],qualiti:[],quantit:12,question:12,quick:8,quit:12,qxm:2,radian:[],radii:[],radiolog:8,radiom:[0,10,14],radiu:14,rais:[],ran:[],randint:[],random:[2,10],random_search:[],random_search_paramet:[],random_st:2,randomizedsearchcv:[],randomizedsearchcvfastr:[],randomizedsearchcvjoblib:[],randomli:[],randomsearch:[],randomst:2,rang:4,rank:[3,4,9,12],rank_:[],rank_test_scor:[],ranked_pid:4,ranked_scor:4,ranked_truth:4,rankedsvm:[0,8,9],ranksvm:2,ranksvm_test:2,ranksvm_test_origin:2,ranksvm_train:2,ranksvm_train_old:2,rate:[],rather:[],ratio:4,razvan:8,rbf:2,read:[1,2,5,12,14],read_config_fil:[],readabl:[],readi:[],readthedoc:[0,8,14],real:[],realli:10,reason:[],rebuild:[],rebuilt:[],receiv:4,recommend:[2,10,12,13],record:[],recreat:[],rectangl:[],reduc:[],reduct:[9,12],ref:2,refer:[0,1,2,3,4,5,7,9,12,14],referen:[],referenc:[],refit:[],refit_and_scor:[],reflect:[],regist:[],registr:[9,12,14],registratio:0,registri:[],regress:2,regular:[],rel:[],relat:0,releas:[9,12],relev:12,reliabl:[],relief:[0,8,9],reliefdistancep:[],reliefnn:[],reliefnumfeatur:[],reliefsamples:[],reliefsel:[],reliefus:[],remov:9,repeat:[2,10],replac:[2,3],replacenan:[],repo:[],report:[],repositoi:[],repositori:8,repr:[],repres:[],represent:[],reproduc:12,request:[],requir:[0,2,8,9,12],rerun:[],resampl:[],research:[8,12],resolv:[],resourc:[5,6,8,12],resourcelimit:[],respect:[2,3],respons:[],rest:[],result:[3,4,12],result_1:[],result_2:[],resum:[],ret:[],retain:[],retreiv:5,retri:[],retriev:10,return_al:[],return_n_test_sampl:[],return_paramet:[],return_tim:[],return_train_scor:[],reus:[],rfmax_depth:[],rfmin_samples_split:[],rfn_estim:[],rfr:[],ride:[],right:[],right_hand:[],ring:14,risk:[],rms_score:[],rng:2,roc:[4,9],roc_threshold:4,roi:14,root:[],ros:[],round:2,rounded_list:2,routin:12,row:2,rtstructread:[0,8,9],rule:[],run:[9,10,12,13,14],rundir:[],runtim:[],runtimeerror:[],rvs:2,safe:[],same:[10,12,14],sampl:[0,2,3,4,10,13],sample_1_1:[],sample_1_2:[],sample_1_3:[],sample_id:[],sample_s:3,sampleprocess:8,sar:[],sar_scor:[],save:[4,9,10,14],scale:[2,10,12],scale_featur:[],scaler:[],scaling_method:[],scan:10,scatterplot:[0,8],scenario:[],scenc:[],schedul:[],schedulingplugin:[],schema:[],scheme:[],schoot:8,scikit:[],scipi:2,score:[2,3,4,7,9],score_tim:[],scorer:[],scorer_:[],scoring_method:[],scratch:[],script:[12,13],search:[2,3,8,9,13],searchcv:[0,4,8],sebastian:8,second:[3,10],secret:[],secret_servic:[],secretprovid:[],secretservic:[],secretstorag:[],section:[13,14],secur:[],see:[0,1,2,4,5,7,8,10,13,14],seed:2,seem:12,seen:2,seg1:14,seg2:14,seg:7,segment:[0,4,7,8,9,10,12],segmentations1:14,segmentations2:14,segmentations_test:14,segmentations_train:14,segmentix:[1,8,9,14],segradiu:[],segtyp:[],sel:[],select:[3,9,10,12],selectfeatgroup:8,selectfrommodel:[],selectgroup:[0,8],selectindividu:[0,8],selectmodel:[],selectmulticlassrelief:3,selectormixin:3,self:[0,2,5,7],selfeat_vari:[],semant:[0,8,9],semantic_featur:3,semantics_test:14,semantics_train:14,send:[],separ:[9,10,14],sequenc:[0,2,14],sequenti:[],serial:[],serpar:9,serv:[0,12,14],servic:[],session:[],set:[0,1,2,3,4,7,8,9,10,12,13],set_data:[],set_password_for_us:[],settin:[],settings_dict:1,sever:[5,9,10,12,14],sex:14,sf_compact:3,sgd:[],sgd_alpha:[],sgd_l1_ratio:[],sgd_loss:[],sgd_penalti:[],sgdr:[],shape:2,shape_featur:3,share:[],shear:12,shell:[],ship:[],shortcut:[],shorthand:[],should:[0,1,2,3,4,10,14],show:13,show_plot:4,shown:12,shrink:[],shrinkag:[],side:[],sign:[],signatur:[0,2,5,7],signific:4,similar:[9,12,14],simpl:[12,13],simpleelastix:14,simpleitk:14,simpler:12,simplest:[],simpli:[10,13],simplifi:[],simul:[],simultan:12,sinc:[],singl:[4,5,8,9,10,14],single_class_relief:3,singleclass:2,singlelabel:4,singleton:2,sink1:[],sink2:[],sink:[0,7,9,12,14],sink_1:[],sink_2:[],sink_3:[],sink_4:[],sink_5:[],sink_data:[0,6,7],sink_id1:[],sinkenod:[],sinknod:[],site:13,situat:[],size:[2,4,7,14],size_alpha:2,skip:14,sklearn:[2,3,10],slack:[],sleijfer:8,slice:4,slicer:[0,4,8,9],slight:2,small:9,smaller:[],smallest:[],smart:4,smit:8,smote:10,smote_neighbor:[],smote_ratio:[],snippet:[],societi:8,softwar:[8,12],solid:[],solut:[],solv:12,solver:[],some:[0,2,9,10,12,13],some_output_loc:[],somenam:[10,14],someon:12,someth:[],sometim:[],sort:[],souc:[],sourc:[0,1,2,3,4,5,6,7,8,9,10,12],source1:14,source2:14,source3:[],source_data:[0,6],source_data_data:14,source_id1:[],source_id2:[],source_nod:[],sourcenod:[],sourcetre:[],space:2,span:[],spawn:0,spawner:0,special:[],specif:[3,10,12,14],specifi:[0,10,14],spend:[],spent:[],split0_test_scor:[],split0_train_scor:[],split1_test_scor:[],split1_train_scor:[],split2_test_scor:[],split2_train_scor:[],split:[10,12,14],squar:[],squared_hing:[],src:2,ssh:13,stabl:[0,14],stack:1,stage:[],stai:[],standard:8,standardis:8,starman:8,start:[8,9,12],stat:[2,4],state:[0,2],statement:5,statist:[3,4,9],statisticalsel:[],statisticaltestfeatur:[0,8],statisticaltestmetr:[],statisticaltestthreshold:[0,8],statisticaltestus:[],statu:5,std_fit_tim:[],std_score_tim:[],std_test_scor:[],std_train_scor:[],stderr:[],stdout:[],stefan:8,step1:[],step:[12,14],step_1:[],step_id:[],still:[9,10,14],stimul:8,stop:5,storag:[],store:[2,14],str:[2,9],str_valu:[],straight:12,strategi:[3,8,9],stratif:8,stratifi:[],stratifiedkfold:[],strenght:[],strength:[],stretch:4,strict:[],string:[0,1,2,3,4,5,10,14],structur:[],stuck:13,student:12,studi:[0,8,12],style:[],sub:0,subclass:[],subfold:9,subinput:[],subject:2,subobjectmap:[],subouput:[],suboutput:[],subpackag:8,subprocess:[],subtract:9,succeed:[],succesful:[],success:[],successfulli:[],suggest:2,suit:[0,5],sum:[],summari:[],suppli:[1,4,10,14],support:[2,3,8,9,10,12,14],suppos:10,sure:14,surgeri:8,surrog:2,surviv:[],svc:[],svd:[],svg:[],svm:[2,4,9,10],svmc:[],svmcoef0:[],svmdegre:[],svmgamma:[],svmkernel:[],svr:2,symposium:8,syntax:[],synthet:10,sys:[],system:[0,13,14],tabl:2,tag:14,take:[2,14],taken:[],target:2,task:12,techniqu:10,tedious:12,tell:14,temp:[],templat:[],temporari:[0,9,14],tempsav:[],term:[9,12],terminolog:8,test:[0,3,4,9,10,13,14],test_data:2,test_sampl:4,test_sample_count:[],test_scor:[],test_siz:[],test_target:2,test_throwdi:[],testserv:[],tex:[4,9],text:[],textur:10,texture_featur:3,texture_gabor_featur:3,texture_glcm_featur:3,texture_glcmms_featur:3,texture_glrlm_featur:3,texture_glszm_featur:3,texture_lbp_featur:3,texture_ngtdm_featur:3,than:10,thei:[9,14],them:[2,10,12],therebi:[9,12],therefor:[0,12],thi:[0,2,3,4,8,9,10,11,12,13,14],thing:[10,14],thomeer:8,those:[],though:[],thread:10,three:2,thresh:[],threshold:[3,4],threshold_mask:[],thresholdimag:[],through:[0,7,8,9,10,12,14],throw_di:[],throwdi:[],thrown:[],thu:[10,12,14],tiff:14,timbergen:8,time:[4,12],timestamp:[],tionplugin:[],tmp:[],tmpdir:[],todo:0,togeth:[],tol:[],toler:2,tool:[0,8,9,10,11,12,13,14],tool_vers:[],toolbox:[10,14],toolmanag:[],toolnam:[],tools_path:[],top50:[],top:4,tortoisehg:[],total:[],tpr:4,tprt:4,trace:13,track:[],trade:[],trail:[],train:[0,2,4,9,10,14],train_data:2,train_scor:[],train_target:2,train_test_split:[],trainclassi:[],trainclassifi:[0,4,8,9],transform:[3,9,14],transformat:[],transformi:[],transformix:[0,8,9,14],translat:[],treat:10,tree:[],tri:12,trigger:[],trough:[],truth:4,tsampl:4,ttest:[3,9],tumor:[8,14],tumour:8,tune:12,tupl:[],turn:[],tutori:[8,10],twai:[],two:[0,14],txt:[0,1,4,9,10,14],type:[0,2,3,4,5,7,8,10,12],typeerror:0,typegroup:9,typenam:[],types_path:[],ubuntu:13,udr:2,ulat:[],unag:5,unavail:[],under:[8,9,14],underli:[],understand:12,unfit:[],uniform:2,uniformli:[],union:[],uniqu:[],unit:10,univari:[],univers:8,unknown:[],unless:[],unreleas:[],unseen:[],unsupervis:[],unsupport:[],until:[],untouch:[],updat:9,upon:13,upper:[],uppercamelcas:[],url:5,urltyp:9,usabl:[],usag:9,usd:3,use:[0,2,3,4,9,10,12,13,14],use_fastr:[],used:[0,1,2,3,4,5,8,9,10,12,14],useful:[],usepca:[],user:[2,11,13],user_manu:[],usernam:[],uses:11,using:[0,2,3,8,9,10,12,13,14],usr:13,usual:[],util:[],val1:[],val2:[],val3:[],val4:[],val:[],valid:[0,4,9,10,14],valu:[0,2,3,4,5,10,14],value1:10,value2:10,valueerror:0,valuetyp:[],van:8,vari:12,variabl:[0,9],varianc:[],variancethreshold:[0,8],variancethresholdmean:[],variant:12,variou:[8,10,11,12,14],varsel:[],vault:[],vector:2,veenland:8,verbos:4,verhoef:8,veri:12,verifi:[],version:9,versu:8,vessel:[],vessel_featur:3,vessel_radiu:[],vessel_scale_rang:[],vessel_scale_step:[],vfs:[0,14],via:8,view:[],vincent:8,virtual:[],virtualenv:13,virtualfilesystem:[],visser:8,visual:[],vizual:[],volum:8,voort:8,w3c:[],wai:[],wait:[],want:[0,8,10,13,14],warn:[],warp:14,wavelength:[],weak:[0,2,3,5,7],web:[],websit:[],weight:2,welch:3,well:[8,9,12,13],went:[],were:[9,12],what:[],whatev:[],when:[0,4,9,10,12,14],whenev:2,where:[2,12],wherea:[],whether:[4,5,9,14],which:[0,2,4,5,9,10,12,13,14],who:[],whole:12,wich:[],wide:[],wijnenga:8,wiki:[1,2,4],wilcoxon:3,window:[9,13],wip:[3,4],wiro:8,wise:[],wish:[],within:[12,14],without:[2,14],wonder:12,worc:[1,2,3,4,5,6,7,9,10,11,12,13],worc_config:[9,13],worcassertionerror:0,worccastconvert:9,worcerror:0,worcflow:8,worcindexerror:0,worcioerror:0,worckeyerror:0,worcnotimplementederror:0,worcpy27:[],worctutori:[8,13],worctypeerror:0,worcvalueerror:0,work:[5,9,10,12],workaround:10,workflow:[0,9,10,12,14],world:[],would:[10,12],wouter:8,wrap:12,wrapper:[],write:[],written:4,wrong:[],wtype:0,www:[],x_train:3,xcode:[],xlsx:[],xml:[],xnat:[5,10],y_predict:[2,4],y_score:[2,4],y_train:3,y_truth:[2,4],yellow:[],yet:[],yield:2,you:[0,5,7,9,10,12,13,14],your:[0,10,13,14],yourprovidernam:[],yourself:[8,12],yourusernam:[],z_score:[],zero:[],zip:[4,9],zoomfactor:4},titles:["WORC Package","IOparser Package","classification Package","featureprocessing Package","plotting Package","processing Package","fastr_tests Package","tools Package","WORC","Changelog","Configuration","Resource File Formats","Introduction","Quick start guide","User Manual"],titleterms:{"0rc1":9,"class":5,"function":14,Added:9,The:14,Using:[],addexcept:0,advanc:[],advancedsampl:2,algorithm:[],ask:[],attribut:14,broadcast:[],calcfeatures_test:6,chang:9,changelog:9,classif:[2,8,10],code:13,combin:[],command:14,compute_ci:4,config:[],config_io_classifi:1,config_preprocess:1,config_segmentix:1,config_worc:1,configur:[10,13],constantnod:[],construct:14,construct_classifi:2,continu:[],convent:[],creat:[],crossval:2,crossvalid:10,data:[],datatyp:[],debug:[],definit:[],descript:[],design:[],develop:8,differ:[],dimens:[],document:8,elastix:7,elastix_para:14,elastix_test:6,ensembl:10,error:[],estim:2,evalu:7,exampl:[],execut:14,extractnlargestblobsn:5,fastr:[12,14],fastr_bug:10,fastr_test:6,fastrhub:[],featsel:10,featur:14,featureprocess:3,featuresc:10,field:[],file:11,file_io:1,fitandscor:2,fix:9,flow:[],format:11,from:13,gener:10,guid:13,guidlin:[],help:[],hyperoptim:10,hyperparamet:[],imag:14,imagefeatur:10,implement:[],imput:[3,10],indic:8,input:[],insid:[],instal:13,introduct:12,invalid:[],iopars:1,ioplugin:[],label:[10,14],label_process:5,link:[],linstretch:4,manual:14,mask:14,match:[],metadata:14,metric:2,modul:[0,1,2,3,4,5,6,7,8],modular:12,name:[],network:[],node:[],object:14,optim:[8,12],origin:[],overview:[],own:[],packag:[0,1,2,3,4,5,6,7],parameter_optim:2,philosophi:[],pip:13,plot:4,plot_barchart:4,plot_boxplot:4,plot_imag:4,plot_ranked_scor:4,plot_roc:4,plot_svm:4,plot_svr:4,plotminmaxrespons:4,predictgener:10,preprocess:10,process:5,prov:[],proven:[],quick:13,radiom:[8,12],rankedsvm:2,refer:8,relief:3,resolv:[],resourc:11,rtstructread:5,run:[],sampl:[],sampleprocess:10,scatterplot:4,schedulingplugin:[],searchcv:2,secret:[],secretprovid:[],segment:14,segmentix:10,segmentix_test:6,select:[],selectfeatgroup:10,selectgroup:3,selectindividu:3,semant:14,set:14,simpl:[],sinknod:[],slicer:7,sourc:[13,14],sourcenod:[],split:[],standard:12,start:13,statisticaltestfeatur:3,statisticaltestthreshold:3,subpackag:0,system:[],tabl:8,terminolog:12,tool:7,trainclassifi:2,transformix:7,tutori:13,unreleas:[],upload:[],usag:[],user:[8,14],using:[],variancethreshold:3,via:13,w3c:[],worc:[0,8,14],worcpy27:[],workflow:8,your:[]}}) \ No newline at end of file diff --git a/build/lib/WORC/doc/_build/html/static/changelog.html b/build/lib/WORC/doc/_build/html/static/changelog.html deleted file mode 100644 index 55f75b84..00000000 --- a/build/lib/WORC/doc/_build/html/static/changelog.html +++ /dev/null @@ -1,431 +0,0 @@ - - - - - - - - - - - Changelog — WORC 3.0.0 documentation - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
            - - - -
            - - - - - -
            - -
            - - - - - - - - - - - - - - - - - -
            - - - - -
            -
            -
            -
            - -
            -

            Changelog¶

            -

            All notable changes to this project will be documented in this file.

            -

            The format is based on Keep a Changelog -and this project adheres to Semantic Versioning

            -
            -

            3.0.0 - 2019-05-08¶

            -
            -

            Added¶

            -
              -
            • Now ported to Python3.6+ (Python 2 is no longer supported!). Thereby also -to fastr3.

            • -
            • Compatibility for Windows. Some small changes in functions, as some packages -behaviour differently under Windows. Also, adjusted sink and source paths -to use OS file separator.

            • -
            • Config is now also a sink.

            • -
            -
            -
            -

            Changed¶

            -
              -
            • PCE and DTI node removed, as they were not open source.

            • -
            • Pinfo file can now also be a csv. Txt is still supported.

            • -
            • Use fastr as default for hyperparameter search parallelization instead -of Joblib, as this is much more flexible.

            • -
            • When the conffidence interval cannot be computed, just use the mean.

            • -
            -
            -
            -

            Fixed¶

            -
              -
            • WORC_config.py was not correctly copied in Windows due to incorrect path separation.

            • -
            • Source creation for the config was only for Linux.

            • -
            • In numpy 1.15>, booleans cannot be subtracted. Fixed an error due to this in -segmentix by using bitwise_xor instead.

            • -
            • Bug when using masks, but not for all images, and segmentix.

            • -
            • Cardinality of classify node was incorrect.

            • -
            -
            -
            -
            -

            2.1.3 - 2019-04-08¶

            -
            -

            Changed¶

            -
              -
            • PREDICT was updated, so had to update the requirements. Changed it -to a minimum of PREDICT to prevent these issues in the future.

            • -
            -
            -
            -
            -

            2.1.2 - 2019-04-02¶

            -
            -

            Added¶

            -
              -
            • Dummy workflow in segmentix and calcfeatures PREDICT tools.

            • -
            • Added several new PREDICT parameters.

            • -
            • Slicer tool.

            • -
            -
            -
            -

            Changed¶

            -
              -
            • Memory for elastix tool is now larger.

            • -
            -
            -
            -

            Fixed¶

            -

            -Evaluate framework now correctly adopts the name you give it.

            -
            -
            -
            -

            2.1.1 - 2019-02-15¶

            -
            -

            Added¶

            -
              -
            • Several new PREDICT variables to the config.

            • -
            • Multilabel classification workflow.

            • -
            • New oversampling strategy.

            • -
            • RankedSVM multilabel classification and Relief feature selection.

            • -
            -
            -
            -

            Changed¶

            -
              -
            • Major reduction in memory usage, especially due to PREDICT updates.

            • -
            • Only use first configuration in the classify config.

            • -
            • Outputs are now in multiple subfolders instead of one big folder.

            • -
            -
            -
            -

            Fixed¶

            -
              -
            • Minor bug in test workflow: needed str of label in appending to classify.

            • -
            • There was a bug in using a .ini file as a config.

            • -
            -
            -
            -
            -

            2.1.0 - 2018-08-09¶

            -
            -

            Added¶

            -
              -
            • Feature imputation settings in WORC config.

            • -
            • PCA settings in WORC config.

            • -
            • Dummy file, which can generally be accepted by WORC.

            • -
            • Preprocessing is now a separate node before the calcfeatures node.

            • -
            • Started working on a RTStructReader tool.

            • -
            • Added EditElastixTransformFile node to set FinalBSplineInterpolationOrder to 0 -in Elastix. Neccesary for transforming segmentations.

            • -
            • Registred image is also saved as a sink.

            • -
            • Tex, Zip and PNG Datatypes

            • -
            • Plot ROC tool for PREDICT

            • -
            • Plot SVM tool for PREDICT

            • -
            • Plot Barchart tool for PREDICT

            • -
            • Plot Ranked Scores tool for PREDICT

            • -
            • Plot statistical test tool for PREDICT

            • -
            • Tools: Evaluation network. Can currently be run only serparately: future -work includes the optional addition of the Evaluate network to the WORC network.

            • -
            • Settings for PREDICT General, which contains the joblib Parallel settings and -whether a temporary save will be made after each cross validation.

            • -
            -
            -
            -

            Changed¶

            -
              -
            • Separate sinks for the output segmentations of the elastix and segmentix -nodes.

            • -
            • Switched from using PXCastConvert to WORCCastConvert, hence ITK is not -anymore required as well as ITK tools.

            • -
            -
            -
            -

            Fixed¶

            -
              -
            • Patientclass ID was used for both test and training. Now given separate names.

            • -
            • When elastix is used but segmentix isn’t, there was a bug.

            • -
            • DataFile dataype is now a TypeGroup instead of an URLType.

            • -
            • Last transformation output from elastix is passed further to the network.

            • -
            • Set FinalBSplineInterpolationOrder to 0 before transforming segmentation with -transformix.

            • -
            • Bug: when giving multiple feature sources, only the first was used.

            • -
            -
            -
            -
            -

            2.0.0 - 2018-02-13¶

            -
            -

            Added¶

            -
              -
            • Elastix and transformix as separate workflow in the tools folder. Can be used -through the WORC.Tools attribute.

            • -
            • Example data for elastix and transformix tool.

            • -
            • Workflow for separate training and testing set

            • -
            • FASTR tool for applying ttest to all features. Works similar to the -trainclassifier tool in terms of inputs and outputs.

            • -
            -
            -
            -

            Changed¶

            -
              -
            • Option for multiple modalities. Supports infinitely many inputs per object.

            • -
            • Moved many PREDICT parameters to the configuration file.

            • -
            • When using a multimodal workflow with only a single segmentation, -Elastix will automatically be used for registration. Note that you have to -put the reference segmentation on the first modality!

            • -
            -
            -
            -

            Fixed¶

            -
              -
            • Proper combining of features from multiple modalities to classify tool.

            • -
            • Minor bugs in segmentix tool.

            • -
            • For multiple modalities, add only optional sources like metadata when present.

            • -
            -
            -
            -
            -

            1.0.0rc1 - 2017-05-08¶

            -

            First release

            -
            -
            - - -
            - -
            -
            - - - - -
            - -
            -

            - © Copyright 2016 -- 2019, Biomedical Imaging Group Rotterdam, Departments of Medical Informatics and Radiology, Erasmus MC, Rotterdam, The Netherlands - -

            -
            - Built with Sphinx using a theme provided by Read the Docs. - -
            - -
            -
            - -
            - -
            - - - - - - - - - - - - \ No newline at end of file diff --git a/build/lib/WORC/doc/_build/html/static/configuration.html b/build/lib/WORC/doc/_build/html/static/configuration.html deleted file mode 100644 index a6ceead5..00000000 --- a/build/lib/WORC/doc/_build/html/static/configuration.html +++ /dev/null @@ -1,414 +0,0 @@ - - - - - - - - - - - Configuration — WORC 3.0.0 documentation - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
            - - - -
            - - - - - -
            - -
            - - - - - - - - - - - - - - - - - -
            - - - - -
            -
            -
            -
            - -
            -

            Configuration¶

            -

            As WORC and the default tools used are mostly Python based, we’ve chosen -to put our configuration in a configparser object. This has several -advantages:

            -
              -
            1. The object can be treated as a python dictionary and thus is easily adjusted.

            2. -
            3. Second, each tool can be set to parse only specific parts of the configuration, -enabling us to supply one file to all tools instead of needing many parameter files.

            4. -
            -

            The default configuration is generated through the -WORC.defaultconfig() -function. You can then change things as you would in a dictionary and -then append it to the configs source:

            -
            >>> network = WORC.WORC('somename')
            ->>> config = network.defaultconfig()
            ->>> config['Classification']['classifier'] = 'RF'
            ->>> network.configs.append(config)
            -
            -
            -

            When executing the WORC.set() command, the config objects are saved as -.ini files in the WORC.fastr_tempdir folder and added to the -WORC.fastrconfigs() source.

            -

            Below are some details on several of the fields in the configuration. -Note that for many of the fields, we currently only provide one default -value. However, when adding your own tools, these fields can be adjusted -to your specific settings.

            -

            WORC performs Combined Algorithm Selection and Hyperparameter (CASH) -optimization. The configuration determines how the optimization is -performed and which hyperparameters and models will be included. -Repeating specific models/parameters in the config will make them more -likely to be used, e.g.

            -
            >>> config['Classification']['classifiers'] = 'SVM, SVM, LR'
            -
            -
            -

            means that the SVM is 2x more likely to be tested in the model selection than LR.

            -
            -

            Note

            -

            All fields in the config must either be supplied as strings. A -list can be created by using commas for separation, e.g. -Network.create_source.

            -
            -
            -

            General¶

            -
            -
            -

            PREDICTGeneral¶

            -

            These fields contain general settings for when using PREDICT. -For more info on the Joblib settings, which are used in the Joblib -Parallel function, see here. When you run -WORC on a cluster with nodes supporting only a single core to be used -per node, e.g. the BIGR cluster, use only 1 core and threading as a -backend.

            -
            -
            -

            Segmentix¶

            -

            These fields are only important if you specified using the segmentix -tool in the general configuration.

            -
            -
            -

            Preprocessing¶

            -

            The preprocessing node acts before the feature extraction on the image. -Currently, only normalization is included: hence the dictionary name is -Normalize. Additionally, scans with image type CT (see later in the -tutorial) provided as DICOM are scaled to Hounsfield Units.

            -
            -
            -

            Imagefeatures¶

            -

            If using the PREDICT toolbox, you can specify some settings for the -feature computation here. Also, you can select if the certain features -are computed or not.

            -
            -
            -

            Featsel¶

            -

            When using the PREDICT toolbox for classification, these settings can be -used for feature selection methods. Note that these settings are -actually used in the hyperparameter optimization. Hence you can provide -multiple values per field, of which random samples will be drawn of -which finally the best setting in combination with the other -hyperparameters is selected. Again, these should be formatted as string -containing the actual values, e.g. value1, value2.

            -
            -
            -

            SelectFeatGroup¶

            -

            If the PREDICT feature computation and classification tools are used, -then you can do a gridsearch among the various feature groups for the -optimal combination. If you do not want this, set all fields to a single -value.

            -

            Previously, there was a single parameter for the texture features, -selecting all, none or a single group. This is still supported, but not -recommended, and looks as follows:

            -
            -
            -

            Imputation¶

            -

            When using the PREDICT toolbox for classification, these settings are -used for feature imputation.Note that these settings are actually used -in the hyperparameter optimization. Hence you can provide multiple -values per field, of which random samples will be drawn of which finally -the best setting in combination with the other hyperparameters is -selected.

            -
            -
            -

            Classification¶

            -

            When using the PREDICT toolbox for classification, you can specify the -following settings. Almost all of these are used in CASH. Most of the -classifiers are implemented using sklearn; hence descriptions of the -hyperparameters can also be found there.

            -
            -
            -

            CrossValidation¶

            -

            When using the PREDICT toolbox for classification and you specified -using cross validation, specify the following settings.

            -
            -
            -

            Labels¶

            -

            When using the PREDICT toolbox for classification, you have to set the -label used for classification.

            -

            This part is really important, as it should match your label file. -Suppose your patientclass.txt file you supplied as source for labels -looks like this:

            - ----- - - - - - - - - - - - - - - - - - - - - -

            Patient

            Label1

            Label2

            patient1

            1

            0

            patient2

            2

            1

            patient3

            1

            5

            -

            You can supply a single label or multiple labels split by commas, for -each of which an estimator will be fit. For example, suppose you simply -want to use Label1 for classification, then set:

            -
            config['Labels']['label_names'] = 'Label1'
            -
            -
            -

            If you want to first train a classifier on Label1 and then Label2, -set: config[Genetics][label_names] = Label1, Label2

            -
            -
            -

            Hyperoptimization¶

            -

            When using the PREDICT toolbox for classification, you have to supply -your hyperparameter optimization procedure here.

            -
            -
            -

            FeatureScaling¶

            -

            Determines which method is applied to scale each feature.

            -
            -
            -

            SampleProcessing¶

            -

            Before performing the hyperoptimization, you can use SMOTE: Synthetic -Minority Over-sampling Technique to oversample your data.

            -
            -
            -

            Ensemble¶

            -

            WORC supports ensembling of workflows. This is not a default approach in -radiomics, hence the default is to not use it and select only the best -performing workflow.

            -
            -
            -

            FASTR_bugs¶

            -

            Currently, when using XNAT as a source, FASTR can only retrieve DICOM -directories. We made a workaround for this for the images and -segmentations, but this only works if all your files have the same name -and extension. These are provided in this configuration part.

            -
            -
            - - -
            - -
            -
            - - - - -
            - -
            -

            - © Copyright 2016 -- 2019, Biomedical Imaging Group Rotterdam, Departments of Medical Informatics and Radiology, Erasmus MC, Rotterdam, The Netherlands - -

            -
            - Built with Sphinx using a theme provided by Read the Docs. - -
            - -
            -
            - -
            - -
            - - - - - - - - - - - - \ No newline at end of file diff --git a/build/lib/WORC/doc/_build/html/static/development.html b/build/lib/WORC/doc/_build/html/static/development.html deleted file mode 100644 index 4aedee2c..00000000 --- a/build/lib/WORC/doc/_build/html/static/development.html +++ /dev/null @@ -1,636 +0,0 @@ - - - - - - - - - - - Development and Design Documentation — WORC 2.1.3 documentation - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
            - - - -
            - - - - - -
            - -
            - - - - - - - - - - - - - - - - - -
            - - - - -
            -
            -
            -
            - -
            -

            Development and Design Documentation¶

            -

            In this chapter we will discuss the design of Fastr in more detail. We give -pointers for development and add the design documents as we currently envision -Fastr. This is both for people who are interested in the Fastr develop and for -current developers to have an archive of the design decision agreed upon.

            -
            -

            Sample flow in Fastr¶

            -

            The current Sample flow is the following:

            -digraph sampleflow { - Output [ - shape=plaintext - label=< - <table border="0"> - <tr> - <td border="1px" width="120" height="40" port="port">Output</td> - <td border="0" width="140" height="40"><b>ContainsSamples</b></td> - <td border="0" width="120" height="40" align="left"></td> - </tr> - </table> - > - ]; - SubOutput [ - shape=plaintext - label=< - <table border="0"> - <tr> - <td border="1px" width="120" height="40" port="port">SubOutput</td> - <td border="0" width="140" height="40"><b>ForwardsSamples</b></td> - <td border="0" width="120" height="40" align="left">selects cardinality</td> - </tr> - </table> - > - ]; - Link [ - shape=plaintext - label=< - <table border="0"> - <tr> - <td border="1px" width="120" height="40" port="port">Link</td> - <td border="0" width="140" height="40"><b>ForwardsSamples</b></td> - <td border="0" width="120" height="40" align="left">collapse + expand (changes cardinality and dimensions)</td> - </tr> - </table> - > - ]; - SubInput [ - shape=plaintext - label=< - <table border="0"> - <tr> - <td border="1px" width="120" height="40" port="port">SubInput</td> - <td border="0" width="140" height="40"><b>ForwardsSamples</b></td> - <td border="0" width="120" height="40" align="left">direct forward</td> - </tr> - </table> - > - ]; - Input [ - shape=plaintext - label=< - <table border="0"> - <tr> - <td border="1px" width="120" height="40" port="port">Input</td> - <td border="0" width="140" height="40"><b>ForwardsSamples</b></td> - <td border="0" width="120" height="40" align="left">broadcast matching (combine samples in cardinality)</td> - </tr> - </table> - > - ]; - InputGroup [ - shape=plaintext - label=< - <table border="0"> - <tr> - <td border="1px" width="120" height="40" port="port">InputGroup</td> - <td border="0" width="140" height="40"><b>ForwardsSamples</b></td> - <td border="0" width="120" height="40" align="left">broadcast matching (combine samples in payload)</td> - </tr> - </table> - > - ]; - NodeC [ - shape=plaintext - label=< - <table border="0"> - <tr> - <td border="1px" width="120" height="40" port="port">NodeRun</td> - <td border="0" width="140" height="40"><b>ForwardsSamples</b></td> - <td border="0" width="120" height="40" align="left">combines payloads (plugin based, e.g. cross product)</td> - </tr> - </table> - > - ]; - - Output:port -> SubOutput:port [weight=25]; - Output:port -> Link:port [weight=10]; - SubOutput:port -> SubOutput:port [weight=0]; - SubOutput:port -> Link:port [weight=25]; - Link:port -> SubInput:port; - SubInput:port -> Input:port; - Input:port -> InputGroup:port; - InputGroup:port -> NodeC:port; -}

            The idea is that we make a common interface for all classes that are related -to the flow of Samples. For this we propose the following mixin classes that -provide the interface and allow for better code sharing. The basic structure -of the classes is given in the following diagram:

            -digraph mixins { - node [ - fontname = "Bitstream Vera Sans" - fontsize = 9 - shape = "record" - ] - - edge [ - arrowtail = "empty" - ] - - HasDimensions [ - shape = record - label = "{HasDimensions|dimensions|+ size\l+ dimnames\l}" - ]; - HasSamples [ - shape = record - label = "{HasSamples|__getitem__()|+ __contains__\l+ __iter__\l+ iteritems()\l+ items()\l+ indexes\l+ ids \l}" - ]; - ContainsSamples [ - shape = record - label = "{ContainsSamples|samples|+ __getitem__()\l+ __setitem__()\l+ dimensions\l}" - ]; - ForwardsSamples [ - shape = record - label = "{ForwardsSamples|source\lindex_to_target\lindex_to_source\lcombine_samples\lcombine_dimensions|+ __getitem__\l+ dimensions\l}" - ]; - - HasDimensions -> HasSamples [dir=back]; - HasSamples -> ContainsSamples [dir=back]; - HasSamples -> ForwardsSamples [dir=back]; -}

            The abstract and mixin methods are as follows:

            - ------ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -

            ABC

            Inherits from

            Abstract Methods

            Mixin methods

            HasDimensions

            -
            dimensions
            -
            -
            -
            size
            -
            dimnames
            -
            -

            HasSamples

            HasDimensions

            -
            __getitem__
            -
            -
            -
            __contains__
            -
            __iter__
            -
            iteritems
            -
            items
            -
            indexes
            -
            ids
            -
            -

            ContainsSamples

            HasSamples

            -
            samples
            -
            -
            -
            __getitem__
            -
            __setitem__
            -
            dimensions
            -
            -

            ForwardsSamples

            HasSamples

            -
            source
            -
            index_to_target
            -
            index_to_source
            -
            combine_samples
            -
            combine_dimensions
            -
            -
            -
            __getitem__
            -
            dimensions
            -
            -
            -
            -

            Note

            -

            Though the flow is currently working like this, the mixins are not yet created.

            -
            -
            -
            -

            Network Execution¶

            -

            The network execution should contain a number of steps:

            -
              -
            • Network

              -
                -
              • Creates a NetworkRun based on the current layout

              • -
              -
            • -
            • NetworkRun

              -
                -
              • Transform the Network (possibly joining Nodes of certain interface into a combined NodeRun etc)

              • -
              • Start generation of the Job Direct Acyclic Graph (DAG)

              • -
              -
            • -
            • SchedulingPlugin

              -
                -
              • Prioritize Jobs based on some predefined rules

              • -
              • Combine certain Jobs to improve efficiency (e.g. minimize i/o on a grid)

              • -
              -
            • -
            • ExecutionPlugin

              -
                -
              • Run a (list of) Jobs. If there is more than one jobs, run them sequentially on -same execution host using a local temp for intermediate files.

              • -
              • On finished callback: Updated DAG with newly ready jobs, or remove cancelled jobs

              • -
              -
            • -
            -

            This could be visualized as the following loop:

            -digraph execution { - node [ - fontname = "Bitstream Vera Sans" - fontsize = 11 - shape = "box" - ] - - Network; - NetworkRun; - NodeRun; - JobDAG; - SchedulingPlugin; - ExecutionPlugin; - - Network -> NetworkRun [label=creates]; - NetworkRun -> JobDAG [label=creates]; - NetworkRun -> NodeRun [label=executes]; - NodeRun -> JobDAG [label="adds jobs"]; - JobDAG -> SchedulingPlugin [label="analyzes and selects jobs"]; - SchedulingPlugin -> ExecutionPlugin [label="(list of) Jobs to execute"]; - ExecutionPlugin -> NetworkRun [label=callback]; -}

            The callback of the ExecutionPlugin to the NetworkRun would trigger -the execution of the relevant NodeRuns and the addition of more Jobs -to the JobDAG.

            -
            -

            Note

            -

            The Job DAG should be thread-safe as it could be both read and -extended at the same time.

            -
            -
            -

            Note

            -

            If a list of jobs is send to the ExecutionPlugin to be run as -on Job on an external execution platform, the resources should be -combined as follows: memory=max, cores=max, runtime=sum

            -
            -
            -

            Note

            -

            If there are execution hosts that have mutliple cores the -ExecutionPlugin should manage this (for example by using pilot -jobs). The SchedulingPlugin creates units that should be run -sequentially on the resources noted and will not attempt -parallelization

            -
            -

            A NetworkRun would be contain similar information as the Network but -not have functionality for editting/changing it. It would contain the -functionality to execute the Network and track the status and samples. This -would allow Network.execute to create multiple concurent runs that operate -indepent of each other. Also editting a Network after the run started would -have no effect on that run.

            -
            -

            Note

            -

            This is a plan, not yet implemented

            -
            -
            -

            Note

            -

            For this to work, it would be important for a Jobs to have forward -and backward dependency links.

            -
            -
            -

            SchedulingPlugins¶

            -

            The idea of the plugin is that it would give a priority on Jobs created by a -Network. This could be done based on different strategies:

            -
              -
            • Based on (sorted) sample id’s, so that one sample is always prioritized over -others. The idea is that samples are process as much as possible in order, -finishing the first sample first. Only processing other samples if there is -left-over capacity.

            • -
            • Based on distance to a (particular) Sink. This is to generate specific -results as quick as possible. It would not focus on specific samples, but -give priority to whatever sample is closest to being finished.

            • -
            • Based on the distance to from a Souce. Based on the sign of the weight -it would either keep all samples on the same stage as much as possible, only -progressing to a new NodeRun when all samples are done with the previous -NodeRun, or it would push samples with accelerated rates.

            • -
            -

            Additionally it will group Jobs to be executed on a single host. This could -reduce i/o and limited the number of jobs an external scheduler has to track.

            -
            -

            Note

            -

            The interface for such a plugin has not yet been established.

            -
            -
            -
            -
            -

            Secrets¶

            -

            “Something that is kept or meant to be kept unknown or unseen by others.â€

            -
            -

            Using secrets¶

            -

            Fastr IOPlugins that need authentication data should use the Fastr SecretService for retrieving such data. The SecretService can be used as follows.

            -
            from fastr.utils.secrets import SecretService
            -from fastr.utils.secrets.exceptions import CouldNotRetrieveCredentials
            -
            -secret_service = SecretService()
            -
            -try:
            -  password = secret_service.find_password_for_user('testserver.lan:9000', 'john-doe')
            -except CouldNotRetrieveCredentials:
            -  # the password was not found
            -  pass
            -
            -
            -
            -
            -

            Implementing a SecretProvider¶

            -

            A SecretProvider is implemented as follows:

            -
              -
            1. Create a file in fastr/utils/secrets/providers/<yourprovidername>.py

            2. -
            3. Use the template below to write your SecretProvider

            4. -
            5. Add the secret provider to fastr/utils/secrets/providers/__init__.py

            6. -
            7. Add the secret provider to fastr/utils/secrets/secretservice.py: import it and add it to the array in function _init_providers

            8. -
            -
            from fastr.utils.secrets.secretprovider import SecretProvider
            -from fastr.utils.secrets.exceptions import CouldNotRetrieveCredentials, CouldNotSetCredentials, CouldNotDeleteCredentials, NotImplemented
            -
            -
            -try:
            -  # this is where libraries can be imported
            -  # we don't want fastr to crash if a specific
            -  # library is unavailable
            -  # import my-libary
            -except (ImportError, ValueError) as e:
            -  pass
            -
            -class KeyringProvider(SecretProvider):
            -  def __init__(self):
            -    # if libraries are imported in the code above
            -    # we need to check if import was succesfull
            -    # if it was not, raise a RuntimeError
            -    # so that FASTR ignores this SecretProvider
            -    # if 'my-library' not in globals():
            -    #   raise RuntimeError("my-library module required")
            -    pass
            -
            -  def get_password_for_user(self, machine, username):
            -    # This function should return the password as a string
            -    # or raise a CouldNotRetrieveCredentials error if the password
            -    # is not found.
            -    # In the event that this function is unsupported a
            -    # NotImplemented exception should be thrown
            -    raise NotImplemented()
            -
            -  def set_password_for_user(self, machine, username, password):
            -    # This function should set the password for a specified
            -    # machine + user. If anything goes wrong while setting
            -    # the password a CouldNotSetCredentials error should be raised.
            -    # In the event that this function is unsupported a
            -    # NotImplemented exception should be thrown
            -    raise NotImplemented()
            -
            -  def del_password_for_user(self, machine, username):
            -    # This function should delete the password for a specified
            -    # machine + user. If anything goes wrong while setting
            -    # the password a CouldNotDeleteCredentials error should be raised.
            -    # In the event that this function is unsupported a
            -    # NotImplemented exception should be thrown
            -    raise NotImplemented()
            -
            -
            -
            -
            -
            - - -
            - -
            -
            - - - - -
            - -
            -

            - © Copyright 2016 -- 2019, Biomedical Imaging Group Rotterdam, Departments of Medical Informatics and Radiology, Erasmus MC, Rotterdam, The Netherlands - -

            -
            - Built with Sphinx using a theme provided by Read the Docs. - -
            - -
            -
            - -
            - -
            - - - - - - - - - - - - \ No newline at end of file diff --git a/build/lib/WORC/doc/_build/html/static/file_description.html b/build/lib/WORC/doc/_build/html/static/file_description.html deleted file mode 100644 index 72d355d5..00000000 --- a/build/lib/WORC/doc/_build/html/static/file_description.html +++ /dev/null @@ -1,218 +0,0 @@ - - - - - - - - - - - Resource File Formats — WORC 3.0.0 documentation - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
            - - - -
            - - - - - -
            - -
            - - - - - - - - - - - - - - - - - -
            - - - - -
            -
            -
            -
            - -
            -

            Resource File Formats¶

            -

            This chapter describes the various files WORC uses. The function and format -of the files is described allowing the user to configure WORC and add -DataTypes and Tools.

            -
            - - -
            - -
            -
            - - - - -
            - -
            -

            - © Copyright 2016 -- 2019, Biomedical Imaging Group Rotterdam, Departments of Medical Informatics and Radiology, Erasmus MC, Rotterdam, The Netherlands - -

            -
            - Built with Sphinx using a theme provided by Read the Docs. - -
            - -
            -
            - -
            - -
            - - - - - - - - - - - - \ No newline at end of file diff --git a/build/lib/WORC/doc/_build/html/static/introduction.html b/build/lib/WORC/doc/_build/html/static/introduction.html deleted file mode 100644 index 235d1752..00000000 --- a/build/lib/WORC/doc/_build/html/static/introduction.html +++ /dev/null @@ -1,306 +0,0 @@ - - - - - - - - - - - Introduction — WORC 3.0.0 documentation - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
            - - - -
            - - - - - -
            - -
            - - - - - - - - - - - - - - - - - -
            - - - - -
            -
            -
            -
            - -
            -

            Introduction¶

            -

            When I started my PhD at the Erasmus MC in 2016 on radiomics, the idea was to start with a straight-forward radiomics study to get familiar with the field. -Both the field of radiomics and my group at the Erasmus MC had existed for quite some time. -Therefore, I naively expected that all previously created methods and software were nicely organized and would be straight forward to apply and compare. -However, I found that of all the radiomics studies, only a few actually released their software open-source. -Moreover, the software that was available was very diverse in terms of programming language and often difficult to understand. -Each developer used its own ontology, workflow and implementation.

            -

            Hence I wondered which method would work best for my specific application. -It seemed that many of my fellow PhD students started out with the same question. -I did not like the foresight to start out my PhD by tediously working on finding a decent baseline and trying out all kinds of methods. -Moreover, it felt inefficient that every time a new study is started, someone like me had to go through the whole process over and over again.

            -

            I therefore decided to create one radiomics platform in which multiple approaches could easily be integrated. -I tried to make it as flexible as possible and modular, such that researcher can easily integrate their own components into the workflow.

            -

            Including all these methods brought along many choices in terms of both the methods to use and their parameters. -Similar to the above, I also did not like the foresight of manual tuning, which both feels inefficient and a non-optimal approach. -Hence, I decided to create an automatic optimization routine for the platform which includes all the choices in the workflow that have to be made.

            -

            The result is WORC, which has made my research a lot easier and more fun, as I can very easily create a decent radiomics baseline for any study with little effort.

            -
            -

            Radiomics Terminology¶

            -

            Radiomics concerns the use of quantitative medical image features to predict clinically relevant outcomes. -In WORC, the computational radiomics workflow is divided in five steps:

            -
            -../_images/RadiomicsSteps.png -
            -
              -
            1. Image Acquisition, which we assume has already been done.

            2. -
            3. Preprocessing

            4. -
            5. Segmentation

            6. -
            7. Feature Extraction

            8. -
            9. Data Mining

            10. -
            -

            Preprocessing is defined as anything that is done to the image before the feature extraction. -This may include normalization, cropping, masking, and registration. Filtering may be included as well, although several features may already implicitly use a filter.

            -

            Data mining is defined as anything that is used to go from features to the actual label or outcome. -This may include feature selection, feature imputation, feature scaling, dimensionality reduction, and oversampling. -Note that we always define the last step in data mining as a machine learning approach. -Although several radiomics studies do not use machine learning but directly correlate features with outcome, -we feel that in clinical practice a prediction model is most of the time required.

            -

            Due to the shear amount of tools available in the data mining node, this node in itself is another fastr (micro)network.

            -
            -
            -

            Modularity and standardization: fastr¶

            -

            The first step of building WORC was to standardize radiomics in components to create a modular workflow. -The available radiomics methods were all in different software languages, hence my framework had to support this as well. -Luckily, some of my colleagues had the same issues and decided to create a new workflow engine: `fastr http://journal.frontiersin.org/article/10.3389/fict.2016.00015/full/>`_. -I highly recommend to read at least the introductory page of the manual in order to get familiar with the basic concept of fastr .

            -

            To illustrate the principles of fastr, one of the simpler workflows created by WORC using fastr is shown in the figure below.

            -
            -../_images/WORC_small.png -
            -

            The radiomics workflow is split in nodes. We define four types of nodes: -* Sources, which serve as the input for the workflow. -* Nodes, which is where the actual algorithms run. -* Sinks, which serve as the output for the workflow. -* Constants

            -

            In each node, the inputs, outputs and thereby the task is fixed. However, the actual algorithm that is used within a node is node. -For example, in a feature extraction node, the inputs are an image, possibly a segmentation and parameters, from which features are extracted, which are thereby the output. -Which methods is actually used to extract the features and the features extracted may vary.

            -

            Using fastr in WORC gives us several benefits: -* You can use any tool that can be run on the command line: thus languages or interpreters like MATLAB, Python, R, but also executables. -* As the workflow is standardized, the outputs are as well. Hence workflows can be easily compared. -* fastr automatic keeps a history of how an output was created, or the provenance, and extensive logging. This facilitates high reproducability. -* Wrapping a tool in fastr is easy: you only need to determine the inputs, outputs, interpreter and script. -* fastr supports various execution plugins, thus execution of a pipeline on a cluster or a simple laptop can be adapted to the resources at hand. -* Data can be imported and exported to various sources, also online!

            -
            -
            -

            Optimization¶

            -

            When starting a new radiomics study, e.g. trying to find a imaging biomarker on a new dataset, you would normally have to design a workflow yourself from all methods available in WORC. -Not only would you have to determine which methods you are going to use, but also which parameters for all methods. Many studies have shown that these are often not independent: -the performance of many methods highly depends on the parameters used. Thus, we need to simultanously look for the best combination of these.

            -

            As these parameters are set before the actual learning step in the machine learning part, we refer to these as hyperparameters. -As the performance of the machine learning algorithm may depend on the previous steps -(e.g. preprocessing, feature extraction, and all other steps in the data mining node), -we decided to include all parameters from all nodes as hyperparameters.

            -

            Optimization is done through a variant of combined algorithm selection and hyperparameter (CASH) optimization problem. -Currently, WORC solves the problem as following:

            -
            -../_images/CASH.png -
            -
              -
            1. Generate a large number of different pipelines.

            2. -
            3. Execute them and rank them.

            4. -
            5. Create and ensemble of the X best performing pipelines.

            6. -
            -

            More information on this can be found in X.

            -
            -
            - - -
            - -
            -
            - - - - -
            - -
            -

            - © Copyright 2016 -- 2019, Biomedical Imaging Group Rotterdam, Departments of Medical Informatics and Radiology, Erasmus MC, Rotterdam, The Netherlands - -

            -
            - Built with Sphinx using a theme provided by Read the Docs. - -
            - -
            -
            - -
            - -
            - - - - - - - - - - - - \ No newline at end of file diff --git a/build/lib/WORC/doc/_build/html/static/quick_start.html b/build/lib/WORC/doc/_build/html/static/quick_start.html deleted file mode 100644 index 8ff71f11..00000000 --- a/build/lib/WORC/doc/_build/html/static/quick_start.html +++ /dev/null @@ -1,287 +0,0 @@ - - - - - - - - - - - Quick start guide — WORC 3.0.0 documentation - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
            - - - -
            - - - - - -
            - -
            - - - - - - - - - - - - - - - - - -
            - - - - -
            -
            -
            -
            - -
            -

            Quick start guide¶

            -

            This manual will show users how to install WORC, configure WORC and construct and run simple networks.

            -
            -

            Installation¶

            -

            You can install WORC either using pip, or from the source code.

            -
            -

            Installing via pip¶

            -

            You can simply install WORC using pip:

            -
            pip install WORC
            -
            -
            -
            -

            Note

            -

            You might want to consider installing WORC in a virtualenv

            -
            -
            -
            -

            Installing from source code¶

            -

            To install from source code, use git via the command-line:

            -
            git clone https://github.com/MStarmans91/WORC.git  # for http
            -git clone ssh://git@github.com:MStarmans91/WORC.git # for ssh
            -
            -
            -

            To install to your current Python environment, run:

            -
            cd WORC/
            -pip install .
            -
            -
            -

            This installs the scripts and packages in the default system folders. For -Windows this is the python site-packages directory for the WORC python -library. For Ubuntu this is in the /usr/local/lib/python3.x/dist-packages/ folder.

            -
            -

            Note

            -

            If you want to develop WORC, you might want to use pip install -e . to get an editable install

            -
            -
            -

            Note

            -

            You might want to consider installing WORC in a virtualenv

            -
            -
            -
            -
            -

            Configuration¶

            -

            WORC has defaults for all settings so it can be run out of the box to test the examples. -However, you may want to alter the fastr configuration to your system settings, e.g. -to locate your input and output folders and how much you want to parallelize the execution.

            -

            Fastr will search for a config file named config.py in the $FASTRHOME directory -(which defaults to ~/.fastr/ if it is not set). So if $FASTRHOME is set the ~/.fastr/ -will be ignored. Additionally, .py files from the $FASTRHOME/config.d folder will be parsed -as well. You will see that upon installation, WORC has already put a WORC_config.py file in the -config.d folder.

            -

            For a sample configuration file and a complete overview of the options in config.py see -the Config file section.

            -
            -
            -

            Tutorial¶

            -

            To start out using WORC, we recommend you to follow the tutorial located in the -[WORCTutorial Github](https://github.com/MStarmans91/WORCTutorial). Besides some more advanced tutorials, -the main tutorial can be found in the WORCTutorial.ipynb Jupyter notebook. Instructions on how -to use the notebook can be found in the Github.

            -

            If you run into any issue, you can first debug your network using -the fastr trace tool. -If you’re stuck, feel free to post an issue on the WORC Github.

            -
            -
            - - -
            - -
            -
            - - - - -
            - -
            -

            - © Copyright 2016 -- 2019, Biomedical Imaging Group Rotterdam, Departments of Medical Informatics and Radiology, Erasmus MC, Rotterdam, The Netherlands - -

            -
            - Built with Sphinx using a theme provided by Read the Docs. - -
            - -
            -
            - -
            - -
            - - - - - - - - - - - - \ No newline at end of file diff --git a/build/lib/WORC/doc/_build/html/static/reference.html b/build/lib/WORC/doc/_build/html/static/reference.html deleted file mode 100644 index 6a479ab8..00000000 --- a/build/lib/WORC/doc/_build/html/static/reference.html +++ /dev/null @@ -1,211 +0,0 @@ - - - - - - - - - - - Resource Reference — WORC 2.1.3 documentation - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
            - - - -
            - - - - - -
            - -
            - - - - - - - - - - - - - - - - - -
            - - - - -
            -
            -
            -
            - -
            -

            Resource Reference¶

            -

            In this chapter we describe the different plugins bundled with Fastr (e.g. -IOPlugins, ExecutionPlugins). The reference is build automatically from code, -so after installing a new plugin the documentation has to be rebuild for it to -be included in the docs.

            -
            - - -
            - -
            -
            - - -
            - -
            -

            - © Copyright 2016 -- 2019, Biomedical Imaging Group Rotterdam, Departments of Medical Informatics and Radiology, Erasmus MC, Rotterdam, The Netherlands - -

            -
            - Built with Sphinx using a theme provided by Read the Docs. - -
            - -
            -
            - -
            - -
            - - - - - - - - - - - - \ No newline at end of file diff --git a/build/lib/WORC/doc/_build/html/static/tools.html b/build/lib/WORC/doc/_build/html/static/tools.html deleted file mode 100644 index 1d4101bb..00000000 --- a/build/lib/WORC/doc/_build/html/static/tools.html +++ /dev/null @@ -1,236 +0,0 @@ - - - - - - - - - - - Guidlines on using and creating Fastr tools — WORC 2.1.3 documentation - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
            - - - -
            - - - - - -
            - -
            - - - - - - - - - - - - - - - - - -
            - - - - -
            -
            -
            -
            - -
            -

            Guidlines on using and creating Fastr tools¶

            -

            Fastr pulls its tools definitions from a repository called FastrHub. Optionally tool definitions can also be pulled from a -local folder or a private repository.

            -
            -A flowchart of the Fastr tool loading order. Priority is as follows: 1 load from cache, 2 load from local disk, 3 load from FastrHub repository, 4 raise Fastr Cannot Find Tool Definition Exception. -

            Fastr tool definition loading order.¶

            -
            -
            -

            Creating a tool definition¶

            -

            The tool definition (xml file) is a wrapper. We should version these wrappers. Use the version property in the tool element to do this.

            -
            -
            -

            Uploading a tool definition to FastrHub¶

            -

            Tool definitions in FastrHub can not be overwritten. This is to improve reproducability. A tool definition can be changed to ‘deprecated’ which hides it from search but it will still be downloadable. -The example below pushes the FSLMaths tool into the fsl namespace. It uses definition v1.0. This is the version property in the tool-element of your tool-wrapper xml.

            -
            $ fastr tools push fsl/FSLMaths 1.0
            -  Username: demo
            -  Password: *****
            -  Uploading [########--] 80%
            -
            -
            -
            -
            -

            Code examples¶

            -

            Instantiate a node that uses the FSLMaths tool.

            -
            # network.create_node('<required:namespace>/<required:tool>:<required:command_version>', tool_version='<required:tool_version>', repositoy='<optional:repo url, defaults to FastrHub>')
            -node = network.create_node('fsl/FSLMaths:5.0.9', tool_version='1.0')
            -
            -
            -
            -
            - - -
            - -
            -
            - - -
            - -
            -

            - © Copyright 2016 -- 2019, Biomedical Imaging Group Rotterdam, Departments of Medical Informatics and Radiology, Erasmus MC, Rotterdam, The Netherlands - -

            -
            - Built with Sphinx using a theme provided by Read the Docs. - -
            - -
            -
            - -
            - -
            - - - - - - - - - - - - \ No newline at end of file diff --git a/build/lib/WORC/doc/_build/html/static/user_manual.html b/build/lib/WORC/doc/_build/html/static/user_manual.html deleted file mode 100644 index 1bedc4e6..00000000 --- a/build/lib/WORC/doc/_build/html/static/user_manual.html +++ /dev/null @@ -1,452 +0,0 @@ - - - - - - - - - - - User Manual — WORC 3.0.0 documentation - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
            - - - -
            - - - - - -
            - -
            - - - - - - - - - - - - - - - - - -
            - - - - -
            -
            -
            -
            - -
            -

            User Manual¶

            -

            In this chapter we will discuss the parts of Fastr in more detail. We will give a more complete overview of the system -and describe the more advanced features.

            -
            -

            The WORC object¶

            -

            The WORC toolbox consists of one main object, the WORC object:

            -
            import WORC
            -network = WORC.WORC('somename')
            -
            -
            -

            It’s attributes are split in a couple of categories. We will not discuss -the WORC.defaultconfig() function here, which generates the default -configuration, as it is listed in a separate page, see the config file section.

            -
            -
            -

            Attributes: Sources¶

            -

            There are numerous WORC attributes which serve as source nodes for the -FASTR network. These are:

            -
              -
            • images_train and images_test

            • -
            • segmentations_train and segmentations_test

            • -
            • semantics_train and semantics_test

            • -
            • labels_train and labels_test

            • -
            • masks_train and masks_test

            • -
            • features_train and features_test

            • -
            • metadata_train and metadata_test

            • -
            • Elastix_Para

            • -
            • fastrconfigs

            • -
            -

            When using a single dataset for both training and evaluation, you should -supply all sources in train objects. You can use several kinds of -validation methods (e.g.cross validation) to compute the performance on -this dataset. Optionally, you can supply a separate training and test -set.

            -

            Each source should be given as a dictionary of strings corresponding to -the source files. Each element should correspond to a single object, -e.g. tumor, or patient. The keys are used to match the features to the -label and semantics sources, so make sure these correspond to the label -file. The values should refer to the actual source files corresponding -to the FASTR formats, see -http://fastr.readthedocs.io/en/stable/fastr.reference.html#ioplugin-reference.

            -

            You can off course have multiple images or ROIs per object, e.g. a liver -ROI and a tumor ROI. This can be easily done by appending to the -sources. For example:

            -
            images1 = {'patient1': vfs://example/MR.nii, 'patient2': vfs://example/MR.nii}
            -segmentations1 = {'patient1': vfs://example/tumor.nii, 'patient2': vfs://example/tumor.nii}
            -segmentations2 = {'patient1': vfs://example/liver.nii, 'patient2': vfs://example/liver.nii}
            -
            -network.images_train.append(images1)
            -network.images_train.append(images1)
            -
            -network.segmentations_train.append(segmentations1)
            -network.segmentations_train.append(segmentations2)
            -
            -
            -

            When using multiple sequences per patients (e.g. T1 and T2), the same -appending procedure can be used.

            -
            -

            Note

            -

            You have to make sure the images and segmentation sources match in size.

            -
            -
            -

            Note

            -

            You have to supply a configuration file for each image or feature source you append. -Thus, in above example, you need to append two configurations!

            -
            -
            -

            Note

            -

            When you use -multiple image sequences, you can supply a ROI for each sequence by -appending to to segmentations object. Alternatively, when you do not -supply a segmentation for a specific sequence, WORC will use Elastix to -align this sequence to another through image registration. It will then -warp the segmentation from this sequence to the sequence for which you -did not supply a segmentation. WORC will always align these sequences with no segmentations to the first sequence, i.e. the first object in the images_train list. -Hence make sure you supply the sequence for which you have a ROI as the first object.

            -
            -
            -
            -

            Attributes: Settings¶

            -

            There are several attributes in WORC which define how your pipeline is -executed:

            -
              -
            • fastr_plugin

            • -
            • fastr_tmpdir

            • -
            • Tools: additional workflows are stored here. Currently only includes -a pipeline for image registration without any Radiomics.

            • -
            • CopyMetadata: Whether to automatically copy the metadata info -(e.g. direction of cosines) from the images to the segmentations -before applying transformix.

            • -
            -

            An explanation of the FASTR settings is given below.

            -
            -
            -

            Attributes: Functions¶

            -

            The WORC.configs() attribute contains the configparser files, which you -can easily edit. The WORC.set() function saves these objects in a -temporary folder and converts the filename into as FASTR source, which -is then put in the WORC.fastrconfigs() objects. Hence you do not need to -edit the fastrconfigs object manually.

            -
            -

            Images and segmentations¶

            -

            The minimal input for a Radiomics pipeline consists of either images -(plus a segmentation if you have not implemented an automatic -segmentation tool) or features plus a label file (and a configuration, -but you can just use the default one.

            -

            If you supply these, features will be computed within the segmentations -on the images. They are read out using SimpleITK, which supports various -image formats such as DICOM, NIFTI, TIFF, NRRD and MHD.

            -
            -
            -

            Semantics¶

            -

            Semantic features are used in the PREDICT CalcFeatures tool. You can -supply these as a .csv listing your features per patient. The first -column should always be named Patient and contain the Patient ID. The -other columns should contain a label for the feature and their values. -For example:

            - ----- - - - - - - - - - - - - - - - - - - - - -

            Patient

            Label1

            Label2

            patient1

            1

            0

            patient2

            2

            1

            patient3

            1

            5

            -

            Similar to the patient labels, the semantic features are matched to the -correct image/features by the name of the image/features. So in this -case, your sources should look as following:

            -
            images_train = {'patient1': 'source1.nii.gz', 'patient2': 'source2.nii.gz', ...}
            -segmentations_train = {'patient1': 'seg1.nii.gz', 'patient2': 'seg2.nii.gz', ...}
            -
            -
            -
            -
            -

            Labels¶

            -

            The labels are used in classification. For PREDICT, these should be -supplied as a .txt file. Similar to the semantics, the first column -should head Patient and contain the patient ID. The next columns can -contain things you want to predict. Hence the format is similar to the -semantics file.

            -
            -
            -
            -

            Masks¶

            -

            WORC contains a segmentation preprocessing tool, called segmentix. This -tool is still under development. The idea is that you can manipulate -your segmentation, e.g. using dilation, then use a mask to make sure it -is still valid. Currently, you can only let it take a ring of a certain -radius around your ROI and mask it.

            -
            -
            -

            Features¶

            -

            If you already computed your features, e.g. from a previous run, you can -directly supply the features instead of the images and segmentations and -skip the feature computation step. These should be stored in .hdf5 files -matching the PREDICT CalcFeatures format.

            -
            -
            -

            Metadata¶

            -

            This source can be used if you want to use tags from the DICOM header as -features, e.g. patient age and sex. In this case, this source should -contain a single DICOM per patient from which the tags that are read. -Check the PREDICT.imagefeatures.patient_feature module for the currently -implemented tags.

            -
            -
            -

            Elastix_Para¶

            -

            If you have multiple images for each patient, e.g. T1 and T2, but only a -single segmentation, you can use image registration to align and -transform the segmentation to the other modality. This is done in WORC -using Elastix http://elastix.isi.uu.nl/. In this source, you can supply -a parameter file for Elastix to be used in the registration in .txt. -format. Alternatively, you can use SimpleElastix to generate a parameter -map and pass this object to WORC. Note: WORC assume your segmentation -is made on the first WORC.images source you supply. The segmentation -will be alingned to all other image sources.

            -
            -
            -

            FASTR settings¶

            -

            There are two WORC attributes which contain settings on running FASTR. -In WORC.fastr_plugin, you can specify which Execution Plugin should be -used: see also -http://fastr.readthedocs.io/en/stable/fastr.reference.html#executionplugin-reference.

            -

            The default is the ProcessPollExecution plugin. The WORC.fastr_tempdir -sets the temporary directory used in your run.

            -
            -
            -

            Construction and execution commands¶

            -

            After supplying your sources, you need to build the FASTR network. This -can be done through the WORC.build() command. Depending on your sources, -several nodes will be added and linked. This creates the WORC.network() -object, which is a fastr.network() object. You can edit this network -freely, e.g. add another source or node. You can print the network with -the WORC.network.draw_network() command.

            -

            Next, we have to tell the network which sources should be used in the -source nodes. This can be done through the WORC.set() command. This will -put your supplied sources into the source nodes and also creates the -needed sink nodes. You can check these by looking at the created -WORC.source_data_data and WORC.sink objects.

            -

            Finally, after completing above steps, you can execute the network -through the WORC.execute() command.

            -
            -
            - - -
            - -
            -
            - - - - -
            - -
            -

            - © Copyright 2016 -- 2019, Biomedical Imaging Group Rotterdam, Departments of Medical Informatics and Radiology, Erasmus MC, Rotterdam, The Netherlands - -

            -
            - Built with Sphinx using a theme provided by Read the Docs. - -
            - -
            -
            - -
            - -
            - - - - - - - - - - - - \ No newline at end of file diff --git a/build/lib/WORC/doc/_build/html/user_reference/user_reference.html b/build/lib/WORC/doc/_build/html/user_reference/user_reference.html deleted file mode 100644 index c5fd03eb..00000000 --- a/build/lib/WORC/doc/_build/html/user_reference/user_reference.html +++ /dev/null @@ -1,803 +0,0 @@ - - - - - - - - - - - Fastr User Reference — WORC 2.1.3 documentation - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
            - - - -
            - - - - - -
            - -
            - - - - - - - - - - - - - - - - - -
            - - - - -
            -
            -
            -
            - -
            -

            Fastr User Reference¶

            -
            -
            -fastr.tools¶
            -

            A ToolManager containing all versions of all Tools loaded into the FASTR -environment. The ToolManager can be indexed using the Tool id string or -a tool id string and a version. For example if you have two versions (4.5 -and 4.8) of a tool called Elastix:

            -
            >>> fastr.tools['elastix.Elastix']
            -Tool Elastix v4.8 (Elastix Registration)
            -                           Inputs                              |             Outputs
            ---------------------------------------------------------------------------------------------------
            -fixed_image       (ITKImageFile)                               |  directory (Directory)
            -moving_image      (ITKImageFile)                               |  transform (ElastixTransformFile)
            -parameters        (ElastixParameterFile)                       |  log_file  (ElastixLogFile)
            -fixed_mask        (ITKImageFile)                               |
            -moving_mask       (ITKImageFile)                               |
            -initial_transform (ElastixTransformFile)                       |
            -priority          (__Elastix_4.8_interface__priority__Enum__)  |
            -threads           (Int)                                        |
            -
            ->>> fastr.tools['elastix.Elastix', '4.5']
            -Tool Elastix v4.5 (Elastix Registration)
            -                           Inputs                              |             Outputs
            ---------------------------------------------------------------------------------------------------
            -fixed_image       (ITKImageFile)                               |  directory (Directory)
            -moving_image      (ITKImageFile)                               |  transform (ElastixTransformFile)
            -parameters        (ElastixParameterFile)                       |  log_file  (ElastixLogFile)
            -fixed_mask        (ITKImageFile)                               |
            -moving_mask       (ITKImageFile)                               |
            -initial_transform (ElastixTransformFile)                       |
            -priority          (__Elastix_4.5_interface__priority__Enum__)  |
            -threads           (Int)                                        |
            -
            -
            -
            - -
            -
            -fastr.types¶
            -

            A dictionary containing all types loaded into the FASTR environment. The keys are the typenames and the values are the classes.

            -
            - -
            -
            -fastr.networks¶
            -

            A dictionary containing all networks loaded in fastr

            -
            - -
            -
            -api.create_network(version=None)¶
            -

            Create a new Network object

            -
            -
            Parameters
            -
              -
            • id (str) – id of the network

            • -
            • version (Union[Version, str, None]) – version of the network

            • -
            -
            -
            Return type
            -

            Network

            -
            -
            Returns
            -

            -
            -
            -
            - -
            -
            -api.create_network_copy()¶
            -

            Create a network based on another Network state. The network state can be a Network -or the state gotten from a Network with __getstate__.

            -
            -
            Parameters
            -

            network_state (Union[Network, Network, dict]) – Network (state) to create a copy of

            -
            -
            Return type
            -

            Network

            -
            -
            Returns
            -

            The rebuilt network

            -
            -
            -
            - -
            -
            -class fastr.api.Network(id, version=None)[source]¶
            -

            Representation of a Network for the creating and adapting Networks

            -
            -
            -create_constant(datatype, data, id=None, step_id=None, resources=None, node_group=None)[source]¶
            -

            Create a ConstantNode in this Network. The Node will be automatically added to -the Network.

            -
            -
            Parameters
            -
              -
            • datatype (Union[BaseDataType, str]) – The DataType of the constant node

            • -
            • data (Dict[str, Union[List[Union[str, Tuple[str, …]]], Dict[str, Union[str, Tuple[str, …]]]]]) – The data to hold in the constant node

            • -
            • id (Optional[str]) – The id of the constant node to be created

            • -
            • step_id (Optional[str]) – The step to add the created constant node to

            • -
            • resources (Optional[ResourceLimit]) – The resources required to run this node

            • -
            • node_group (Optional[str]) – The group the node belongs to, this can be -important for FlowNodes and such, as they -will have matching dimension names.

            • -
            -
            -
            Return type
            -

            Node

            -
            -
            Returns
            -

            the newly created constant node

            -
            -
            -
            - -
            - -

            Create a link between two Nodes and add it to the current Network.

            -
            -
            Parameters
            -
              -
            • source (Union[Input, BaseInput]) – the output that is the source of the link

            • -
            • target (Union[Output, BaseOutput]) – the input that is the target of the link

            • -
            • id (Optional[str]) – the id of the link

            • -
            • collapse (Optional[Tuple[Union[int, str], …]]) – The dimensions to collapse in this link.

            • -
            • expand (bool) – Flag to expand cardinality into a new dimension

            • -
            -
            -
            Return type
            -

            Link

            -
            -
            Returns
            -

            the created link

            -
            -
            -
            - -
            -
            -create_macro(network, id=None)[source]¶
            -

            Create macro node (a node which actually contains a network used as node -inside another network).

            -
            -
            Parameters
            -
              -
            • network (Union[Network, Network, dict, Tool, str]) – The network to use, this can be a network (state), a -macro tool, or the path to a python file that contains -a function create_network which returns the desired -network.

            • -
            • id (Optional[str]) – The id of the node to be created

            • -
            -
            -
            Return type
            -

            Node

            -
            -
            Returns
            -

            the newly created node

            -
            -
            -
            - -
            -
            -create_node(tool, tool_version, id=None, step_id=None, resources=None, node_group=None)[source]¶
            -

            Create a Node in this Network. The Node will be automatically added to -the Network.

            -
            -
            Parameters
            -
              -
            • tool (Union[Tool, str]) – The Tool to base the Node on in the form: name/space/toolname:version

            • -
            • tool_version (str) – The version of the tool wrapper to use

            • -
            • id (Optional[str]) – The id of the node to be created

            • -
            • step_id (Optional[str]) – The step to add the created node to

            • -
            • resources (Optional[ResourceLimit]) – The resources required to run this node

            • -
            • node_group (Optional[str]) – The group the node belongs to, this can be -important for FlowNodes and such, as they -will have matching dimension names.

            • -
            -
            -
            Return type
            -

            Node

            -
            -
            Returns
            -

            the newly created node

            -
            -
            -
            - -
            -
            -create_sink(datatype, id=None, step_id=None, resources=None, node_group=None)[source]¶
            -

            Create a SinkNode in this Network. The Node will be automatically added to -the Network.

            -
            -
            Parameters
            -
              -
            • datatype (Union[BaseDataType, str]) – The DataType of the sink node

            • -
            • id (Optional[str]) – The id of the sink node to be created

            • -
            • step_id (Optional[str]) – The step to add the created sink node to

            • -
            • resources (Optional[ResourceLimit]) – The resources required to run this node

            • -
            • node_group (str) – The group the node belongs to, this can be -important for FlowNodes and such, as they -will have matching dimension names.

            • -
            -
            -
            Return type
            -

            Node

            -
            -
            Returns
            -

            the newly created sink node

            -
            -
            -
            - -
            -
            -create_source(datatype, id=None, step_id=None, resources=None, node_group=None)[source]¶
            -

            Create a SourceNode in this Network. The Node will be automatically added to -the Network.

            -
            -
            Parameters
            -
              -
            • datatype (BaseDataType) – The DataType of the source source_node

            • -
            • id (str) – The id of the source source_node to be created

            • -
            • step_id (str) – The step to add the created source source_node to

            • -
            • resources (Optional[ResourceLimit]) – The resources required to run this node

            • -
            • node_group (str) – The group the node belongs to, this can be -important for FlowNodes and such, as they -will have matching dimension names.

            • -
            -
            -
            Returns
            -

            the newly created source source_node

            -
            -
            Return type
            -

            SourceNode

            -
            -
            -
            - -
            -
            -draw(file_path=None, draw_dimensions=True, hide_unconnected=True, expand_macros=1, font_size=14)[source]¶
            -

            Draw a graphical representation of the Network

            -
            -
            Parameters
            -
              -
            • file_path (str) – The path of the file to create, the extension will control the image type

            • -
            • draw_dimensions (bool) – Flag to control if the dimension sizes should be drawn -in the figure, default is true

            • -
            • expand_macros (bool) – Flag to control if and how macro nodes should be expanded, -by default 1 level is expanded

            • -
            -
            -
            Return type
            -

            Optional[str]

            -
            -
            Returns
            -

            path of the image created or None if failed

            -
            -
            -
            - -
            -
            -execute(source_data, sink_data, tmpdir=None, timestamp=None, blocking=True, execution_plugin=None)[source]¶
            -

            Execute the network with the given source and sink data.

            -
            -
            Parameters
            -
              -
            • source_data (Dict[str, Union[List[Union[str, Tuple[str, …]]], Dict[str, Union[str, Tuple[str, …]]]]]) – Source data to use as an input

            • -
            • sink_data (Union[str, Dict[str, str]]) – Sink rules to use for determining the outputs

            • -
            • tmpdir (Optional[str]) – The scratch directory to use for this network run, if -an existing directory is given, fastr will try to resume -a network run (see continuing-network)

            • -
            • timestamp (Union[datetime, str, None]) – The timestamp of the network run (useful for retrying -or continuing previous runs)

            • -
            • blocking (bool) – Flag to indicate if the execution should be blocking -or launched in a background thread

            • -
            • execution_plugin (Optional[str]) – The execution plugin to use for this run

            • -
            -
            -
            Return type
            -

            NetworkRun

            -
            -
            Returns
            -

            The network run object for the started execution

            -
            -
            -
            - -
            -
            -id¶
            -

            The unique id describing this resource

            -
            -
            Return type
            -

            str

            -
            -
            -
            - -
            -
            -classmethod load(filename)[source]¶
            -

            Load Network froma file

            -
            -
            Parameters
            -

            filename (str) –

            -
            -
            Returns
            -

            loaded network

            -
            -
            Return type
            -

            Network

            -
            -
            -
            - -
            -
            -save(filename, indent=2)[source]¶
            -

            Save the Network to a JSON file

            -
            -
            Parameters
            -
              -
            • filename (str) – Path of the file to save to

            • -
            • indent (int) – Indentation to use (None for no indentation)

            • -
            -
            -
            -
            - -
            -
            -version¶
            -

            Version of the Network (so users can keep track of their version)

            -
            -
            Return type
            -

            Version

            -
            -
            -
            - -
            - -
            - -

            Representation of a link for editing the Network

            -
            -
            -collapse¶
            -

            The dimensions which the link will collapse into the cardinality

            -
            -
            Return type
            -

            Tuple[Union[int, str], …]

            -
            -
            -
            - -
            -
            -expand¶
            -

            Flag that indicates if the Link will expand the cardinality into a new -dimension.

            -
            -
            Return type
            -

            bool

            -
            -
            -
            - -
            -
            -id¶
            -

            The unique id describing this resource

            -
            -
            Return type
            -

            str

            -
            -
            -
            - -
            - -
            -
            -class fastr.api.Node(parent)[source]¶
            -

            Representation of Node for editing the Network

            -
            -
            -id¶
            -

            The unique id describing this resource

            -
            -
            Return type
            -

            str

            -
            -
            -
            - -
            -
            -input¶
            -

            In case there is only a single Inputs in a Node, this can be used as a short hand. -In that case it is basically the same as list(node.inputs.values()[0]).

            -
            -
            Return type
            -

            Input

            -
            -
            -
            - -
            -
            -inputs¶
            -

            Mapping object containing all Inputs of a Node

            -
            -
            Return type
            -

            InputMap

            -
            -
            -
            - -
            -
            -output¶
            -

            In case there is only a single Outputs in a Node, this can be used as a short hand. -In that case it is basically the same as list(node.outputs.values()[0]).

            -
            -
            Return type
            -

            Output

            -
            -
            -
            - -
            -
            -outputs¶
            -

            Mapping object containing all Outputs of a Node

            -
            -
            Return type
            -

            Subobjectmap[Output]

            -
            -
            -
            - -
            - -
            -
            -class fastr.api.Input(parent)[source]¶
            -

            Representation of an Input of a Node

            -
            -
            -__lshift__(other)[source]¶
            -

            This operator allows the easy creation of Links to this Input using the << operator. -Creating links can be done by:

            -
            # Generic form
            ->> link = input << output
            ->> link = input << ['some', 'data']  # Create a constant node
            -
            -# Examples
            ->> link1 = addint.inputs['left_hand'] << source1.input
            ->> link2 = addint.inputs['right_hand'] << [1, 2, 3]
            -
            -# Mutliple links
            ->> links = addints.inputs['left_hand'] << (source1.output, source2.output, source3.output)
            -
            -
            -

            The last example would return a tuple with three links.

            -
            -
            Parameters
            -

            other (Union[Output, BaseOutput, list, dict, tuple]) – the target to create the link from, this can be an Output, a tuple of Outputs, or a data -structure that can be used as the data for a ConstantNode

            -
            -
            Return type
            -

            Union[Link, Tuple[Link, …]]

            -
            -
            Returns
            -

            Newly created link(s)

            -
            -
            -
            - -
            -
            -__rrshift__(other)[source]¶
            -

            This operator allows to use the >> operator as alternative to using the << operator. -See the __lshift__ operator for details.

            -
            -
            Parameters
            -

            other (Union[Output, BaseOutput, list, dict, tuple]) – the target to create the link from

            -
            -
            Return type
            -

            Union[Link, Tuple[Link, …]]

            -
            -
            Returns
            -

            Newly created link(s)

            -
            -
            -
            - -
            -
            -append(value)[source]¶
            -

            Create a link from give resource to a new SubInput.

            -
            -
            Parameters
            -

            value (Union[Output, BaseOutput, list, dict, tuple]) – The source for the link to be created

            -
            -
            Return type
            -

            Link

            -
            -
            Returns
            -

            The newly created link

            -
            -
            -
            - -
            -
            -id¶
            -

            The unique id describing this resource

            -
            -
            Return type
            -

            str

            -
            -
            -
            - -
            -
            -input_group¶
            -

            The input group of this Input. This property can be read and changed. -Changing the input group of an Input will influence the data flow in -a Node (see advanced-flow-node for details).

            -
            -
            Return type
            -

            str

            -
            -
            -
            - -
            - -
            -
            -class fastr.api.Output(parent)[source]¶
            -

            Representation of an Output of a Node

            -
            -
            -__getitem__(item)[source]¶
            -

            Get a SubOuput of this Ouput. The SubOutput selects some data from the -parent Output based on an index or slice of the cardinalty.

            -
            -
            Parameters
            -

            key – the key of the requested item, can be an index or slice

            -
            -
            Return type
            -

            Output

            -
            -
            Returns
            -

            the requested SubOutput with a view of the data in this Output

            -
            -
            -
            - -
            -
            -id¶
            -

            The unique id describing this resource

            -
            -
            Return type
            -

            str

            -
            -
            -
            - -
            - -
            - - -
            - -
            -
            - - - - -
            - -
            -

            - © Copyright 2016 -- 2019, Biomedical Imaging Group Rotterdam, Departments of Medical Informatics and Radiology, Erasmus MC, Rotterdam, The Netherlands - -

            -
            - Built with Sphinx using a theme provided by Read the Docs. - -
            - -
            -
            - -
            - -
            - - - - - - - - - - - - \ No newline at end of file diff --git a/build/lib/WORC/doc/autogen/WORC.IOparser.rst b/build/lib/WORC/doc/autogen/WORC.IOparser.rst deleted file mode 100644 index a6744112..00000000 --- a/build/lib/WORC/doc/autogen/WORC.IOparser.rst +++ /dev/null @@ -1,48 +0,0 @@ -IOparser Package -================ - -:mod:`config_WORC` Module -------------------------- - -.. automodule:: WORC.IOparser.config_WORC - :members: - :undoc-members: - :show-inheritance: - :special-members: - -:mod:`config_io_classifier` Module ----------------------------------- - -.. automodule:: WORC.IOparser.config_io_classifier - :members: - :undoc-members: - :show-inheritance: - :special-members: - -:mod:`config_preprocessing` Module ----------------------------------- - -.. automodule:: WORC.IOparser.config_preprocessing - :members: - :undoc-members: - :show-inheritance: - :special-members: - -:mod:`config_segmentix` Module ------------------------------- - -.. automodule:: WORC.IOparser.config_segmentix - :members: - :undoc-members: - :show-inheritance: - :special-members: - -:mod:`file_io` Module ---------------------- - -.. automodule:: WORC.IOparser.file_io - :members: - :undoc-members: - :show-inheritance: - :special-members: - diff --git a/build/lib/WORC/doc/autogen/WORC.classification.rst b/build/lib/WORC/doc/autogen/WORC.classification.rst deleted file mode 100644 index 3e0ac848..00000000 --- a/build/lib/WORC/doc/autogen/WORC.classification.rst +++ /dev/null @@ -1,93 +0,0 @@ -classification Package -====================== - -:mod:`AdvancedSampler` Module ------------------------------ - -.. automodule:: WORC.classification.AdvancedSampler - :members: - :undoc-members: - :show-inheritance: - :special-members: - -:mod:`RankedSVM` Module ------------------------ - -.. automodule:: WORC.classification.RankedSVM - :members: - :undoc-members: - :show-inheritance: - :special-members: - -:mod:`SearchCV` Module ----------------------- - -.. automodule:: WORC.classification.SearchCV - :members: - :undoc-members: - :show-inheritance: - :special-members: - -:mod:`construct_classifier` Module ----------------------------------- - -.. automodule:: WORC.classification.construct_classifier - :members: - :undoc-members: - :show-inheritance: - :special-members: - -:mod:`crossval` Module ----------------------- - -.. automodule:: WORC.classification.crossval - :members: - :undoc-members: - :show-inheritance: - :special-members: - -:mod:`estimators` Module ------------------------- - -.. automodule:: WORC.classification.estimators - :members: - :undoc-members: - :show-inheritance: - :special-members: - -:mod:`fitandscore` Module -------------------------- - -.. automodule:: WORC.classification.fitandscore - :members: - :undoc-members: - :show-inheritance: - :special-members: - -:mod:`metrics` Module ---------------------- - -.. automodule:: WORC.classification.metrics - :members: - :undoc-members: - :show-inheritance: - :special-members: - -:mod:`parameter_optimization` Module ------------------------------------- - -.. automodule:: WORC.classification.parameter_optimization - :members: - :undoc-members: - :show-inheritance: - :special-members: - -:mod:`trainclassifier` Module ------------------------------ - -.. automodule:: WORC.classification.trainclassifier - :members: - :undoc-members: - :show-inheritance: - :special-members: - diff --git a/build/lib/WORC/doc/autogen/WORC.featureprocessing.rst b/build/lib/WORC/doc/autogen/WORC.featureprocessing.rst deleted file mode 100644 index 29ce3960..00000000 --- a/build/lib/WORC/doc/autogen/WORC.featureprocessing.rst +++ /dev/null @@ -1,75 +0,0 @@ -featureprocessing Package -========================= - -:mod:`featureprocessing` Package --------------------------------- - -.. automodule:: WORC.featureprocessing - :members: - :undoc-members: - :show-inheritance: - :special-members: - -:mod:`Imputer` Module ---------------------- - -.. automodule:: WORC.featureprocessing.Imputer - :members: - :undoc-members: - :show-inheritance: - :special-members: - -:mod:`Relief` Module --------------------- - -.. automodule:: WORC.featureprocessing.Relief - :members: - :undoc-members: - :show-inheritance: - :special-members: - -:mod:`SelectGroups` Module --------------------------- - -.. automodule:: WORC.featureprocessing.SelectGroups - :members: - :undoc-members: - :show-inheritance: - :special-members: - -:mod:`SelectIndividuals` Module -------------------------------- - -.. automodule:: WORC.featureprocessing.SelectIndividuals - :members: - :undoc-members: - :show-inheritance: - :special-members: - -:mod:`StatisticalTestFeatures` Module -------------------------------------- - -.. automodule:: WORC.featureprocessing.StatisticalTestFeatures - :members: - :undoc-members: - :show-inheritance: - :special-members: - -:mod:`StatisticalTestThreshold` Module --------------------------------------- - -.. automodule:: WORC.featureprocessing.StatisticalTestThreshold - :members: - :undoc-members: - :show-inheritance: - :special-members: - -:mod:`VarianceThreshold` Module -------------------------------- - -.. automodule:: WORC.featureprocessing.VarianceThreshold - :members: - :undoc-members: - :show-inheritance: - :special-members: - diff --git a/build/lib/WORC/doc/autogen/WORC.plotting.rst b/build/lib/WORC/doc/autogen/WORC.plotting.rst deleted file mode 100644 index 8cec5656..00000000 --- a/build/lib/WORC/doc/autogen/WORC.plotting.rst +++ /dev/null @@ -1,102 +0,0 @@ -plotting Package -================ - -:mod:`compute_CI` Module ------------------------- - -.. automodule:: WORC.plotting.compute_CI - :members: - :undoc-members: - :show-inheritance: - :special-members: - -:mod:`linstretch` Module ------------------------- - -.. automodule:: WORC.plotting.linstretch - :members: - :undoc-members: - :show-inheritance: - :special-members: - -:mod:`plot_ROC` Module ----------------------- - -.. automodule:: WORC.plotting.plot_ROC - :members: - :undoc-members: - :show-inheritance: - :special-members: - -:mod:`plot_SVM` Module ----------------------- - -.. automodule:: WORC.plotting.plot_SVM - :members: - :undoc-members: - :show-inheritance: - :special-members: - -:mod:`plot_SVR` Module ----------------------- - -.. automodule:: WORC.plotting.plot_SVR - :members: - :undoc-members: - :show-inheritance: - :special-members: - -:mod:`plot_barchart` Module ---------------------------- - -.. automodule:: WORC.plotting.plot_barchart - :members: - :undoc-members: - :show-inheritance: - :special-members: - -:mod:`plot_boxplot` Module --------------------------- - -.. automodule:: WORC.plotting.plot_boxplot - :members: - :undoc-members: - :show-inheritance: - :special-members: - -:mod:`plot_images` Module -------------------------- - -.. automodule:: WORC.plotting.plot_images - :members: - :undoc-members: - :show-inheritance: - :special-members: - -:mod:`plot_ranked_scores` Module --------------------------------- - -.. automodule:: WORC.plotting.plot_ranked_scores - :members: - :undoc-members: - :show-inheritance: - :special-members: - -:mod:`plotminmaxresponse` Module --------------------------------- - -.. automodule:: WORC.plotting.plotminmaxresponse - :members: - :undoc-members: - :show-inheritance: - :special-members: - -:mod:`scatterplot` Module -------------------------- - -.. automodule:: WORC.plotting.scatterplot - :members: - :undoc-members: - :show-inheritance: - :special-members: - diff --git a/build/lib/WORC/doc/autogen/WORC.processing.rst b/build/lib/WORC/doc/autogen/WORC.processing.rst deleted file mode 100644 index 3aa1f2c8..00000000 --- a/build/lib/WORC/doc/autogen/WORC.processing.rst +++ /dev/null @@ -1,39 +0,0 @@ -processing Package -================== - -:mod:`ExtractNLargestBlobsn` Module ------------------------------------ - -.. automodule:: WORC.processing.ExtractNLargestBlobsn - :members: - :undoc-members: - :show-inheritance: - :special-members: - -:mod:`RTStructReader` Module ----------------------------- - -.. automodule:: WORC.processing.RTStructReader - :members: - :undoc-members: - :show-inheritance: - :special-members: - -:mod:`classes` Module ---------------------- - -.. automodule:: WORC.processing.classes - :members: - :undoc-members: - :show-inheritance: - :special-members: - -:mod:`label_processing` Module ------------------------------- - -.. automodule:: WORC.processing.label_processing - :members: - :undoc-members: - :show-inheritance: - :special-members: - diff --git a/build/lib/WORC/doc/autogen/WORC.resources.fastr_tests.rst b/build/lib/WORC/doc/autogen/WORC.resources.fastr_tests.rst deleted file mode 100644 index 3832d1f8..00000000 --- a/build/lib/WORC/doc/autogen/WORC.resources.fastr_tests.rst +++ /dev/null @@ -1,30 +0,0 @@ -fastr_tests Package -=================== - -:mod:`CalcFeatures_test` Module -------------------------------- - -.. automodule:: WORC.resources.fastr_tests.CalcFeatures_test - :members: - :undoc-members: - :show-inheritance: - :special-members: - -:mod:`elastix_test` Module --------------------------- - -.. automodule:: WORC.resources.fastr_tests.elastix_test - :members: - :undoc-members: - :show-inheritance: - :special-members: - -:mod:`segmentix_test` Module ----------------------------- - -.. automodule:: WORC.resources.fastr_tests.segmentix_test - :members: - :undoc-members: - :show-inheritance: - :special-members: - diff --git a/build/lib/WORC/doc/autogen/WORC.rst b/build/lib/WORC/doc/autogen/WORC.rst deleted file mode 100644 index 7a6d477b..00000000 --- a/build/lib/WORC/doc/autogen/WORC.rst +++ /dev/null @@ -1,42 +0,0 @@ -WORC Package -============ - -:mod:`WORC` Package -------------------- - -.. automodule:: WORC.__init__ - :members: - :undoc-members: - :show-inheritance: - :special-members: - -:mod:`WORC` Module ------------------- - -.. automodule:: WORC.WORC - :members: - :undoc-members: - :show-inheritance: - :special-members: - -:mod:`addexceptions` Module ---------------------------- - -.. automodule:: WORC.addexceptions - :members: - :undoc-members: - :show-inheritance: - :special-members: - -Subpackages ------------ - -.. toctree:: - - WORC.IOparser - WORC.classification - WORC.featureprocessing - WORC.plotting - WORC.processing - WORC.tools - diff --git a/build/lib/WORC/doc/autogen/WORC.tools.rst b/build/lib/WORC/doc/autogen/WORC.tools.rst deleted file mode 100644 index 7649a737..00000000 --- a/build/lib/WORC/doc/autogen/WORC.tools.rst +++ /dev/null @@ -1,39 +0,0 @@ -tools Package -============= - -:mod:`Elastix` Module ---------------------- - -.. automodule:: WORC.tools.Elastix - :members: - :undoc-members: - :show-inheritance: - :special-members: - -:mod:`Evaluate` Module ----------------------- - -.. automodule:: WORC.tools.Evaluate - :members: - :undoc-members: - :show-inheritance: - :special-members: - -:mod:`Slicer` Module --------------------- - -.. automodule:: WORC.tools.Slicer - :members: - :undoc-members: - :show-inheritance: - :special-members: - -:mod:`Transformix` Module -------------------------- - -.. automodule:: WORC.tools.Transformix - :members: - :undoc-members: - :show-inheritance: - :special-members: - diff --git a/build/lib/WORC/doc/autogen/__placeholder__ b/build/lib/WORC/doc/autogen/__placeholder__ deleted file mode 100644 index e69de29b..00000000 diff --git a/build/lib/WORC/doc/conf.py b/build/lib/WORC/doc/conf.py deleted file mode 100644 index ef9be218..00000000 --- a/build/lib/WORC/doc/conf.py +++ /dev/null @@ -1,275 +0,0 @@ -# -*- coding: utf-8 -*- -# -# WORC documentation build configuration file, created by -# sphinx-quickstart on Fri Aug 12 17:01:23 2011. -# -# This file is execfile()d with the current directory set to its containing dir. -# -# Note that not all possible configuration values are present in this -# autogenerated file. -# -# All configuration values have a default; values that are commented out -# serve to show the default. - -from collections import namedtuple -import os -import sys - -# If extensions (or modules to document with autodoc) are in another directory, -# add these directories to sys.path here. If the directory is relative to the -# documentation root, use os.path.abspath to make it absolute, like shown here. -sys.path.insert(0, os.path.dirname(__file__)) - -# Read the docs hacks -on_rtd = os.environ.get('READTHEDOCS', None) == 'True' -if on_rtd: - print('[conf.py] On Read the Docs') - -from generate_modules import recurse_tree -from doc_clean import clean - -# -- General configuration ----------------------------------------------------- - -# If your documentation needs a minimal Sphinx version, state it here. -# needs_sphinx = '1.0' - -# Add any Sphinx extension module names here, as strings. They can be extensions -# coming with Sphinx (named 'sphinx.ext.*') or your custom ones. -extensions = [ - 'sphinx.ext.autodoc', - 'sphinx_autodoc_typehints', - 'sphinx.ext.todo', - 'sphinx.ext.coverage', - 'sphinx.ext.viewcode', - 'sphinx.ext.inheritance_diagram', - 'sphinx.ext.intersphinx', - 'sphinx.ext.graphviz', - 'sphinxcontrib.httpdomain', - 'sphinxarg.ext' -] - -# Intersphinx mapping to Pyhton documentation -intersphinx_mapping = {'python': ('https://docs.python.org/3.7', None)} - -# Graphviz output format to svg -graphviz_output_format = 'svg' - -# Add any paths that contain templates here, relative to this directory. -templates_path = ['_templates'] - -# The suffix of source filenames. -source_suffix = '.rst' - -# Numbering references -numfig = True - -# The encoding of source files. -# source_encoding = 'utf-8-sig' - -# The master toctree document. -# master_doc = 'modules' -master_doc = 'index' - -# General information about the project. -project = 'WORC' -copyright = '2016 -- 2019, Biomedical Imaging Group Rotterdam, Departments of ' \ - 'Medical Informatics and Radiology, Erasmus MC, Rotterdam, The Netherlands' - -# The version info for the project you're documenting, acts as replacement for -# |version| and |release|, also used in various other places throughout the -# built documents. -# - -with open(os.path.join(os.path.dirname(__file__), - '..', '..', - 'version')) as version_file: - release = version_file.read().strip() - -# The short X.Y version. -# version = '.'.join(release.split('.')[:2]) -version = release -print('[conf.py] Found version: {}'.format(version)) - -# The language for content autogenerated by Sphinx. Refer to documentation -# for a list of supported languages. -# language = None - -# There are two options for replacing |today|: either, you set today to some -# non-false value, then it is used: -# today = '' -# Else, today_fmt is used as the format for a strftime call. -# today_fmt = '%B %d, %Y' - -# List of patterns, relative to source directory, that match files and -# directories to ignore when looking for source files. -exclude_patterns = ['_build'] - -# The reST default role (used for this markup: `text`) to use for all documents. -# default_role = None - -# If true, '()' will be appended to :func: etc. cross-reference text. -# add_function_parentheses = True - -# If true, the current module name will be prepended to all description -# unit titles (such as .. function::). -# add_module_names = True - -# If true, sectionauthor and moduleauthor directives will be shown in the -# output. They are ignored by default. -# show_authors = False - -# The name of the Pygments (syntax highlighting) style to use. -pygments_style = 'sphinx' - -# A list of ignored prefixes for module index sorting. -# modindex_common_prefix = [] - - -# -- Options for HTML output --------------------------------------------------- - -# The theme to use for HTML and HTML Help pages. See the documentation for -# a list of builtin themes. -if not on_rtd: - import sphinx_rtd_theme - html_theme = 'sphinx_rtd_theme' - html_theme_path = [sphinx_rtd_theme.get_html_theme_path()] -else: - html_theme = 'default' - -# Theme options are theme-specific and customize the look and feel of a theme -# further. For a list of options available for each theme, see the -# documentation. -# html_theme_options = {} - -# Add any paths that contain custom themes here, relative to this directory. -# html_theme_path = [] - -# The name for this set of Sphinx documents. If None, it defaults to -# " v documentation". -# html_title = None - -# A shorter title for the navigation bar. Default is the same as html_title. -# html_short_title = None - -# The name of an image file (relative to this directory) to place at the top -# of the sidebar. -# html_logo = None - -# The name of an image file (within the static path) to use as favicon of the -# docs. This file should be a Windows icon file (.ico) being 16x16 or 32x32 -# pixels large. -# html_favicon = None - -# Add any paths that contain custom static files (such as style sheets) here, -# relative to this directory. They are copied after the builtin static files, -# so a file named "default.css" will overwrite the builtin "default.css". -html_static_path = ['_static'] - -# If not '', a 'Last updated on:' timestamp is inserted at every page bottom, -# using the given strftime format. -# html_last_updated_fmt = '%b %d, %Y' - -# If true, SmartyPants will be used to convert quotes and dashes to -# typographically correct entities. -# html_use_smartypants = True - -# Custom sidebar templates, maps document names to template names. -# html_sidebars = {} - -# Additional templates that should be rendered to pages, maps page names to -# template names. -# html_additional_pages = {} - -# If false, no module index is generated. -# html_domain_indices = True - -# If false, no index is generated. -# html_use_index = True - -# If true, the index is split into individual pages for each letter. -# html_split_index = False - -# If true, links to the reST sources are added to the pages. -# html_show_sourcelink = True - -# If true, "Created using Sphinx" is shown in the HTML footer. Default is True. -# html_show_sphinx = True - -# If true, "(C) Copyright ..." is shown in the HTML footer. Default is True. -# html_show_copyright = True - -# If true, an OpenSearch description file will be output, and all pages will -# contain a tag referring to it. The value of this option must be the -# base URL from which the finished HTML is served. -# html_use_opensearch = '' - -# This is the file name suffix for HTML files (e.g. ".xhtml"). -# html_file_suffix = None - -# Output file base name for HTML help builder. -htmlhelp_basename = 'WORCdoc' - - -# -- Options for LaTeX output -------------------------------------------------- - -# The paper size ('letter' or 'a4'). -latex_element = { - 'papersize': 'a4', -} - -# Grouping the document tree into LaTeX files. List of tuples -# (source start file, target name, title, author, documentclass [howtos/manual]). -latex_documents = [ - ('index', 'WORC.tex', 'WORC Documentation', - 'WORC contributors', 'manual'), -] - -# -- Options for manual page output -------------------------------------------- - -# One entry per manual page. List of tuples -# (source start file, name, description, authors, manual section). -man_pages = [ - ('index', 'WORC', 'WORC Documentation', - ['WORC contributors'], 1) -] - -# Some autogeneration of documentation (make autodoc index, generate plugin -# references etc. -if hasattr(sys, 'real_prefix'): - print('[conf.py] Inside virtual env: {}'.format(sys.prefix)) -else: - print('[conf.py] Not inside a virtual env!') - -try: - import WORC - print('[conf.py] Loaded WORC, will build reference of available plugins') -except ImportError: - print('[conf.py] Cannot load WORC, will not build reference of plugins!') - WORC = None - -print('[conf.py] Current directory: {}'.format(os.path.abspath(os.curdir))) - -print('[conf.py] Cleaning old files...') -clean() # call doc_clean via code - -print('[conf.py] python generate_modules.py ..' + os.path.sep + ' -d .' + os.path.sep + ' -s rst -f') - -# Call generate modules from code rather than via a subprocess -# Feed all options via opts namedtuple -options = {'destdir': './autogen/', - 'dryrun': False, - 'force': True, - 'maxdepth': 4, - 'notoc': False, - 'suffix': 'rst'} - -opts = namedtuple('opts', list(options.keys()))(*list(options.values())) -rootpath = '../' -excludes = [ - os.path.abspath(os.path.join(rootpath, 'doc')), - os.path.abspath(os.path.join(rootpath, 'examples')), -] -recurse_tree(rootpath, excludes, opts) - -print('[conf.py] Done...') -print('[conf.py] Found files in curdir: {}'.format(os.listdir('.'))) diff --git a/build/lib/WORC/doc/doc_clean.py b/build/lib/WORC/doc/doc_clean.py deleted file mode 100644 index 30440bd5..00000000 --- a/build/lib/WORC/doc/doc_clean.py +++ /dev/null @@ -1,40 +0,0 @@ -#!/usr/bin/env python - -# Copyright 2011-2014 Biomedical Imaging Group Rotterdam, Departments of -# Medical Informatics and Radiology, Erasmus MC, Rotterdam, The Netherlands -# -# 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 pathlib - - -def clean(): - """ - Clean the autogen and main directories of .rst and .txt files - """ - doc_path = pathlib.Path(__file__).parent - clean_dir(doc_path) - - autogen_path = doc_path / 'autogen' - clean_dir(autogen_path) - - -def clean_dir(directory): - for filepath in directory.iterdir(): - if filepath.suffix in ('.rst', '.txt'): - filepath.unlink() - print(f'removed {filepath}') - - -if __name__ == '__main__': - clean() diff --git a/build/lib/WORC/doc/doc_generate.py b/build/lib/WORC/doc/doc_generate.py deleted file mode 100644 index f2032157..00000000 --- a/build/lib/WORC/doc/doc_generate.py +++ /dev/null @@ -1,28 +0,0 @@ -#!/usr/bin/env python - -# Copyright 2011-2014 Biomedical Imaging Group Rotterdam, Departments of -# Medical Informatics and Radiology, Erasmus MC, Rotterdam, The Netherlands -# -# 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 -os.chdir(os.path.dirname(os.path.abspath(__file__))) - -os.system('python3 doc_clean.py') -print('python3 generate_modules.py ..' + os.path.sep + ' -d .' + os.path.sep + ' -s rst -f') -os.system('python3 generate_modules.py ..' + os.path.sep + ' -d .' + os.path.sep + ' -s rst -f') -os.system('python3 generate_config.py') -print('python3 generate_config.py') -print('make html') -os.system('make html') -#os.system('make latexpdf') diff --git a/build/lib/WORC/doc/generate_config.py b/build/lib/WORC/doc/generate_config.py deleted file mode 100644 index 396ee21c..00000000 --- a/build/lib/WORC/doc/generate_config.py +++ /dev/null @@ -1,433 +0,0 @@ -#!/usr/bin/env python -import os - -import WORC -from fastr.helpers.rest_generation import create_rest_table - - -def generate_config(): - field_key = [] - field_subkey = [] - field_default = [] - field_description = [] - field_option = [] - - a = WORC.WORC() - - config_defaults = a.defaultconfig() - config_options = generate_config_options() - config_descriptions = generate_config_descriptions() - - for key in config_defaults.keys(): - for num, subkey in enumerate(config_defaults[key].keys()): - print(f'[generate_config.py] Documenting field {key}: {subkey}') - if num == 0: - field_key.append(key) - else: - # After the first field of this key is generated, we do not append the key for better readability - field_key.append('') - - field_subkey.append(subkey) - field_default.append(config_defaults[key][subkey]) - - try: - field_description.append(config_descriptions[key][subkey]) - except KeyError: - print(f'[WARNING] No description for {key}: {subkey}') - field_description.append('') - - try: - field_option.append(config_options[key][subkey]) - except KeyError: - print(f'[WARNING] No options for {key}: {subkey}') - field_option.append(config_defaults[key][subkey]) - - data = [field_key, field_subkey, field_description, field_default, field_option] - headers = ['Key', 'Subkey', 'Description', 'Default', 'Options',] - - return create_rest_table(data, headers) - - -def generate_config_doc(): - print('[generate_config.py] Generating config reference...') - filename = os.path.join(os.path.dirname(__file__), 'autogen', 'WORC.config.rst') - - with open(filename, 'w') as fh_out: - fh_out.write(generate_config()) - - print(f'[generate_config.py] Config reference saved to {filename}') - - -def generate_config_options(): - config = dict() - - # General configuration of WORC - config['General'] = dict() - config['General']['cross_validation'] = 'True, False' - config['General']['Segmentix'] = 'True, False' - config['General']['FeatureCalculator'] = 'predict/CalcFeatures:1.0, pyradiomics/CF_pyradiomics:1.0, your own tool reference' - config['General']['Preprocessing'] = 'worc/PreProcess:1.0, your own tool reference' - config['General']['RegistrationNode'] = "'elastix4.8/Elastix:4.8', your own tool reference" - config['General']['TransformationNode'] = "'elastix4.8/Transformix:4.8', your own tool reference" - config['General']['Joblib_ncores'] = 'Integer > 0' - config['General']['Joblib_backend'] = 'multiprocessing, threading' - config['General']['tempsave'] = 'True, False' - - # Segmentix - config['Segmentix'] = dict() - config['Segmentix']['mask'] = 'subtract, multiply' - config['Segmentix']['segtype'] = 'None, Ring' - config['Segmentix']['segradius'] = 'Integer > 0' - config['Segmentix']['N_blobs'] = 'Integer > 0' - config['Segmentix']['fillholes'] = 'True, False' - - # Preprocessing - config['Normalize'] = dict() - config['Normalize']['ROI'] = 'True, False, Full' - config['Normalize']['Method'] = 'z_score, minmed' - - # PREDICT - Feature calculation - # Determine which features are calculated - config['ImageFeatures'] = dict() - config['ImageFeatures']['shape'] = 'True, False' - config['ImageFeatures']['histogram'] = 'True, False' - config['ImageFeatures']['orientation'] = 'True, False' - config['ImageFeatures']['texture_Gabor'] = 'True, False' - config['ImageFeatures']['texture_LBP'] = 'True, False' - config['ImageFeatures']['texture_GLCM'] = 'True, False' - config['ImageFeatures']['texture_GLCMMS'] = 'True, False' - config['ImageFeatures']['texture_GLRLM'] = 'True, False' - config['ImageFeatures']['texture_GLSZM'] = 'True, False' - config['ImageFeatures']['texture_NGTDM'] = 'True, False' - config['ImageFeatures']['coliage'] = 'True, False' - config['ImageFeatures']['vessel'] = 'True, False' - config['ImageFeatures']['log'] = 'True, False' - config['ImageFeatures']['phase'] = 'True, False' - - # Parameter settings for PREDICT feature calculation - # Defines what should be done with the images - config['ImageFeatures']['image_type'] = 'CT' - - # Define frequencies for gabor filter in pixels - config['ImageFeatures']['gabor_frequencies'] = 'Float(s)' - - # Gabor, GLCM angles in degrees and radians, respectively - config['ImageFeatures']['gabor_angles'] = 'Integer(s)' - config['ImageFeatures']['GLCM_angles'] = 'Float(s)' - - # GLCM discretization levels, distances in pixels - config['ImageFeatures']['GLCM_levels'] = 'Integer > 0' - config['ImageFeatures']['GLCM_distances'] = 'Integer(s) > 0' - - # LBP radius, number of points in pixels - config['ImageFeatures']['LBP_radius'] = 'Integer(s) > 0' - config['ImageFeatures']['LBP_npoints'] = 'Integer(s) > 0' - - # Phase features minimal wavelength and number of scales - config['ImageFeatures']['phase_minwavelength'] = 'Integer > 0' - config['ImageFeatures']['phase_nscale'] = 'Integer > 0' - - # Log features sigma of Gaussian in pixels - config['ImageFeatures']['log_sigma'] = 'Integer(s)' - - # Vessel features scale range, steps for the range - config['ImageFeatures']['vessel_scale_range'] = 'Two integers: min and max.' - config['ImageFeatures']['vessel_scale_step'] = 'Integer > 0' - - # Vessel features radius for erosion to determine boudnary - config['ImageFeatures']['vessel_radius'] = 'Integer > 0' - - # Feature selection - config['Featsel'] = dict() - config['Featsel']['Variance'] = 'Boolean(s)' - config['Featsel']['GroupwiseSearch'] = 'Boolean(s)' - config['Featsel']['SelectFromModel'] = 'Boolean(s)' - config['Featsel']['UsePCA'] = 'Boolean(s)' - config['Featsel']['PCAType'] = 'Inteteger(s), 95variance' - config['Featsel']['StatisticalTestUse'] = 'Boolean(s)' - config['Featsel']['StatisticalTestMetric'] = 'ttest, Welch, Wilcoxon, MannWhitneyU' - config['Featsel']['StatisticalTestThreshold'] = 'Two Integers: loc and scale' - config['Featsel']['ReliefUse'] = 'Boolean(s)' - config['Featsel']['ReliefNN'] = 'Two Integers: loc and scale' - config['Featsel']['ReliefSampleSize'] = 'Two Integers: loc and scale' - config['Featsel']['ReliefDistanceP'] = 'Two Integers: loc and scale' - config['Featsel']['ReliefNumFeatures'] = 'Two Integers: loc and scale' - - # Groupwie Featureselection options - config['SelectFeatGroup'] = dict() - config['SelectFeatGroup']['shape_features'] = 'Boolean(s)' - config['SelectFeatGroup']['histogram_features'] = 'Boolean(s)' - config['SelectFeatGroup']['orientation_features'] = 'Boolean(s)' - config['SelectFeatGroup']['texture_Gabor_features'] = 'Boolean(s)' - config['SelectFeatGroup']['texture_GLCM_features'] = 'Boolean(s)' - config['SelectFeatGroup']['texture_GLCMMS_features'] = 'Boolean(s)' - config['SelectFeatGroup']['texture_GLRLM_features'] = 'Boolean(s)' - config['SelectFeatGroup']['texture_GLSZM_features'] = 'Boolean(s)' - config['SelectFeatGroup']['texture_NGTDM_features'] = 'Boolean(s)' - config['SelectFeatGroup']['texture_LBP_features'] = 'Boolean(s)' - config['SelectFeatGroup']['patient_features'] = 'Boolean(s)' - config['SelectFeatGroup']['semantic_features'] = 'Boolean(s)' - config['SelectFeatGroup']['coliage_features'] = 'Boolean(s)' - config['SelectFeatGroup']['log_features'] = 'Boolean(s)' - config['SelectFeatGroup']['vessel_features'] = 'Boolean(s)' - config['SelectFeatGroup']['phase_features'] = 'Boolean(s)' - - # Feature imputation - config['Imputation'] = dict() - config['Imputation']['use'] = 'Boolean(s)' - config['Imputation']['strategy'] = 'mean, median, most_frequent, constant, knn' - config['Imputation']['n_neighbors'] = 'Two Integers: loc and scale' - - # Classification - config['Classification'] = dict() - config['Classification']['fastr'] = 'True, False' - config['Classification']['fastr_plugin'] = 'Any `fastr execution plugin `_ .' - config['Classification']['classifiers'] = 'SVM , SVR, SGD, SGDR, RF, LDA, QDA, ComplementND, GaussianNB, LR, RFR, Lasso, ElasticNet. All are estimators from `sklearn `_ ' - config['Classification']['max_iter'] = 'Integer' - config['Classification']['SVMKernel'] = 'poly, linear, rbf' - config['Classification']['SVMC'] = 'Two Integers: loc and scale' - config['Classification']['SVMdegree'] = 'Two Integers: loc and scale' - config['Classification']['SVMcoef0'] = 'Two Integers: loc and scale' - config['Classification']['SVMgamma'] = 'Two Integers: loc and scale' - config['Classification']['RFn_estimators'] = 'Two Integers: loc and scale' - config['Classification']['RFmin_samples_split'] = 'Two Integers: loc and scale' - config['Classification']['RFmax_depth'] = 'Two Integers: loc and scale' - config['Classification']['LRpenalty'] = 'none, l2, l1' - config['Classification']['LRC'] = 'Two Integers: loc and scale' - config['Classification']['LDA_solver'] = 'svd, lsqr, eigen' - config['Classification']['LDA_shrinkage'] = 'Two Integers: loc and scale' - config['Classification']['QDA_reg_param'] = 'Two Integers: loc and scale' - config['Classification']['ElasticNet_alpha'] = 'Two Integers: loc and scale' - config['Classification']['ElasticNet_l1_ratio'] = 'Two Integers: loc and scale' - config['Classification']['SGD_alpha'] = 'Two Integers: loc and scale' - config['Classification']['SGD_l1_ratio'] = 'Two Integers: loc and scale' - config['Classification']['SGD_loss'] = 'hinge, squared_hinge, modified_huber' - config['Classification']['SGD_penalty'] = 'none, l2, l1' - config['Classification']['CNB_alpha'] = 'Two Integers: loc and scale' - - # CrossValidation - config['CrossValidation'] = dict() - config['CrossValidation']['N_iterations'] = 'Integer' - config['CrossValidation']['test_size'] = 'Float' - - # Options for the object/patient labels that are used - config['Labels'] = dict() - config['Labels']['label_names'] = 'String(s)' - config['Labels']['modus'] = 'singlelabel, multilabel' - config['Labels']['url'] = 'Not Supported Yet' - config['Labels']['projectID'] = 'Not Supported Yet' - - # Hyperparameter optimization options - config['HyperOptimization'] = dict() - config['HyperOptimization']['scoring_method'] = 'Any `sklearn metric `_' - config['HyperOptimization']['test_size'] = 'Float' - config['HyperOptimization']['N_iterations'] = 'Integer' - config['HyperOptimization']['n_jobspercore'] = 'Integer' - - # Feature scaling options - config['FeatureScaling'] = dict() - config['FeatureScaling']['scale_features'] = 'Boolean(s)' - config['FeatureScaling']['scaling_method'] = 'z_score, minmax' - - # Sample processing options - config['SampleProcessing'] = dict() - config['SampleProcessing']['SMOTE'] = 'Boolean(s)' - config['SampleProcessing']['SMOTE_ratio'] = 'Two Integers: loc and scale' - config['SampleProcessing']['SMOTE_neighbors'] = 'Two Integers: loc and scale' - config['SampleProcessing']['Oversampling'] = 'Boolean(s)' - - # Ensemble options - config['Ensemble'] = dict() - config['Ensemble']['Use'] = 'Boolean or Integer' - - return config - - -def generate_config_descriptions(): - config = dict() - - # General configuration of WORC - config['General'] = dict() - config['General']['cross_validation'] = 'Determine whether a cross validation will be performed or not. Obsolete, will be removed.' - config['General']['Segmentix'] = 'Determine whether to use Segmentix tool for segmentation preprocessing.' - config['General']['FeatureCalculator'] = 'Specifies which feature calculation tool should be used.' - config['General']['Preprocessing'] = 'Specifies which tool will be used for image preprocessing.' - config['General']['RegistrationNode'] = "Specifies which tool will be used for image registration." - config['General']['TransformationNode'] = "Specifies which tool will be used for applying image transformations." - config['General']['Joblib_ncores'] = 'Number of cores to be used by joblib for multicore processing.' - config['General']['Joblib_backend'] = 'Type of backend to be used by joblib for multicore processing.' - config['General']['tempsave'] = 'Determines whether after every cross validation iteration the result will be saved, in addition to the result after all iterations. Especially useful for debugging.' - - # Segmentix - config['Segmentix'] = dict() - config['Segmentix']['mask'] = 'If a mask is supplied, should the mask be subtracted from the contour or multiplied.' - config['Segmentix']['segtype'] = 'If Ring, then a ring around the segmentation will be used as contour.' - config['Segmentix']['segradius'] = 'Define the radius of the ring used if segtype is Ring.' - config['Segmentix']['N_blobs'] = 'How many of the largest blobs are extracted from the segmentation. If None, no blob extraction is used.' - config['Segmentix']['fillholes'] = 'Determines whether hole filling will be used.' - - # Preprocessing - config['Normalize'] = dict() - config['Normalize']['ROI'] = 'If a mask is supplied and this is set to True, normalize image based on supplied ROI. Otherwise, the full image is used for normalization using the SimpleITK Normalize function. Lastly, setting this to False will result in no normalization being applied.' - config['Normalize']['Method'] = 'Method used for normalization if ROI is supplied. Currently, z-scoring or using the minimum and median of the ROI can be used.' - - # PREDICT - Feature calculation - # Determine which features are calculated - config['ImageFeatures'] = dict() - config['ImageFeatures']['shape'] = 'Determine whether orientation features are computed or not.' - config['ImageFeatures']['histogram'] = 'Determine whether histogram features are computed or not.' - config['ImageFeatures']['orientation'] = 'Determine whether orientation features are computed or not.' - config['ImageFeatures']['texture_Gabor'] = 'Determine whether Gabor texture features are computed or not.' - config['ImageFeatures']['texture_LBP'] ='Determine whether LBP texture features are computed or not.' - config['ImageFeatures']['texture_GLCM'] = 'Determine whether GLCM texture features are computed or not.' - config['ImageFeatures']['texture_GLCMMS'] = 'Determine whether GLCM Multislice texture features are computed or not.' - config['ImageFeatures']['texture_GLRLM'] = 'Determine whether GLRLM texture features are computed or not.' - config['ImageFeatures']['texture_GLSZM'] = 'Determine whether GLSZM texture features are computed or not.' - config['ImageFeatures']['texture_NGTDM'] = 'Determine whether NGTDM texture features are computed or not.' - config['ImageFeatures']['coliage'] = 'Determine whether coliage features are computed or not.' - config['ImageFeatures']['vessel'] = 'Determine whether vessel features are computed or not.' - config['ImageFeatures']['log'] = 'Determine whether LoG features are computed or not.' - config['ImageFeatures']['phase'] = 'Determine whether local phase features are computed or not.' - - # Parameter settings for PREDICT feature calculation - # Defines what should be done with the images - config['ImageFeatures']['image_type'] = 'Modality of images supplied. Determines how the image is loaded.' - - # Define frequencies for gabor filter in pixels - config['ImageFeatures']['gabor_frequencies'] = 'Frequencies of Gabor filters used: can be a single float or a list.' - - # Gabor, GLCM angles in degrees and radians, respectively - config['ImageFeatures']['gabor_angles'] = 'Angles of Gabor filters in degrees: can be a single integer or a list.' - config['ImageFeatures']['GLCM_angles'] = 'Angles used in GLCM computation in radians: can be a single float or a list.' - - # GLCM discretization levels, distances in pixels - config['ImageFeatures']['GLCM_levels'] = 'Number of grayscale levels used in discretization before GLCM computation.' - config['ImageFeatures']['GLCM_distances'] = 'Distance(s) used in GLCM computation in pixels: can be a single integer or a list.' - - # LBP radius, number of points in pixels - config['ImageFeatures']['LBP_radius'] = 'Radii used for LBP computation: can be a single integer or a list.' - config['ImageFeatures']['LBP_npoints'] = 'Number(s) of points used in LBP computation: can be a single integer or a list.' - - # Phase features minimal wavelength and number of scales - config['ImageFeatures']['phase_minwavelength'] = 'Minimal wavelength in pixels used for phase features.' - config['ImageFeatures']['phase_nscale'] = 'Number of scales used in phase feature computation.' - - # Log features sigma of Gaussian in pixels - config['ImageFeatures']['log_sigma'] = 'Standard deviation(s) in pixels used in log feature computation: can be a single integer or a list.' - - # Vessel features scale range, steps for the range - config['ImageFeatures']['vessel_scale_range'] = 'Scale in pixels used for Frangi vessel filter. Given as a minimum and a maximum.' - config['ImageFeatures']['vessel_scale_step'] = 'Step size used to go from minimum to maximum scale on Frangi vessel filter.' - - # Vessel features radius for erosion to determine boudnary - config['ImageFeatures']['vessel_radius'] = 'Radius to determine boundary of between inner part and edge in Frangi vessel filter.' - - # Feature selection - config['Featsel'] = dict() - config['Featsel']['Variance'] = 'If True, exclude features which have a variance < 0.01. Based on ` sklearn `_.' - config['Featsel']['GroupwiseSearch'] = 'Randomly select which feature groups to use. Parameters determined by the SelectFeatGroup config part, see below.' - config['Featsel']['SelectFromModel'] = 'Select features by first training a LASSO model. The alpha for the LASSO model is randomly generated. See also `sklearn `_.' - config['Featsel']['UsePCA'] = 'If True, Use Principle Component Analysis (PCA) to select features.' - config['Featsel']['PCAType'] = 'Method to select number of components using PCA: Either the number of components that explains 95% of the variance, or use a fixed number of components.95variance' - config['Featsel']['StatisticalTestUse'] = 'If True, use statistical test to select features.' - config['Featsel']['StatisticalTestMetric'] = 'Define the type of statistical test to be used.' - config['Featsel']['StatisticalTestThreshold'] = 'Specify a threshold for the p-value threshold used in the statistical test to select features. The first element defines the lower boundary, the other the upper boundary. Random sampling will occur between the boundaries.' - config['Featsel']['ReliefUse'] = 'If True, use Relief to select features.' - config['Featsel']['ReliefNN'] = 'Min and max of number of nearest neighbors search range in Relief.' - config['Featsel']['ReliefSampleSize'] = 'Min and max of sample size search range in Relief.' - config['Featsel']['ReliefDistanceP'] = 'Min and max of positive distance search range in Relief.' - config['Featsel']['ReliefNumFeatures'] = 'Min and max of number of features that is selected search range in Relief.' - - # Groupwie Featureselection options - config['SelectFeatGroup'] = dict() - config['SelectFeatGroup']['shape_features'] = 'If True, use shape features in model.' - config['SelectFeatGroup']['histogram_features'] = 'If True, use histogram features in model.' - config['SelectFeatGroup']['orientation_features'] = 'If True, use orientation features in model.' - config['SelectFeatGroup']['texture_Gabor_features'] = 'If True, use Gabor texture features in model.' - config['SelectFeatGroup']['texture_GLCM_features'] = 'If True, use GLCM texture features in model.' - config['SelectFeatGroup']['texture_GLCMMS_features'] = 'If True, use GLCM Multislice texture features in model.' - config['SelectFeatGroup']['texture_GLRLM_features'] = 'If True, use GLRLM texture features in model.' - config['SelectFeatGroup']['texture_GLSZM_features'] = 'If True, use GLSZM texture features in model.' - config['SelectFeatGroup']['texture_NGTDM_features'] = 'If True, use NGTDM texture features in model.' - config['SelectFeatGroup']['texture_LBP_features'] = 'If True, use LBP texture features in model.' - config['SelectFeatGroup']['patient_features'] = 'If True, use patient features in model.' - config['SelectFeatGroup']['semantic_features'] = 'If True, use semantic features in model.' - config['SelectFeatGroup']['coliage_features'] = 'If True, use coliage features in model.' - config['SelectFeatGroup']['log_features'] = 'If True, use log features in model.' - config['SelectFeatGroup']['vessel_features'] = 'If True, use vessel features in model.' - config['SelectFeatGroup']['phase_features'] = 'If True, use phase features in model.' - - # Feature imputation - config['Imputation'] = dict() - config['Imputation']['use'] = 'If True, use feature imputation methods to replace NaN values. If False, all NaN features will be set to zero.' - config['Imputation']['strategy'] = 'Method to be used for imputation.' - config['Imputation']['n_neighbors'] = 'When using k-Nearest Neighbors (kNN) for feature imputation, determines the number of neighbors used for imputation. Can be a single integer or a list.' - - # Classification - config['Classification'] = dict() - config['Classification']['fastr'] = 'Use fastr for the optimization gridsearch (recommended on clusters, default) or if set to False , joblib (recommended for PCs but not on Windows).' - config['Classification']['fastr_plugin'] = 'Name of execution plugin to be used. Default use the same as the self.fastr_plugin for the WORC object.' - config['Classification']['classifiers'] = "Select the estimator(s) to use. Most are implemented using `sklearn `_. For abbreviations, see above." - config['Classification']['max_iter'] = 'Maximum number of iterations to use in training an estimator. Only for specific estimators, see `sklearn `_.' - config['Classification']['SVMKernel'] = 'When using a SVM, specify the kernel type.' - config['Classification']['SVMC'] = 'Range of the SVM slack parameter. We sample on a uniform log scale: the parameters specify the range of the exponent (a, a + b).' - config['Classification']['SVMdegree'] = 'Range of the SVM polynomial degree when using a polynomial kernel. We sample on a uniform scale: the parameters specify the range (a, a + b). ' - config['Classification']['SVMcoef0'] = 'Range of SVM homogeneity parameter. We sample on a uniform scale: the parameters specify the range (a, a + b). ' - config['Classification']['SVMgamma'] = 'Range of the SVM gamma parameter. We sample on a uniform log scale: the parameters specify the range of the exponent (a, a + b)' - config['Classification']['RFn_estimators'] = 'Range of number of trees in a RF. We sample on a uniform scale: the parameters specify the range (a, a + b).' - config['Classification']['RFmin_samples_split'] = 'Range of minimum number of samples required to split a branch in a RF. We sample on a uniform scale: the parameters specify the range (a, a + b). ' - config['Classification']['RFmax_depth'] = 'Range of maximum depth of a RF. We sample on a uniform scale: the parameters specify the range (a, a + b). ' - config['Classification']['LRpenalty'] = 'Penalty term used in LR.' - config['Classification']['LRC'] = 'Range of regularization strength in LR. We sample on a uniform scale: the parameters specify the range (a, a + b). ' - config['Classification']['LDA_solver'] = 'Solver used in LDA.' - config['Classification']['LDA_shrinkage'] = 'Range of the LDA shrinkage parameter. We sample on a uniform log scale: the parameters specify the range of the exponent (a, a + b).' - config['Classification']['QDA_reg_param'] = 'Range of the QDA regularization parameter. We sample on a uniform log scale: the parameters specify the range of the exponent (a, a + b). ' - config['Classification']['ElasticNet_alpha'] = 'Range of the ElasticNet penalty parameter. We sample on a uniform log scale: the parameters specify the range of the exponent (a, a + b).' - config['Classification']['ElasticNet_l1_ratio'] = 'Range of l1 ratio in LR. We sample on a uniform scale: the parameters specify the range (a, a + b).' - config['Classification']['SGD_alpha'] = 'Range of the SGD penalty parameter. We sample on a uniform log scale: the parameters specify the range of the exponent (a, a + b).' - config['Classification']['SGD_l1_ratio'] = 'Range of l1 ratio in SGD. We sample on a uniform scale: the parameters specify the range (a, a + b).' - config['Classification']['SGD_loss'] = 'hinge, Loss function of SG' - config['Classification']['SGD_penalty'] = 'Penalty term in SGD.' - config['Classification']['CNB_alpha'] = 'Regularization strenght in ComplementNB. We sample on a uniform scale: the parameters specify the range (a, a + b)' - - # CrossValidation - config['CrossValidation'] = dict() - config['CrossValidation']['N_iterations'] = 'Number of times the data is split in training and test in the outer cross-validation.' - config['CrossValidation']['test_size'] = 'The percentage of data to be used for testing.' - - # Options for the object/patient labels that are used - config['Labels'] = dict() - config['Labels']['label_names'] = 'The labels used from your label file for classification.' - config['Labels']['modus'] = 'Determine whether multilabel or singlelabel classification or regression will be performed.' - config['Labels']['url'] = 'WIP' - config['Labels']['projectID'] = 'WIP' - - # Hyperparameter optimization options - config['HyperOptimization'] = dict() - config['HyperOptimization']['scoring_method'] = 'Specify the optimization metric for your hyperparameter search.' - config['HyperOptimization']['test_size'] = 'Size of test set in the hyperoptimization cross validation, given as a percentage of the whole dataset.' - config['HyperOptimization']['N_iterations'] = 'Number of iterations used in the hyperparameter optimization. This corresponds to the number of samples drawn from the parameter grid.' - config['HyperOptimization']['n_jobspercore'] = 'Number of jobs assigned to a single core. Only used if fastr is set to true in the classfication.' # only relevant when using fastr in classification - - # Feature scaling options - config['FeatureScaling'] = dict() - config['FeatureScaling']['scale_features'] = 'Determine whether to use feature scaling is.' - config['FeatureScaling']['scaling_method'] = 'Determine the scaling method.' - - # Sample processing options - config['SampleProcessing'] = dict() - config['SampleProcessing']['SMOTE'] = 'Determine whether to use SMOTE oversampling, see also ` imbalanced learn `_. ' - config['SampleProcessing']['SMOTE_ratio'] = 'Determine the ratio of oversampling. If 1, the minority class will be oversampled to the same size as the majority class. We sample on a uniform scale: the parameters specify the range (a, a + b). ' - config['SampleProcessing']['SMOTE_neighbors'] = 'Number of neighbors used in SMOTE. This should be much smaller than the number of objects/patients you supply. We sample on a uniform scale: the parameters specify the range (a, a + b).' - config['SampleProcessing']['Oversampling'] = 'Determine whether to random oversampling.' - - # Ensemble options - config['Ensemble'] = dict() - config['Ensemble']['Use'] = 'Determine whether to use ensembling or not. Either provide an integer to state how many estimators to include, or True, which will use the default ensembling method.' - - - return config - - -if __name__ == '__main__': - generate_config_doc() diff --git a/build/lib/WORC/doc/generate_modules.py b/build/lib/WORC/doc/generate_modules.py deleted file mode 100644 index 52d70be2..00000000 --- a/build/lib/WORC/doc/generate_modules.py +++ /dev/null @@ -1,306 +0,0 @@ -#!/usr/bin/env python -# -*- coding: utf-8 -*- -""" -sphinx-autopackage-script - -This script parses a directory tree looking for python modules and packages and -creates ReST files appropriately to create code documentation with Sphinx. -It also creates a modules index (named modules.). -""" - -# Copyright 2008 Société des arts technologiques (SAT), http://www.sat.qc.ca/ -# Copyright 2010 Thomas Waldmann -# All rights reserved. -# -# This program is free software: you can redistribute it and/or modify -# it under the terms of the GNU General Public License as published by -# the Free Software Foundation, either version 2 of the License, or -# (at your option) any later version. -# -# This program is distributed in the hope that it will be useful, -# but WITHOUT ANY WARRANTY; without even the implied warranty of -# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -# GNU General Public License for more details. -# -# You should have received a copy of the GNU General Public License -# along with this program. If not, see . - - -import os -import optparse -import re - - -# automodule options -OPTIONS = ['members', - 'undoc-members', - # 'inherited-members', # disabled because there's a bug in sphinx - 'show-inheritance', - 'special-members', - ] - -INIT = '__init__.py' - - -def makename(package, module): - """Join package and module with a dot.""" - # Both package and module can be None/empty. - if package: - name = package - if module: - name += '.' + module - else: - name = module - return name - - -def write_file(name, text, opts): - """Write the output file for module/package .""" - if opts.dryrun: - return - fname = os.path.join(opts.destdir, "%s.%s" % (name, opts.suffix)) - if not opts.force and os.path.isfile(fname): - print('File %s already exists, skipping.' % fname) - else: - print('Creating file %s.' % fname) - f = open(fname, 'w') - f.write(text) - f.close() - - -def read_file(name, opts): - """Read the input file for a template.""" - if opts.dryrun: - return - fname = os.path.abspath(os.path.join(opts.destdir, '..', "%s.template" % (name))) - fname2 = os.path.join(os.path.dirname(fname), 'doc', os.path.basename(fname)) - if os.path.isfile(fname): - f = open(fname, 'r') - data = f.read() - f.close() - return data - elif os.path.isfile(fname2): - # BUG in index.template - f = open(fname2, 'r') - data = f.read() - f.close() - return data - else: - raise IOError('File %s does not exists!' % fname) - - -def format_heading(level, text): - """Create a heading of [1, 2 or 3 supported].""" - underlining = ['=', '-', '~', ][level - 1] * len(text) - return '%s\n%s\n\n' % (text, underlining) - - -def format_directive(module, package=None): - """Create the automodule directive and add the options.""" - directive = '.. automodule:: %s\n' % makename(package, module) - for option in OPTIONS: - directive += ' :%s:\n' % option - return directive - - -def create_module_file(package, module, opts): - """Build the text of the file and write the file.""" - text = format_heading(1, '%s Module' % module) - text += format_heading(2, ':mod:`%s` Module' % module) - text += format_directive(module, package) - write_file(makename(package, module), text, opts) - - -def create_package_file(root, master_package, subroot, py_files, opts, subs): - """Build the text of the file and write the file.""" - package = os.path.split(root)[-1] - text = format_heading(1, '%s Package' % package) - # add each package's module - for py_file in py_files: - if shall_skip(os.path.join(root, py_file)): - continue - is_package = py_file == INIT - py_file = os.path.splitext(py_file)[0] - py_path = makename(subroot, py_file) - if is_package: - heading = ':mod:`%s` Package' % package - else: - heading = ':mod:`%s` Module' % py_file - text += format_heading(2, heading) - text += format_directive(is_package and subroot or py_path, master_package) - text += '\n' - - # build a list of directories that are packages (they contain an INIT file) - subs = [sub for sub in subs if os.path.isfile(os.path.join(root, sub, INIT))] - # if there are some package directories, add a TOC for theses subpackages - if subs: - text += format_heading(2, 'Subpackages') - text += '.. toctree::\n\n' - for sub in subs: - text += ' %s.%s\n' % (makename(master_package, subroot), sub) - text += '\n' - - write_file(makename(master_package, subroot), text, opts) - - -def create_modules_toc_file(master_package, modules, opts, name='index'): - """ - Create the module's index. - """ - - template = read_file(name, opts) - text = '' - - modules.sort() - prev_module = '' - for module in modules: - # look if the module is a subpackage and, if yes, ignore it - if module.startswith(prev_module + '.'): - continue - prev_module = module - text += ' autogen/%s\n' % module - - text = re.sub('\\$modules', text, template) - - # Add contributors - root_dir = os.path.abspath(__file__).rsplit(os.path.sep, 3)[0] - print('ROOT DIR: {}'.format(root_dir)) - with open(os.path.join(root_dir, 'CONTRIBUTORS'), 'r') as fin: - contributors = fin.read().splitlines() - contributors[-1] = 'and {}'.format(contributors[-1]) - text = re.sub('\\$contributors', ', '.join(contributors), text) - - write_file(os.path.join('..', name), text, opts) - - -def shall_skip(module): - """ - Check if we want to skip this module. - """ - # skip it, if there is nothing (or just \n or \r\n) in the file - return os.path.getsize(module) < 3 - - -def recurse_tree(path, excludes, opts): - """ - Look for every file in the directory tree and create the corresponding - ReST files. - """ - # use absolute path for root, as relative paths like '../../foo' cause - # 'if "/." in root ...' to filter out *all* modules otherwise - path = os.path.abspath(path) - # check if the base directory is a package and get is name - if INIT in os.listdir(path): - package_name = path.split(os.path.sep)[-1] - else: - package_name = None - - toc = [] - tree = os.walk(path, False) - for root, subs, files in tree: - # keep only the Python script files - py_files = sorted([f for f in files if os.path.splitext(f)[1] == '.py']) - if INIT in py_files: - py_files.remove(INIT) - py_files.insert(0, INIT) - # remove hidden ('.') and private ('_') directories - subs = sorted([sub for sub in subs if sub[0] not in ['.', '_']]) - # check if there are valid files to process - if "/." in root or "/_" in root \ - or not py_files \ - or is_excluded(root, excludes): - continue - if INIT in py_files: - # we are in package ... - if ( # ... with subpackage(s) - subs - or - # ... with some module(s) - len(py_files) > 1 - or - # ... with a not-to-be-skipped INIT file - not shall_skip(os.path.join(root, INIT)) - ): - subroot = root[len(path):].lstrip(os.path.sep).replace(os.path.sep, '.') - create_package_file(root, package_name, subroot, py_files, opts, subs) - toc.append(makename(package_name, subroot)) - elif root == path: - # if we are at the root level, we don't require it to be a package - for py_file in py_files: - if not shall_skip(os.path.join(path, py_file)): - module = os.path.splitext(py_file)[0] - create_module_file(package_name, module, opts) - toc.append(makename(package_name, module)) - - # create the module's index - if not opts.notoc: - print(package_name, toc, opts) - create_modules_toc_file(package_name, toc, opts) - - -def normalize_excludes(rootpath, excludes): - """ - Normalize the excluded directory list: - * must be either an absolute path or start with rootpath, - * otherwise it is joined with rootpath - * with trailing slash - """ - sep = os.path.sep - f_excludes = [] - for exclude in excludes: - if not os.path.isabs(exclude) and not exclude.startswith(rootpath): - exclude = os.path.join(rootpath, exclude) - if not exclude.endswith(sep): - exclude += sep - f_excludes.append(exclude) - return f_excludes - - -def is_excluded(root, excludes): - """ - Check if the directory is in the exclude list. - - Note: by having trailing slashes, we avoid common prefix issues, like - e.g. an exlude "foo" also accidentally excluding "foobar". - """ - sep = os.path.sep - if not root.endswith(sep): - root += sep - for exclude in excludes: - if root.startswith(exclude): - return True - return False - - -def main(): - """ - Parse and check the command line arguments. - """ - parser = optparse.OptionParser(usage="""usage: %prog [options] [exclude paths, ...] - -Note: By default this script will not overwrite already created files.""") - parser.add_option("-n", "--doc-header", action="store", dest="header", help="Documentation Header (default=WORC)", default="WORC") - parser.add_option("-d", "--dest-dir", action="store", dest="destdir", help="Output destination directory", default="") - parser.add_option("-s", "--suffix", action="store", dest="suffix", help="module suffix (default=txt)", default="txt") - parser.add_option("-m", "--maxdepth", action="store", dest="maxdepth", help="Maximum depth of submodules to show in the TOC (default=4)", type="int", default=4) - parser.add_option("-r", "--dry-run", action="store_true", dest="dryrun", help="Run the script without creating the files") - parser.add_option("-f", "--force", action="store_true", dest="force", help="Overwrite all the files") - parser.add_option("-t", "--no-toc", action="store_true", dest="notoc", help="Don't create the table of content file") - (opts, args) = parser.parse_args() - if not args: - parser.error("package path is required.") - else: - rootpath, excludes = args[0], args[1:] - if os.path.isdir(rootpath): - # check if the output destination is a valid directory - if opts.destdir and os.path.isdir(opts.destdir): - excludes = normalize_excludes(rootpath, excludes) - recurse_tree(rootpath, excludes, opts) - else: - print('%s is not a valid output destination directory.' % opts.destdir) - else: - print('%s is not a valid directory.' % rootpath) - - -if __name__ == '__main__': - main() diff --git a/build/lib/WORC/doc/index.rst b/build/lib/WORC/doc/index.rst deleted file mode 100644 index 155c3206..00000000 --- a/build/lib/WORC/doc/index.rst +++ /dev/null @@ -1,95 +0,0 @@ -***** -WORC -***** - -Workflow for Optimal Radiomics Classification ---------------------------------------------- - -WORC is an open-source python package for the easy execution of end-to-end -radiomics pipelines. - -We aim to establish a general radiomics platform supporting easy -integration of other tools. With our modular build and support of -different software languages (Python, MATLAB, R, executables etc.), we want -to facilitate and stimulate collaboration, standardisation and -comparison of different radiomics approaches. By combining this in a -single framework, we hope to find an universal radiomics strategy that -can address various problems. - -WORC is open-source (licensed under the Apache 2.0 license) and hosted on Github at `https://github.com/MStarmans91/WORC `_ - -For support, go to the issues on the Gibhub page: `https://github.com/MStarmans91/WORC/issues `_ - -To get yourself a copy, see the :ref:`installation-chapter` - -The official documentation can be found at `WORC.readthedocs.io `_ - -For Tutorials on WORC, both for beginner and advanced WORCflows, please - -see our Tutorial repository https://github.com/MStarmans91/WORCTutorial. - - -The article on WORC is currently in press. WORC has been presented in the following: - - `M. P. A. Starmans, S. R. van der Voort, M. Vos, F. Incekara, J. J. Visser, M. Smits, M. G. Thomeer, W. J. Niessen and S. Klein. "Fully automatic construction of optimal radiomics workflows." European Conference of Radiology (ECR) 2019. `_ - - `Martijn P. A. Starmans, Sebastian R. van der Voort, Razvan L. Miclea, Melissa Vos, Fatih Incekara, Milea J.M. Timbergen, Maarten M.J. Wijnenga, Guillaume A. Padmos, G.H.J. van Leenders, George Kapsas, Martin J. van den Bent, Arnaud J.P.E. Vincent, Dirk J. Grünhagen, Cornelis Verhoef, Stefan Sleijfer, Jacob J. Visser, Marion Smits, Maarten, G. Thomeer, Wiro J. Niessen, and Stefan Klein. "Harmonizing radiomics among applications through adaptive workflow optimization." European Society of Medical Imaging Informatics (EuSoMII) Annual Meeting 2019. `_ - -WORC has been used in the following studies: - - `M. P. A. Starmans, R. Miclea, S. R. van der Voort, W. J. Niessen, M. G. Thomeer and S. Klein. "Classification of malignant and benign liver tumors using a radiomics approach." Proceedings Volume 10574, Medical Imaging 2018: Image Processing; 105741D (2018) . `_ - - `Milea J.M. Timbergen*, Martijn P. A. Starmans*, Melissa Vos, Sebastian R. van der Voort, Guillaume A. Padmos, Wouter Kessels, Wiro J. Niessen, Geert J.L.H. van Leenders, Dirk J. Grünhagen, Stefan Sleijfer, Cornelis Verhoef, Stefan Klein and Jacob J. Visser. "Mutation stratification of desmoid-type fibromatosis using a Radiomics approach." Desmoid Tumor Research Foundation (DTRF) 2018. `_ - - `Melissa Vos*, Martijn P. A. Starmans*, Milea J.M. Timbergen, Sebastian R. van der Voort, Guillaume A. Padmos, Wouter Kessels, Wiro J. Niessen, Geert J.L.H. van Leenders, Dirk J. Grünhagen, Stefan Sleijfer, Cornelis Verhoef, Stefan Klein and Jacob J. Visser. "Differentiating well-differentiated liposarcomas from lipomas using a Radiomics approach." ConnectiveTissueOncologySociety (CTOS) 2018.`_ - - `Milea J.M. Timbergen*, Martijn P. A. Starmans*, Melissa Vos, Sebastian R. van der Voort, Guillaume A. Padmos, Wouter Kessels, Wiro J. Niessen, Geert J.L.H. van Leenders, Dirk J. Grünhagen, Stefan Sleijfer, Cornelis Verhoef, Stefan Klein and Jacob J. Visser. "Mutation stratification of desmoid-type fibromatosis using a Radiomics approach." ConnectiveTissueOncologySociety (CTOS) 2018.`_ - - `Martijn P. A. Starmans, Sebastian R. van der Voort, Razvan L. Miclea, Melissa Vos, Fatih Incekara, Milea J.M. Timbergen, Maarten M.J. Wijnenga, Guillaume A. Padmos, Wouter Kessels, G.H.J. van Leenders, George Kapsas, Martin J. van den Bent, Arnaud J.P.E. Vincent, Dirk J. Grünhagen, Cornelis Verhoef, Stefan Sleijfer, Jacob J. Visser, Marion Smits, Maarten, G. Thomeer, Wiro J. Niessen, and Stefan Klein. "Fully Automatic Construction of Optimal Radiomics Workflows ." Bio-Medical Engineering (BME) Conference 2019. `_ - - `M. P. A. Starmans, R. Miclea, S. R. van der Voort, W. J. Niessen, S. Klein and M. G. Thomeer. "Classification of malignant and benign liver tumours using a radiomics approach." European Conference of Radiology (ECR) 2019. `_ - - `M. P. A. Starmans, A. Blazevic, S. R. van der Voort, T. Brabander, J. Hofland, W. J. Niessen, W. W. de Herder and S. Klein. "Prediction of surgery requirement in mesenteric fibrosis on CT using a radiomics approach." European Conference of Radiology (ECR) 2019. `_ - - `Jose M. Castillo T., Martijn P. A. Starmans, Ivo Schoots, Wiro J. Niessen, Stefan Klein, Jifke F. Veenland. "CLASSIFICATION OF PROSTATE CANCER: HIGH GRADE VERSUS LOW GRADE USING A RADIOMICS APPROACH." IEEE International Symposium on Biomedical Imaging (ISBI) 2019. `_ - -WORC is made possible by contributions from the following people: Martijn Starmans, and Stefan Klein - - -WORC Documentation -=================== -.. toctree:: - :maxdepth: 3 - :glob: - - static/introduction.rst - static/quick_start.rst - static/user_manual.rst - static/configuration.rst - static/file_description.rst - static/changelog.rst - -WORC User reference -==================== - -.. toctree:: - :maxdepth: 3 - :glob: - - user_reference/* - -WORC Developer Module reference -================================ -.. toctree:: - :maxdepth: 4 - - autogen/WORC - - - -Indices and tables -================== - -* :ref:`genindex` -* :ref:`modindex` -* :ref:`search` diff --git a/build/lib/WORC/doc/index.template b/build/lib/WORC/doc/index.template deleted file mode 100644 index 58743161..00000000 --- a/build/lib/WORC/doc/index.template +++ /dev/null @@ -1,94 +0,0 @@ -***** -WORC -***** - -Workflow for Optimal Radiomics Classification ---------------------------------------------- - -WORC is an open-source python package for the easy execution of end-to-end -radiomics pipelines. - -We aim to establish a general radiomics platform supporting easy -integration of other tools. With our modular build and support of -different software languages (Python, MATLAB, R, executables etc.), we want -to facilitate and stimulate collaboration, standardisation and -comparison of different radiomics approaches. By combining this in a -single framework, we hope to find an universal radiomics strategy that -can address various problems. - -WORC is open-source (licensed under the Apache 2.0 license) and hosted on Github at `https://github.com/MStarmans91/WORC `_ - -For support, go to the issues on the Gibhub page: `https://github.com/MStarmans91/WORC/issues `_ - -To get yourself a copy, see the :ref:`installation-chapter` - -The official documentation can be found at `WORC.readthedocs.io `_ - -For Tutorials on WORC, both for beginner and advanced WORCflows, please - -see our Tutorial repository https://github.com/MStarmans91/WORCTutorial. - - -The article on WORC is currently in press. WORC has been presented in the following: - - `M. P. A. Starmans, S. R. van der Voort, M. Vos, F. Incekara, J. J. Visser, M. Smits, M. G. Thomeer, W. J. Niessen and S. Klein. "Fully automatic construction of optimal radiomics workflows." European Conference of Radiology (ECR) 2019. `_ - - `Martijn P. A. Starmans, Sebastian R. van der Voort, Razvan L. Miclea, Melissa Vos, Fatih Incekara, Milea J.M. Timbergen, Maarten M.J. Wijnenga, Guillaume A. Padmos, G.H.J. van Leenders, George Kapsas, Martin J. van den Bent, Arnaud J.P.E. Vincent, Dirk J. Grünhagen, Cornelis Verhoef, Stefan Sleijfer, Jacob J. Visser, Marion Smits, Maarten, G. Thomeer, Wiro J. Niessen, and Stefan Klein. "Harmonizing radiomics among applications through adaptive workflow optimization." European Society of Medical Imaging Informatics (EuSoMII) Annual Meeting 2019. `_ - -WORC has been used in the following studies: - - `M. P. A. Starmans, R. Miclea, S. R. van der Voort, W. J. Niessen, M. G. Thomeer and S. Klein. "Classification of malignant and benign liver tumors using a radiomics approach." Proceedings Volume 10574, Medical Imaging 2018: Image Processing; 105741D (2018) . `_ - - `Milea J.M. Timbergen*, Martijn P. A. Starmans*, Melissa Vos, Sebastian R. van der Voort, Guillaume A. Padmos, Wouter Kessels, Wiro J. Niessen, Geert J.L.H. van Leenders, Dirk J. Grünhagen, Stefan Sleijfer, Cornelis Verhoef, Stefan Klein and Jacob J. Visser. "Mutation stratification of desmoid-type fibromatosis using a Radiomics approach." Desmoid Tumor Research Foundation (DTRF) 2018. `_ - - `Melissa Vos*, Martijn P. A. Starmans*, Milea J.M. Timbergen, Sebastian R. van der Voort, Guillaume A. Padmos, Wouter Kessels, Wiro J. Niessen, Geert J.L.H. van Leenders, Dirk J. Grünhagen, Stefan Sleijfer, Cornelis Verhoef, Stefan Klein and Jacob J. Visser. "Differentiating well-differentiated liposarcomas from lipomas using a Radiomics approach." ConnectiveTissueOncologySociety (CTOS) 2018.`_ - - `Milea J.M. Timbergen*, Martijn P. A. Starmans*, Melissa Vos, Sebastian R. van der Voort, Guillaume A. Padmos, Wouter Kessels, Wiro J. Niessen, Geert J.L.H. van Leenders, Dirk J. Grünhagen, Stefan Sleijfer, Cornelis Verhoef, Stefan Klein and Jacob J. Visser. "Mutation stratification of desmoid-type fibromatosis using a Radiomics approach." ConnectiveTissueOncologySociety (CTOS) 2018.`_ - - `Martijn P. A. Starmans, Sebastian R. van der Voort, Razvan L. Miclea, Melissa Vos, Fatih Incekara, Milea J.M. Timbergen, Maarten M.J. Wijnenga, Guillaume A. Padmos, Wouter Kessels, G.H.J. van Leenders, George Kapsas, Martin J. van den Bent, Arnaud J.P.E. Vincent, Dirk J. Grünhagen, Cornelis Verhoef, Stefan Sleijfer, Jacob J. Visser, Marion Smits, Maarten, G. Thomeer, Wiro J. Niessen, and Stefan Klein. "Fully Automatic Construction of Optimal Radiomics Workflows ." Bio-Medical Engineering (BME) Conference 2019. `_ - - `M. P. A. Starmans, R. Miclea, S. R. van der Voort, W. J. Niessen, S. Klein and M. G. Thomeer. "Classification of malignant and benign liver tumours using a radiomics approach." European Conference of Radiology (ECR) 2019. `_ - - `M. P. A. Starmans, A. Blazevic, S. R. van der Voort, T. Brabander, J. Hofland, W. J. Niessen, W. W. de Herder and S. Klein. "Prediction of surgery requirement in mesenteric fibrosis on CT using a radiomics approach." European Conference of Radiology (ECR) 2019. `_ - - `Jose M. Castillo T., Martijn P. A. Starmans, Ivo Schoots, Wiro J. Niessen, Stefan Klein, Jifke F. Veenland. "CLASSIFICATION OF PROSTATE CANCER: HIGH GRADE VERSUS LOW GRADE USING A RADIOMICS APPROACH." IEEE International Symposium on Biomedical Imaging (ISBI) 2019. `_ - -WORC is made possible by contributions from the following people: $contributors - - -WORC Documentation -=================== -.. toctree:: - :maxdepth: 3 - :glob: - - static/introduction.rst - static/quick_start.rst - static/user_manual.rst - static/configuration.rst - static/file_description.rst - static/changelog.rst - -WORC User reference -==================== - -.. toctree:: - :maxdepth: 3 - :glob: - - user_reference/* - -WORC Developer Module reference -================================ -.. toctree:: - :maxdepth: 4 - -$modules - - -Indices and tables -================== - -* :ref:`genindex` -* :ref:`modindex` -* :ref:`search` diff --git a/build/lib/WORC/doc/make.bat b/build/lib/WORC/doc/make.bat deleted file mode 100644 index a78a0566..00000000 --- a/build/lib/WORC/doc/make.bat +++ /dev/null @@ -1,170 +0,0 @@ -@ECHO OFF - -REM Command file for Sphinx documentation - -if "%SPHINXBUILD%" == "" ( - set SPHINXBUILD=sphinx-build -) -set BUILDDIR=_build -set ALLSPHINXOPTS=-d %BUILDDIR%/doctrees %SPHINXOPTS% . -if NOT "%PAPER%" == "" ( - set ALLSPHINXOPTS=-D latex_paper_size=%PAPER% %ALLSPHINXOPTS% -) - -if "%1" == "" goto help - -if "%1" == "help" ( - :help - echo.Please use `make ^` where ^ is one of - echo. html to make standalone HTML files - echo. dirhtml to make HTML files named index.html in directories - echo. singlehtml to make a single large HTML file - echo. pickle to make pickle files - echo. json to make JSON files - echo. htmlhelp to make HTML files and a HTML help project - echo. qthelp to make HTML files and a qthelp project - echo. devhelp to make HTML files and a Devhelp project - echo. epub to make an epub - echo. latex to make LaTeX files, you can set PAPER=a4 or PAPER=letter - echo. text to make text files - echo. man to make manual pages - echo. changes to make an overview over all changed/added/deprecated items - echo. linkcheck to check all external links for integrity - echo. doctest to run all doctests embedded in the documentation if enabled - goto end -) - -if "%1" == "clean" ( - for /d %%i in (%BUILDDIR%\*) do rmdir /q /s %%i - del /q /s %BUILDDIR%\* - goto end -) - -if "%1" == "html" ( - %SPHINXBUILD% -b html %ALLSPHINXOPTS% %BUILDDIR%/html - if errorlevel 1 exit /b 1 - echo. - echo.Build finished. The HTML pages are in %BUILDDIR%/html. - goto end -) - -if "%1" == "dirhtml" ( - %SPHINXBUILD% -b dirhtml %ALLSPHINXOPTS% %BUILDDIR%/dirhtml - if errorlevel 1 exit /b 1 - echo. - echo.Build finished. The HTML pages are in %BUILDDIR%/dirhtml. - goto end -) - -if "%1" == "singlehtml" ( - %SPHINXBUILD% -b singlehtml %ALLSPHINXOPTS% %BUILDDIR%/singlehtml - if errorlevel 1 exit /b 1 - echo. - echo.Build finished. The HTML pages are in %BUILDDIR%/singlehtml. - goto end -) - -if "%1" == "pickle" ( - %SPHINXBUILD% -b pickle %ALLSPHINXOPTS% %BUILDDIR%/pickle - if errorlevel 1 exit /b 1 - echo. - echo.Build finished; now you can process the pickle files. - goto end -) - -if "%1" == "json" ( - %SPHINXBUILD% -b json %ALLSPHINXOPTS% %BUILDDIR%/json - if errorlevel 1 exit /b 1 - echo. - echo.Build finished; now you can process the JSON files. - goto end -) - -if "%1" == "htmlhelp" ( - %SPHINXBUILD% -b htmlhelp %ALLSPHINXOPTS% %BUILDDIR%/htmlhelp - if errorlevel 1 exit /b 1 - echo. - echo.Build finished; now you can run HTML Help Workshop with the ^ -.hhp project file in %BUILDDIR%/htmlhelp. - goto end -) - -if "%1" == "qthelp" ( - %SPHINXBUILD% -b qthelp %ALLSPHINXOPTS% %BUILDDIR%/qthelp - if errorlevel 1 exit /b 1 - echo. - echo.Build finished; now you can run "qcollectiongenerator" with the ^ -.qhcp project file in %BUILDDIR%/qthelp, like this: - echo.^> qcollectiongenerator %BUILDDIR%\qthelp\BIGR-FAST.qhcp - echo.To view the help file: - echo.^> assistant -collectionFile %BUILDDIR%\qthelp\BIGR-FAST.ghc - goto end -) - -if "%1" == "devhelp" ( - %SPHINXBUILD% -b devhelp %ALLSPHINXOPTS% %BUILDDIR%/devhelp - if errorlevel 1 exit /b 1 - echo. - echo.Build finished. - goto end -) - -if "%1" == "epub" ( - %SPHINXBUILD% -b epub %ALLSPHINXOPTS% %BUILDDIR%/epub - if errorlevel 1 exit /b 1 - echo. - echo.Build finished. The epub file is in %BUILDDIR%/epub. - goto end -) - -if "%1" == "latex" ( - %SPHINXBUILD% -b latex %ALLSPHINXOPTS% %BUILDDIR%/latex - if errorlevel 1 exit /b 1 - echo. - echo.Build finished; the LaTeX files are in %BUILDDIR%/latex. - goto end -) - -if "%1" == "text" ( - %SPHINXBUILD% -b text %ALLSPHINXOPTS% %BUILDDIR%/text - if errorlevel 1 exit /b 1 - echo. - echo.Build finished. The text files are in %BUILDDIR%/text. - goto end -) - -if "%1" == "man" ( - %SPHINXBUILD% -b man %ALLSPHINXOPTS% %BUILDDIR%/man - if errorlevel 1 exit /b 1 - echo. - echo.Build finished. The manual pages are in %BUILDDIR%/man. - goto end -) - -if "%1" == "changes" ( - %SPHINXBUILD% -b changes %ALLSPHINXOPTS% %BUILDDIR%/changes - if errorlevel 1 exit /b 1 - echo. - echo.The overview file is in %BUILDDIR%/changes. - goto end -) - -if "%1" == "linkcheck" ( - %SPHINXBUILD% -b linkcheck %ALLSPHINXOPTS% %BUILDDIR%/linkcheck - if errorlevel 1 exit /b 1 - echo. - echo.Link check complete; look for any errors in the above output ^ -or in %BUILDDIR%/linkcheck/output.txt. - goto end -) - -if "%1" == "doctest" ( - %SPHINXBUILD% -b doctest %ALLSPHINXOPTS% %BUILDDIR%/doctest - if errorlevel 1 exit /b 1 - echo. - echo.Testing of doctests in the sources finished, look at the ^ -results in %BUILDDIR%/doctest/output.txt. - goto end -) - -:end diff --git a/build/lib/WORC/doc/static/changelog.rst b/build/lib/WORC/doc/static/changelog.rst deleted file mode 100644 index c0fa1d43..00000000 --- a/build/lib/WORC/doc/static/changelog.rst +++ /dev/null @@ -1 +0,0 @@ -.. include:: ../../../CHANGELOG diff --git a/build/lib/WORC/doc/static/configuration.rst b/build/lib/WORC/doc/static/configuration.rst deleted file mode 100644 index a46085ab..00000000 --- a/build/lib/WORC/doc/static/configuration.rst +++ /dev/null @@ -1,216 +0,0 @@ -.. _config-chapter: - -Configuration -============= - - -As ``WORC`` and the default tools used are mostly Python based, we've chosen -to put our configuration in a ``configparser`` object. This has several -advantages: - -1. The object can be treated as a python dictionary and thus is easily adjusted. -2. Second, each tool can be set to parse only specific parts of the configuration, - enabling us to supply one file to all tools instead of needing many parameter files. - -The default configuration is generated through the -:py:meth:`WORC.defaultconfig() ` -function. You can then change things as you would in a dictionary and -then append it to the configs source: - - -.. code-block:: python - - >>> network = WORC.WORC('somename') - >>> config = network.defaultconfig() - >>> config['Classification']['classifier'] = 'RF' - >>> network.configs.append(config) - -When executing the :py:meth:`WORC.set() ` command, the config objects are saved as -.ini files in the ``WORC.fastr_tempdir`` folder and added to the -:py:meth:`WORC.fastrconfigs() ` source. - -Below are some details on several of the fields in the configuration. -Note that for many of the fields, we currently only provide one default -value. However, when adding your own tools, these fields can be adjusted -to your specific settings. - -WORC performs Combined Algorithm Selection and Hyperparameter (CASH) -optimization. The configuration determines how the optimization is -performed and which hyperparameters and models will be included. -Repeating specific models/parameters in the config will make them more -likely to be used, e.g. - -.. code-block:: python - - >>> config['Classification']['classifiers'] = 'SVM, SVM, LR' - -means that the SVM is 2x more likely to be tested in the model selection than LR. - -.. note:: - - All fields in the config must either be supplied as strings. A - list can be created by using commas for separation, e.g. - :py:meth:`Network.create_source <'value1, value2, ... ')>`. - - -General -------- - - -PREDICTGeneral --------------- - -These fields contain general settings for when using PREDICT. -For more info on the Joblib settings, which are used in the Joblib -Parallel function, see `here `__. When you run -WORC on a cluster with nodes supporting only a single core to be used -per node, e.g. the BIGR cluster, use only 1 core and threading as a -backend. - - - -Segmentix ---------- -These fields are only important if you specified using the segmentix -tool in the general configuration. - - -Preprocessing -------------- -The preprocessing node acts before the feature extraction on the image. -Currently, only normalization is included: hence the dictionary name is -*Normalize*. Additionally, scans with image type CT (see later in the -tutorial) provided as DICOM are scaled to Hounsfield Units. - - -Imagefeatures -------------- - -If using the PREDICT toolbox, you can specify some settings for the -feature computation here. Also, you can select if the certain features -are computed or not. - - -Featsel -------- - -When using the PREDICT toolbox for classification, these settings can be -used for feature selection methods. Note that these settings are -actually used in the hyperparameter optimization. Hence you can provide -multiple values per field, of which random samples will be drawn of -which finally the best setting in combination with the other -hyperparameters is selected. Again, these should be formatted as string -containing the actual values, e.g. value1, value2. - - -SelectFeatGroup ---------------- -If the PREDICT feature computation and classification tools are used, -then you can do a gridsearch among the various feature groups for the -optimal combination. If you do not want this, set all fields to a single -value. - -Previously, there was a single parameter for the texture features, -selecting all, none or a single group. This is still supported, but not -recommended, and looks as follows: - -Imputation ----------------- -When using the PREDICT toolbox for classification, these settings are -used for feature imputation.Note that these settings are actually used -in the hyperparameter optimization. Hence you can provide multiple -values per field, of which random samples will be drawn of which finally -the best setting in combination with the other hyperparameters is -selected. - - -Classification --------------- -When using the PREDICT toolbox for classification, you can specify the -following settings. Almost all of these are used in CASH. Most of the -classifiers are implemented using sklearn; hence descriptions of the -hyperparameters can also be found there. - - -CrossValidation ---------------- -When using the PREDICT toolbox for classification and you specified -using cross validation, specify the following settings. - -Labels --------- -When using the PREDICT toolbox for classification, you have to set the -label used for classification. - - -This part is really important, as it should match your label file. -Suppose your patientclass.txt file you supplied as source for labels -looks like this: - - -+----------+--------+--------+ -| Patient | Label1 | Label2 | -+==========+========+========+ -| patient1 | 1 | 0 | -+----------+--------+--------+ -| patient2 | 2 | 1 | -+----------+--------+--------+ -| patient3 | 1 | 5 | -+----------+--------+--------+ - -You can supply a single label or multiple labels split by commas, for -each of which an estimator will be fit. For example, suppose you simply -want to use Label1 for classification, then set: - - - -.. code-block:: python - - config['Labels']['label_names'] = 'Label1' - - -If you want to first train a classifier on Label1 and then Label2, -set: ``config[Genetics][label_names] = Label1, Label2`` - - - - -Hyperoptimization ------------------ -When using the PREDICT toolbox for classification, you have to supply -your hyperparameter optimization procedure here. - - -FeatureScaling --------------- -Determines which method is applied to scale each feature. - - - -SampleProcessing ----------------- -Before performing the hyperoptimization, you can use SMOTE: Synthetic -Minority Over-sampling Technique to oversample your data. - - - - - -Ensemble --------- -WORC supports ensembling of workflows. This is not a default approach in -radiomics, hence the default is to not use it and select only the best -performing workflow. - - - - -FASTR_bugs ----------- -Currently, when using XNAT as a source, FASTR can only retrieve DICOM -directories. We made a workaround for this for the images and -segmentations, but this only works if all your files have the same name -and extension. These are provided in this configuration part. - - -.. include:: ../autogen/WORC.config.rst \ No newline at end of file diff --git a/build/lib/WORC/doc/static/file_description.rst b/build/lib/WORC/doc/static/file_description.rst deleted file mode 100644 index 79e6216d..00000000 --- a/build/lib/WORC/doc/static/file_description.rst +++ /dev/null @@ -1,6 +0,0 @@ -Resource File Formats -===================== - -This chapter describes the various files WORC uses. The function and format -of the files is described allowing the user to configure WORC and add -DataTypes and Tools. diff --git a/build/lib/WORC/doc/static/images/CASH.pdf b/build/lib/WORC/doc/static/images/CASH.pdf deleted file mode 100644 index 342f0340..00000000 Binary files a/build/lib/WORC/doc/static/images/CASH.pdf and /dev/null differ diff --git a/build/lib/WORC/doc/static/images/CASH.png b/build/lib/WORC/doc/static/images/CASH.png deleted file mode 100644 index 064f3e63..00000000 Binary files a/build/lib/WORC/doc/static/images/CASH.png and /dev/null differ diff --git a/build/lib/WORC/doc/static/images/RadiomicsSteps.pdf b/build/lib/WORC/doc/static/images/RadiomicsSteps.pdf deleted file mode 100644 index 7ec8478a..00000000 Binary files a/build/lib/WORC/doc/static/images/RadiomicsSteps.pdf and /dev/null differ diff --git a/build/lib/WORC/doc/static/images/RadiomicsSteps.png b/build/lib/WORC/doc/static/images/RadiomicsSteps.png deleted file mode 100644 index 2c3fbe25..00000000 Binary files a/build/lib/WORC/doc/static/images/RadiomicsSteps.png and /dev/null differ diff --git a/build/lib/WORC/doc/static/images/WORC_small.png b/build/lib/WORC/doc/static/images/WORC_small.png deleted file mode 100644 index 5a2623f5..00000000 Binary files a/build/lib/WORC/doc/static/images/WORC_small.png and /dev/null differ diff --git a/build/lib/WORC/doc/static/images/datatype_diagram.pdf b/build/lib/WORC/doc/static/images/datatype_diagram.pdf deleted file mode 100644 index 2df40854..00000000 Binary files a/build/lib/WORC/doc/static/images/datatype_diagram.pdf and /dev/null differ diff --git a/build/lib/WORC/doc/static/images/datatype_diagram.svg b/build/lib/WORC/doc/static/images/datatype_diagram.svg deleted file mode 100644 index 6624b7cf..00000000 --- a/build/lib/WORC/doc/static/images/datatype_diagram.svg +++ /dev/null @@ -1,1667 +0,0 @@ - - - - - - image/svg+xml - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - fastr.core.serializable.Serializable - - - fastr.core.serializable.Serializable - - - - - - - - - - - - - - - - - - - - - - fastr.plugins.managers.datatypemanager.ValueType - - - fastr.plugins.managers.datatypemanager.ValueType - - - - - - - - - - - - - - - - - - - - - - fastr.plugins.managers.datatypemanager.URLType - - - fastr.plugins.managers.datatypemanager.URLType - - - - - - - - - - - - - - - - - - - - - - fastr.plugins.managers.datatypemanager.TypeGroup - - - fastr.plugins.managers.datatypemanager.TypeGroup - - - - - - - - - - - - - - - - - - - - - - fastr.plugins.managers.datatypemanager.DataType - - - fastr.plugins.managers.datatypemanager.DataType - - - - - - - - - - - - - - - - - - - - - - fastr.plugins.managers.datatypemanager.BaseDataType - - - fastr.plugins.managers.datatypemanager.BaseDataType - - - - - - - - - - - - - - - - - - - - - - fastr.plugins.managers.datatypemanager.EnumType - - - fastr.plugins.managers.datatypemanager.EnumType - - - - - - - - - - - - - - - - - - diff --git a/build/lib/WORC/doc/static/images/fastr_core.png b/build/lib/WORC/doc/static/images/fastr_core.png deleted file mode 100644 index ee2c8ad7..00000000 Binary files a/build/lib/WORC/doc/static/images/fastr_core.png and /dev/null differ diff --git a/build/lib/WORC/doc/static/images/flow/flow_broadcast.pdf b/build/lib/WORC/doc/static/images/flow/flow_broadcast.pdf deleted file mode 100644 index 4aef6a54..00000000 Binary files a/build/lib/WORC/doc/static/images/flow/flow_broadcast.pdf and /dev/null differ diff --git a/build/lib/WORC/doc/static/images/flow/flow_broadcast.svg b/build/lib/WORC/doc/static/images/flow/flow_broadcast.svg deleted file mode 100644 index 29120978..00000000 --- a/build/lib/WORC/doc/static/images/flow/flow_broadcast.svg +++ /dev/null @@ -1,1338 +0,0 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - image/svg+xml - - - - - - - - - - - (im0) - - - - (im1) - - - - (im2) - - - - (im3) - - - dim_moving - - - dim_fixed - dim_moving - - - - - (tf0,m0,p0) - - - - (tf1,m0,p0) - - - - (tf2,m0,p0) - - - - - - (tf0,m1,p0) - - - - (tf1,m1,p0) - - - - (tf2,m1,p0) - - - - - - (tf0,m2,p0) - - - - (tf1,m2,p0) - - - - (tf2,m2,p0) - - - - - - (tf0,m3,p0) - - - - (tf1,m3,p0) - - - - (tf2,m3,p0) - - - - - - dim_fixed - dim_moving - - - - - (if0,m0,p0) - - - - (if1,m0,p0) - - - - (if2,m0,p0) - - - - - - (if0,m1,p0) - - - - (if1,m1,p0) - - - - (if2,m1,p0) - - - - - - (if0,m2,p0) - - - - (if1,m2,p0) - - - - (if2,m2,p0) - - - - - - (if0,m3,p0) - - - - (if1,m3,p0) - - - - (if2,m3,p0) - - - - - - - (p0) - - - - - - - - - - - (m0) - - - - (m1) - - - - (m2) - - - - (m3) - - - dim_moving - - - - - - (f0) - - - - (f1) - - - - (f2) - - - dim_fixed - - - NodeRun: elastix - - NodeRun: transformix - - diff --git a/build/lib/WORC/doc/static/images/flow/flow_collapse.pdf b/build/lib/WORC/doc/static/images/flow/flow_collapse.pdf deleted file mode 100644 index 462ca9f1..00000000 Binary files a/build/lib/WORC/doc/static/images/flow/flow_collapse.pdf and /dev/null differ diff --git a/build/lib/WORC/doc/static/images/flow/flow_collapse.svg b/build/lib/WORC/doc/static/images/flow/flow_collapse.svg deleted file mode 100644 index 265b7f2f..00000000 --- a/build/lib/WORC/doc/static/images/flow/flow_collapse.svg +++ /dev/null @@ -1,363 +0,0 @@ - - - - - - - - - - - - - - - - image/svg+xml - - - - - - - - - - (a0) - - - - (b0) - - - - (c0) - - - - - - - - (b1) - - - - (c1) - - dim1 - dim2 - - - - - (a0 ,b0, c0) - - - - (b1, c1) - - dim2 - - - - collapse(dim1) - - - diff --git a/build/lib/WORC/doc/static/images/flow/flow_cross_three_sample.pdf b/build/lib/WORC/doc/static/images/flow/flow_cross_three_sample.pdf deleted file mode 100644 index 516ad4ed..00000000 Binary files a/build/lib/WORC/doc/static/images/flow/flow_cross_three_sample.pdf and /dev/null differ diff --git a/build/lib/WORC/doc/static/images/flow/flow_cross_three_sample.svg b/build/lib/WORC/doc/static/images/flow/flow_cross_three_sample.svg deleted file mode 100644 index 512b05cb..00000000 --- a/build/lib/WORC/doc/static/images/flow/flow_cross_three_sample.svg +++ /dev/null @@ -1,700 +0,0 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - image/svg+xml - - - - - - - - - (p0) - - - - results in - - - - - (f0) - - - - (f1) - - - - (f2) - - - - - (m0) - - - - (m1) - - - - (m2) - - - - - - - - - (m3) - - - - - (tf0,m0,p0) - - - - (tf1,m0,p0) - - - - (tf2,m0,p0) - - - - - - (tf0,m1,p0) - - - - (tf1,m1,p0) - - - - (tf2,m1,p0) - - - - - - (tf0,m2,p0) - - - - (tf1,m2,p0) - - - - (tf2,m2,p0) - - - - - - (tf0,m3,p0) - - - - (tf1,m3,p0) - - - - (tf2,m3,p0) - - - - diff --git a/build/lib/WORC/doc/static/images/flow/flow_cross_three_sample_two_cardinality.pdf b/build/lib/WORC/doc/static/images/flow/flow_cross_three_sample_two_cardinality.pdf deleted file mode 100644 index 3b2fdc37..00000000 Binary files a/build/lib/WORC/doc/static/images/flow/flow_cross_three_sample_two_cardinality.pdf and /dev/null differ diff --git a/build/lib/WORC/doc/static/images/flow/flow_cross_three_sample_two_cardinality.svg b/build/lib/WORC/doc/static/images/flow/flow_cross_three_sample_two_cardinality.svg deleted file mode 100644 index bbab5c9f..00000000 --- a/build/lib/WORC/doc/static/images/flow/flow_cross_three_sample_two_cardinality.svg +++ /dev/null @@ -1,726 +0,0 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - image/svg+xml - - - - - - - - - (p0, p1) - - - - results in - - - - - (f0) - - - - (f1) - - - - (f2) - - - - - (m0) - - - - (m1) - - - - (m2) - - - - - - - - - (m3) - - - - - (tf0,m0,p0, tf0,m0,p1) - - - - (tf1,m0,p0, tf1,m0,p1) - - - - (tf2,m0,p0, tf2,m0,p1) - - - - - - (tf0,m1,p0, tf0,m1,p1) - - - - (tf1,m1,p0, tf1,m1,p1) - - - - (tf2,m1,p0, tf2,m1,p1) - - - - - - (tf0,m2,p0, tf0,m2,p1) - - - - (tf1,m2,p0, tf1,m2,p1) - - - - (tf2,m2,p0, tf2,m2,p1) - - - - - - (tf0,m3,p0, tf0,m3,p1) - - - - (tf1,m3,p0, tf1,m3,p1) - - - - (tf2,m3,p0, tf2,m3,p1) - - - - diff --git a/build/lib/WORC/doc/static/images/flow/flow_expand.pdf b/build/lib/WORC/doc/static/images/flow/flow_expand.pdf deleted file mode 100644 index f15e9647..00000000 Binary files a/build/lib/WORC/doc/static/images/flow/flow_expand.pdf and /dev/null differ diff --git a/build/lib/WORC/doc/static/images/flow/flow_expand.svg b/build/lib/WORC/doc/static/images/flow/flow_expand.svg deleted file mode 100644 index 661deff5..00000000 --- a/build/lib/WORC/doc/static/images/flow/flow_expand.svg +++ /dev/null @@ -1,379 +0,0 @@ - - - - - - - - - - - - - - - - image/svg+xml - - - - - - - - - - (a0) - - - - (b0, b1) - - - - (c0, c1) - - dim1 - - - - - (a0) - - - - (b0) - - - - (c0) - - - - - - - - (b1) - - - - (c1) - - dim1 - dim2 - - - - expand - - - diff --git a/build/lib/WORC/doc/static/images/flow/flow_expand_collapse.pdf b/build/lib/WORC/doc/static/images/flow/flow_expand_collapse.pdf deleted file mode 100644 index 9aa6a372..00000000 Binary files a/build/lib/WORC/doc/static/images/flow/flow_expand_collapse.pdf and /dev/null differ diff --git a/build/lib/WORC/doc/static/images/flow/flow_expand_collapse.svg b/build/lib/WORC/doc/static/images/flow/flow_expand_collapse.svg deleted file mode 100644 index 81d995d8..00000000 --- a/build/lib/WORC/doc/static/images/flow/flow_expand_collapse.svg +++ /dev/null @@ -1,301 +0,0 @@ - - - - - - - - - - - - - - - - - - - image/svg+xml - - - - - - - - - - (a0) - - - - (b0, b1) - - - - (c0, c1) - - dim1 - - - - - (a0 ,b0, c0) - - - - (b1, c1) - - dim2 - - expand & - - collapse(dim1) - - diff --git a/build/lib/WORC/doc/static/images/flow/flow_simple_one_sample.pdf b/build/lib/WORC/doc/static/images/flow/flow_simple_one_sample.pdf deleted file mode 100644 index c0157aef..00000000 Binary files a/build/lib/WORC/doc/static/images/flow/flow_simple_one_sample.pdf and /dev/null differ diff --git a/build/lib/WORC/doc/static/images/flow/flow_simple_one_sample.svg b/build/lib/WORC/doc/static/images/flow/flow_simple_one_sample.svg deleted file mode 100644 index b8e78a64..00000000 --- a/build/lib/WORC/doc/static/images/flow/flow_simple_one_sample.svg +++ /dev/null @@ -1,210 +0,0 @@ - - - - - - - - - - - - - - - - - image/svg+xml - - - - - - - - - (f0) - - - - (m0) - - - - (p0) - - - (tf0,m0,p0) - - - results in - - - diff --git a/build/lib/WORC/doc/static/images/flow/flow_simple_one_sample_two_cardinality.pdf b/build/lib/WORC/doc/static/images/flow/flow_simple_one_sample_two_cardinality.pdf deleted file mode 100644 index 8f2d26fb..00000000 Binary files a/build/lib/WORC/doc/static/images/flow/flow_simple_one_sample_two_cardinality.pdf and /dev/null differ diff --git a/build/lib/WORC/doc/static/images/flow/flow_simple_one_sample_two_cardinality.svg b/build/lib/WORC/doc/static/images/flow/flow_simple_one_sample_two_cardinality.svg deleted file mode 100644 index 3e36e7d6..00000000 --- a/build/lib/WORC/doc/static/images/flow/flow_simple_one_sample_two_cardinality.svg +++ /dev/null @@ -1,214 +0,0 @@ - - - - - - - - - - - - - - - - - image/svg+xml - - - - - - - - - (f0) - - - - (m0) - - - - (p0, p1) - - - (tf0,m0,p0, tt0,m0,p1) - - - results in - - - diff --git a/build/lib/WORC/doc/static/images/flow/flow_simple_three_sample.pdf b/build/lib/WORC/doc/static/images/flow/flow_simple_three_sample.pdf deleted file mode 100644 index b4f06db0..00000000 Binary files a/build/lib/WORC/doc/static/images/flow/flow_simple_three_sample.pdf and /dev/null differ diff --git a/build/lib/WORC/doc/static/images/flow/flow_simple_three_sample.svg b/build/lib/WORC/doc/static/images/flow/flow_simple_three_sample.svg deleted file mode 100644 index f17bb03b..00000000 --- a/build/lib/WORC/doc/static/images/flow/flow_simple_three_sample.svg +++ /dev/null @@ -1,345 +0,0 @@ - - - - - - - - - - - - - - - - - - - - image/svg+xml - - - - - - - - - - (p0) - - - - results in - - - - - (f0) - - - - (f1) - - - - (f2) - - - - - - (m0) - - - - - - (tf0,m0,p0) - - - - (tf1,m0,p0) - - - - (tf2,m0,p0) - - - - - diff --git a/build/lib/WORC/doc/static/images/flow/flow_simple_three_sample_two_cardinality.pdf b/build/lib/WORC/doc/static/images/flow/flow_simple_three_sample_two_cardinality.pdf deleted file mode 100644 index 146ec5f2..00000000 Binary files a/build/lib/WORC/doc/static/images/flow/flow_simple_three_sample_two_cardinality.pdf and /dev/null differ diff --git a/build/lib/WORC/doc/static/images/flow/flow_simple_three_sample_two_cardinality.svg b/build/lib/WORC/doc/static/images/flow/flow_simple_three_sample_two_cardinality.svg deleted file mode 100644 index 169572bc..00000000 --- a/build/lib/WORC/doc/static/images/flow/flow_simple_three_sample_two_cardinality.svg +++ /dev/null @@ -1,411 +0,0 @@ - - - - - - - - - - - - - - - - - - - - - - - image/svg+xml - - - - - - - - - - (p0, p1) - - - - results in - - - - - (f0) - - - - (f1) - - - - (f2) - - - - - - (m0) - - - - (m1) - - - - (m2) - - - - - (tf0,m0,p0, tf0,m0,p1) - - (tf1,m1,p0, tf1,m1,p1) - - (tf2,m2,p0, tf2,m2,p1) - - - - diff --git a/build/lib/WORC/doc/static/images/network1.pdf b/build/lib/WORC/doc/static/images/network1.pdf deleted file mode 100644 index 1e895455..00000000 Binary files a/build/lib/WORC/doc/static/images/network1.pdf and /dev/null differ diff --git a/build/lib/WORC/doc/static/images/network1.svg b/build/lib/WORC/doc/static/images/network1.svg deleted file mode 100644 index 6dfbcb26..00000000 --- a/build/lib/WORC/doc/static/images/network1.svg +++ /dev/null @@ -1,64 +0,0 @@ - - - - - - -G - - -source1 - -source1 - - - -output - - -addint - -addint - -left_hand - -right_hand - -result - - -source1:output->addint:left_hand - - - - -const1 - -const1 - -[['1'], ['3'], ['3'], ['7']] - - -const1:output->addint:right_hand - - - - -sink1 - -sink1 - -input - - - - -addint:result->sink1:input - - - - - diff --git a/build/lib/WORC/doc/static/images/network2.pdf b/build/lib/WORC/doc/static/images/network2.pdf deleted file mode 100644 index 48a78a93..00000000 Binary files a/build/lib/WORC/doc/static/images/network2.pdf and /dev/null differ diff --git a/build/lib/WORC/doc/static/images/network2.svg b/build/lib/WORC/doc/static/images/network2.svg deleted file mode 100644 index 6f20f857..00000000 --- a/build/lib/WORC/doc/static/images/network2.svg +++ /dev/null @@ -1,151 +0,0 @@ - - - - - - -G - - -fixed_img - -fixed_img - - - -output - - -elastix - -elastix - -fixed - -moving - -parameters - -fixedMask - -movingMask - -initialTransform - -priority - -threads - -directory - -transform - -log - - -fixed_img:output->elastix:fixed - - - - -moving_img - -moving_img - - - -output - - -transformix - -transformix - -transform - -input_image - -input_points - -detjac - -jacmat - -priority - -threads - -directory - -output_image - -output_points - -output_jac - -output_jacmat - -log - - -moving_img:output->transformix:input_image - - - - -moving_img:output->elastix:moving - - - - -param_file - -param_file - - - -output - - -param_file:output->elastix:parameters - - - - -sink_image - -sink_image - -input - - - - -transformix:output_image->sink_image:input - - - - -elastix:transform->transformix:transform - - - - -sink_trans - -sink_trans - -input - - - - -elastix:transform->sink_trans:input - - - - - diff --git a/build/lib/WORC/doc/static/images/network_multi_atlas.pdf b/build/lib/WORC/doc/static/images/network_multi_atlas.pdf deleted file mode 100644 index b57f02f8..00000000 Binary files a/build/lib/WORC/doc/static/images/network_multi_atlas.pdf and /dev/null differ diff --git a/build/lib/WORC/doc/static/images/network_multi_atlas.svg b/build/lib/WORC/doc/static/images/network_multi_atlas.svg deleted file mode 100644 index 44237e96..00000000 --- a/build/lib/WORC/doc/static/images/network_multi_atlas.svg +++ /dev/null @@ -1,816 +0,0 @@ - - - - - - - - - - image/svg+xml - - - - - - - - - G - - - - target_img - - target_img - - - - output [N] - - - - elastix - - elastix - - [N] fixed_image - - [M] moving_image - - [R] parameters - - fixed_mask - - moving_mask - - initial_transform - - priority - - threads - - directory - - transform [NxM] - - log_file - - - - target_img:o_output->elastix:i_fixed_image - - - - - - mask_image - - mask_image - - - - output [M] - - - - transformix - - transformix - - [NxM] transform - - [M] image - - points - - determinant_of_jacobian_flag - - jacobian_matrix_flag - - priority - - threads - - directory - - image [NxM] - - points - - determinant_of_jacobian - - jacobian_matrix - - log_file - - - - mask_image:o_output->transformix:i_image - - - - - - template_img - - template_img - - - - output [M] - - - - template_img:o_output->elastix:i_moving_image - - - - - - param_file - - param_file - - - - output [O] - - - - param_file:o_output->elastix:i_parameters - - - - - - const_combine_method - - const_combine_method - - [['VOTE']] [P] - - - - combine - - combine - - [N] images - - [P] method - - [Q] number_of_classes - - original_labels - - substitute_labels - - hard_segment [N] - - soft_segment - - - - const_combine_method:o_output->combine:i_method - - - - - - const_combine_number_of_classes - - const_combine_number_of_classes - - [['3']] [Q] - - - - const_combine_number_of_classes:o_output->combine:i_number_of_classes - - - - - - sink_image - - sink_image - - [N] input - - - - - - combine:o_hard_segment->sink_image:i_input - - - - - - transformix:o_image->combine:i_images - - - - - - elastix:o_transform->transformix:i_transform - - - - - diff --git a/build/lib/WORC/doc/static/images/provo.svg b/build/lib/WORC/doc/static/images/provo.svg deleted file mode 100644 index 8bbaa836..00000000 --- a/build/lib/WORC/doc/static/images/provo.svg +++ /dev/null @@ -1,3 +0,0 @@ - - -2012-11-25 17:39ZCanvas 1Layer 1usedendedAtTimewasAssociatedWithactedOnBehalfOfwasGeneratedBywasAttributedTowasDerivedFromwasInformedByActivityEntityAgentxsd:dateTimestartedAtTimexsd:dateTime diff --git a/build/lib/WORC/doc/static/images/sources/fastr_daemon_structure.xmind b/build/lib/WORC/doc/static/images/sources/fastr_daemon_structure.xmind deleted file mode 100644 index 957db41b..00000000 Binary files a/build/lib/WORC/doc/static/images/sources/fastr_daemon_structure.xmind and /dev/null differ diff --git a/build/lib/WORC/doc/static/images/sources/fastr_server_strucure.xmind b/build/lib/WORC/doc/static/images/sources/fastr_server_strucure.xmind deleted file mode 100644 index 1a17eac5..00000000 Binary files a/build/lib/WORC/doc/static/images/sources/fastr_server_strucure.xmind and /dev/null differ diff --git a/build/lib/WORC/doc/static/images/tools/tooldefresolveflowchart.png b/build/lib/WORC/doc/static/images/tools/tooldefresolveflowchart.png deleted file mode 100644 index 37037bfb..00000000 Binary files a/build/lib/WORC/doc/static/images/tools/tooldefresolveflowchart.png and /dev/null differ diff --git a/build/lib/WORC/doc/static/introduction.rst b/build/lib/WORC/doc/static/introduction.rst deleted file mode 100644 index 8807c55e..00000000 --- a/build/lib/WORC/doc/static/introduction.rst +++ /dev/null @@ -1,102 +0,0 @@ -Introduction -============ - -When I started my PhD at the Erasmus MC in 2016 on radiomics, the idea was to start with a straight-forward radiomics study to get familiar with the field. -Both the field of radiomics and my group at the Erasmus MC had existed for quite some time. -Therefore, I naively expected that all previously created methods and software were nicely organized and would be straight forward to apply and compare. -However, I found that of all the radiomics studies, only a few actually released their software open-source. -Moreover, the software that was available was very diverse in terms of programming language and often difficult to understand. -Each developer used its own ontology, workflow and implementation. - -Hence I wondered which method would work best for my specific application. -It seemed that many of my fellow PhD students started out with the same question. -I did not like the foresight to start out my PhD by tediously working on finding a decent baseline and trying out all kinds of methods. -Moreover, it felt inefficient that every time a new study is started, someone like me had to go through the whole process over and over again. - -I therefore decided to create one radiomics platform in which multiple approaches could easily be integrated. -I tried to make it as flexible as possible and modular, such that researcher can easily integrate their own components into the workflow. - -Including all these methods brought along many choices in terms of both the methods to use and their parameters. -Similar to the above, I also did not like the foresight of manual tuning, which both feels inefficient and a non-optimal approach. -Hence, I decided to create an automatic optimization routine for the platform which includes all the choices in the workflow that have to be made. - -The result is WORC, which has made my research a lot easier and more fun, as I can very easily create a decent radiomics baseline for any study with little effort. - -Radiomics Terminology ---------------------- - -Radiomics concerns the use of quantitative medical image features to predict clinically relevant outcomes. -In WORC, the computational radiomics workflow is divided in five steps: - -.. figure:: images/RadiomicsSteps.* - -1. Image Acquisition, which we assume has already been done. -2. Preprocessing -3. Segmentation -4. Feature Extraction -5. Data Mining - -Preprocessing is defined as anything that is done to the image before the feature extraction. -This may include normalization, cropping, masking, and registration. Filtering may be included as well, although several features may already implicitly use a filter. - -Data mining is defined as anything that is used to go from features to the actual label or outcome. -This may include feature selection, feature imputation, feature scaling, dimensionality reduction, and oversampling. -Note that we always define the last step in data mining as a machine learning approach. -Although several radiomics studies do not use machine learning but directly correlate features with outcome, -we feel that in clinical practice a prediction model is most of the time required. - -Due to the shear amount of tools available in the data mining node, this node in itself is another fastr (micro)network. - -Modularity and standardization: fastr -------------------------------------- - -The first step of building WORC was to standardize radiomics in components to create a modular workflow. -The available radiomics methods were all in different software languages, hence my framework had to support this as well. -Luckily, some of my colleagues had the same issues and decided to create a new workflow engine: `fastr http://journal.frontiersin.org/article/10.3389/fict.2016.00015/full/>`_. -I highly recommend to read at least `the introductory page of the manual `_ in order to get familiar with the basic concept of fastr . - -To illustrate the principles of fastr, one of the simpler workflows created by WORC using fastr is shown in the figure below. - -.. figure:: images/WORC_small.* - -The radiomics workflow is split in nodes. We define four types of nodes: -* Sources, which serve as the input for the workflow. -* Nodes, which is where the actual algorithms run. -* Sinks, which serve as the output for the workflow. -* Constants - -In each node, the inputs, outputs and thereby the task is fixed. However, the actual algorithm that is used within a node is node. -For example, in a feature extraction node, the inputs are an image, possibly a segmentation and parameters, from which features are extracted, which are thereby the output. -Which methods is actually used to extract the features and the features extracted may vary. - -Using fastr in WORC gives us several benefits: -* You can use any tool that can be run on the command line: thus languages or interpreters like MATLAB, Python, R, but also executables. -* As the workflow is standardized, the outputs are as well. Hence workflows can be easily compared. -* fastr automatic keeps a history of how an output was created, or the provenance, and extensive logging. This facilitates high reproducability. -* Wrapping a tool in fastr is easy: you only need to determine the inputs, outputs, interpreter and script. -* fastr supports various execution plugins, thus execution of a pipeline on a cluster or a simple laptop can be adapted to the resources at hand. -* Data can be imported and exported to various sources, also online! - - -Optimization ------------- - -When starting a new radiomics study, e.g. trying to find a imaging biomarker on a new dataset, you would normally have to design a workflow yourself from all methods available in WORC. -Not only would you have to determine which methods you are going to use, but also which parameters for all methods. Many studies have shown that these are often not independent: -the performance of many methods highly depends on the parameters used. Thus, we need to simultanously look for the best combination of these. - -As these parameters are set before the actual learning step in the machine learning part, we refer to these as hyperparameters. -As the performance of the machine learning algorithm may depend on the previous steps -(e.g. preprocessing, feature extraction, and all other steps in the data mining node), -we decided to include all parameters from all nodes as hyperparameters. - -Optimization is done through a variant of combined algorithm selection and hyperparameter (CASH) optimization problem. -Currently, WORC solves the problem as following: - -.. figure:: images/CASH.* - -1. Generate a large number of different pipelines. -2. Execute them and rank them. -3. Create and ensemble of the X best performing pipelines. - -More information on this can be found in X. diff --git a/build/lib/WORC/doc/static/quick_start.rst b/build/lib/WORC/doc/static/quick_start.rst deleted file mode 100644 index 47be8c5a..00000000 --- a/build/lib/WORC/doc/static/quick_start.rst +++ /dev/null @@ -1,81 +0,0 @@ -Quick start guide -================= - -This manual will show users how to install WORC, configure WORC and construct and run simple networks. - -.. _installation-chapter: - -Installation ------------- - -You can install WORC either using pip, or from the source code. - -Installing via pip -`````````````````` - -You can simply install WORC using ``pip``: - -.. code-block:: bash - - pip install WORC - -.. note:: You might want to consider installing ``WORC`` in a `virtualenv `_ - - -Installing from source code -``````````````````````````` - -To install from source code, use git via the command-line: - -.. code-block:: bash - - git clone https://github.com/MStarmans91/WORC.git # for http - git clone ssh://git@github.com:MStarmans91/WORC.git # for ssh - -.. _subsec-installing: - -To install to your current Python environment, run: - -.. code-block:: bash - - cd WORC/ - pip install . - -This installs the scripts and packages in the default system folders. For -Windows this is the python ``site-packages`` directory for the WORC python -library. For Ubuntu this is in the ``/usr/local/lib/python3.x/dist-packages/`` folder. - -.. note:: If you want to develop WORC, you might want to use ``pip install -e .`` to get an editable install - -.. note:: You might want to consider installing ``WORC`` in a `virtualenv `_ - - -Configuration -------------- - -WORC has defaults for all settings so it can be run out of the box to test the examples. -However, you may want to alter the fastr configuration to your system settings, e.g. -to locate your input and output folders and how much you want to parallelize the execution. - -Fastr will search for a config file named ``config.py`` in the ``$FASTRHOME`` directory -(which defaults to ``~/.fastr/`` if it is not set). So if ``$FASTRHOME`` is set the ``~/.fastr/`` -will be ignored. Additionally, .py files from the ``$FASTRHOME/config.d`` folder will be parsed -as well. You will see that upon installation, WORC has already put a ``WORC_config.py`` file in the -``config.d`` folder. - -For a sample configuration file and a complete overview of the options in ``config.py`` see -the :ref:`Config file ` section. - - -Tutorial --------- - -To start out using WORC, we recommend you to follow the tutorial located in the -[WORCTutorial Github](https://github.com/MStarmans91/WORCTutorial). Besides some more advanced tutorials, -the main tutorial can be found in the WORCTutorial.ipynb Jupyter notebook. Instructions on how -to use the notebook can be found in the Github. - -If you run into any issue, you can first debug your network using -`the fastr trace tool `_. -If you're stuck, feel free to post an issue on the `WORC Github `_. - diff --git a/build/lib/WORC/doc/static/user_manual.rst b/build/lib/WORC/doc/static/user_manual.rst deleted file mode 100644 index 1a5494bc..00000000 --- a/build/lib/WORC/doc/static/user_manual.rst +++ /dev/null @@ -1,275 +0,0 @@ -User Manual -=========== - -In this chapter we will discuss the parts of Fastr in more detail. We will give a more complete overview of the system -and describe the more advanced features. - -.. _tools: - -The WORC object ---------------- - -The WORC toolbox consists of one main object, the WORC object: - - - -.. code-block:: python - - import WORC - network = WORC.WORC('somename') - - - -It's attributes are split in a couple of categories. We will not discuss -the WORC.defaultconfig() function here, which generates the default -configuration, as it is listed in a separate page, see the :ref:`config file section `. - - - -Attributes: Sources -------------------- - - - -There are numerous WORC attributes which serve as source nodes for the -FASTR network. These are: - - -- images_train and images_test -- segmentations_train and segmentations_test -- semantics_train and semantics_test -- labels_train and labels_test -- masks_train and masks_test -- features_train and features_test -- metadata_train and metadata_test -- Elastix_Para -- fastrconfigs - - -When using a single dataset for both training and evaluation, you should -supply all sources in train objects. You can use several kinds of -validation methods (e.g.cross validation) to compute the performance on -this dataset. Optionally, you can supply a separate training and test -set. - - -Each source should be given as a dictionary of strings corresponding to -the source files. Each element should correspond to a single object, -e.g. tumor, or patient. The keys are used to match the features to the -label and semantics sources, so make sure these correspond to the label -file. The values should refer to the actual source files corresponding -to the FASTR formats, see -http://fastr.readthedocs.io/en/stable/fastr.reference.html#ioplugin-reference. - - -You can off course have multiple images or ROIs per object, e.g. a liver -ROI and a tumor ROI. This can be easily done by appending to the -sources. For example: - -.. code-block:: python - - images1 = {'patient1': vfs://example/MR.nii, 'patient2': vfs://example/MR.nii} - segmentations1 = {'patient1': vfs://example/tumor.nii, 'patient2': vfs://example/tumor.nii} - segmentations2 = {'patient1': vfs://example/liver.nii, 'patient2': vfs://example/liver.nii} - - network.images_train.append(images1) - network.images_train.append(images1) - - network.segmentations_train.append(segmentations1) - network.segmentations_train.append(segmentations2) - - - -When using multiple sequences per patients (e.g. T1 and T2), the same -appending procedure can be used. - - -.. note:: You have to make sure the images and segmentation sources match in size. - -.. note:: You have to supply a configuration file for each image or feature source you append. - Thus, in above example, you need to append two configurations! -.. note:: When you use - multiple image sequences, you can supply a ROI for each sequence by - appending to to segmentations object. Alternatively, when you do not - supply a segmentation for a specific sequence, WORC will use Elastix to - align this sequence to another through image registration. It will then - warp the segmentation from this sequence to the sequence for which you - did not supply a segmentation. **WORC will always align these sequences with no segmentations to the first sequence, i.e. the first object in the images_train list.** - Hence make sure you supply the sequence for which you have a ROI as the first object. - - - -Attributes: Settings --------------------- - - -There are several attributes in WORC which define how your pipeline is -executed: - - - -- fastr_plugin -- fastr_tmpdir -- Tools: additional workflows are stored here. Currently only includes - a pipeline for image registration without any Radiomics. -- CopyMetadata: Whether to automatically copy the metadata info - (e.g. direction of cosines) from the images to the segmentations - before applying transformix. - -An explanation of the FASTR settings is given below. - - - -Attributes: Functions ---------------------- - -The WORC.configs() attribute contains the configparser files, which you -can easily edit. The WORC.set() function saves these objects in a -temporary folder and converts the filename into as FASTR source, which -is then put in the WORC.fastrconfigs() objects. Hence you do not need to -edit the fastrconfigs object manually. - - - -Images and segmentations -~~~~~~~~~~~~~~~~~~~~~~~~ - - - -The minimal input for a Radiomics pipeline consists of either images -(plus a segmentation if you have not implemented an automatic -segmentation tool) or features plus a label file (and a configuration, -but you can just use the default one. - -If you supply these, features will be computed within the segmentations -on the images. They are read out using SimpleITK, which supports various -image formats such as DICOM, NIFTI, TIFF, NRRD and MHD. - - - -Semantics -~~~~~~~~~ - -Semantic features are used in the PREDICT CalcFeatures tool. You can -supply these as a .csv listing your features per patient. The first -column should always be named ``Patient`` and contain the Patient ID. The -other columns should contain a label for the feature and their values. -For example: - - - -+----------+--------+--------+ -| Patient | Label1 | Label2 | -+==========+========+========+ -| patient1 | 1 | 0 | -+----------+--------+--------+ -| patient2 | 2 | 1 | -+----------+--------+--------+ -| patient3 | 1 | 5 | -+----------+--------+--------+ - - -Similar to the patient labels, the semantic features are matched to the -correct image/features by the name of the image/features. So in this -case, your sources should look as following: - - - -.. code-block:: python - - images_train = {'patient1': 'source1.nii.gz', 'patient2': 'source2.nii.gz', ...} - segmentations_train = {'patient1': 'seg1.nii.gz', 'patient2': 'seg2.nii.gz', ...} - - - -Labels -~~~~~~ - -The labels are used in classification. For PREDICT, these should be -supplied as a .txt file. Similar to the semantics, the first column -should head ``Patient`` and contain the patient ID. The next columns can -contain things you want to predict. Hence the format is similar to the -semantics file. - - -Masks ------------ - -WORC contains a segmentation preprocessing tool, called segmentix. This -tool is still under development. The idea is that you can manipulate -your segmentation, e.g. using dilation, then use a mask to make sure it -is still valid. Currently, you can only let it take a ring of a certain -radius around your ROI and mask it. - - - -Features --------- - -If you already computed your features, e.g. from a previous run, you can -directly supply the features instead of the images and segmentations and -skip the feature computation step. These should be stored in .hdf5 files -matching the PREDICT CalcFeatures format. - - -Metadata --------- - -This source can be used if you want to use tags from the DICOM header as -features, e.g. patient age and sex. In this case, this source should -contain a single DICOM per patient from which the tags that are read. -Check the PREDICT.imagefeatures.patient_feature module for the currently -implemented tags. - - - -Elastix_Para ------------- - -If you have multiple images for each patient, e.g. T1 and T2, but only a -single segmentation, you can use image registration to align and -transform the segmentation to the other modality. This is done in WORC -using Elastix http://elastix.isi.uu.nl/. In this source, you can supply -a parameter file for Elastix to be used in the registration in .txt. -format. Alternatively, you can use SimpleElastix to generate a parameter -map and pass this object to WORC. **Note: WORC assume your segmentation -is made on the first WORC.images source you supply. The segmentation -will be alingned to all other image sources.** - - - -FASTR settings --------------- - -There are two WORC attributes which contain settings on running FASTR. -In WORC.fastr_plugin, you can specify which Execution Plugin should be -used: see also -http://fastr.readthedocs.io/en/stable/fastr.reference.html#executionplugin-reference. - -The default is the ProcessPollExecution plugin. The WORC.fastr_tempdir -sets the temporary directory used in your run. - - - -Construction and execution commands ------------------------------------ - - - -After supplying your sources, you need to build the FASTR network. This -can be done through the WORC.build() command. Depending on your sources, -several nodes will be added and linked. This creates the WORC.network() -object, which is a fastr.network() object. You can edit this network -freely, e.g. add another source or node. You can print the network with -the WORC.network.draw_network() command. - - -Next, we have to tell the network which sources should be used in the -source nodes. This can be done through the WORC.set() command. This will -put your supplied sources into the source nodes and also creates the -needed sink nodes. You can check these by looking at the created -WORC.source_data_data and WORC.sink objects. - - -Finally, after completing above steps, you can execute the network -through the WORC.execute() command. diff --git a/build/lib/WORC/exampledata/dummies/dummy.nii.gz b/build/lib/WORC/exampledata/dummies/dummy.nii.gz deleted file mode 100644 index 1bbf8cf0..00000000 Binary files a/build/lib/WORC/exampledata/dummies/dummy.nii.gz and /dev/null differ diff --git a/build/lib/WORC/exampledata/elastix/img0/slice047.mhd b/build/lib/WORC/exampledata/elastix/img0/slice047.mhd deleted file mode 100644 index bd265418..00000000 --- a/build/lib/WORC/exampledata/elastix/img0/slice047.mhd +++ /dev/null @@ -1,13 +0,0 @@ -ObjectType = Image -NDims = 2 -BinaryData = True -BinaryDataByteOrderMSB = False -CompressedData = False -TransformMatrix = 1 0 0 1 -Offset = -57.6875 -250.738 -CenterOfRotation = 0 0 -ElementSpacing = 0.625 0.625 -DimSize = 256 256 -AnatomicalOrientation = ?? -ElementType = MET_SHORT -ElementDataFile = slice047.raw diff --git a/build/lib/WORC/exampledata/elastix/img0/slice047.raw b/build/lib/WORC/exampledata/elastix/img0/slice047.raw deleted file mode 100644 index cb02d1aa..00000000 --- a/build/lib/WORC/exampledata/elastix/img0/slice047.raw +++ /dev/null @@ -1,155 +0,0 @@ -i“±®­¯®®Â¯žŽ{“…sv‘‰¢³§¢•‚ˆk[aw€Ž©§™ª¸»ƒzy‘Ç™}‹‚~zkkaw©¾¢—¼»cbb‹¡³ÐÑ©‘]~~ƒ¦¦žœ¬´®¤mht„“•­¹¶¼¤|ƒŠ§«¥¼É¶†W`y~€}•œŒ ÅÁž¤¥¿ÑÉŲŸ”tz¢›†§ÊÝàŇ…“–†‚wp†ž›£ºÓ¹’Ÿ§‡š«ª’ˆŒ}Œtr|™µ®“Ÿ¬²¤¡š•§¶˜‡z€¹«…yjgYv –rNXy•œŸ¡‡sŽ»Ê¾•…ƒm™¶Å§…XGYƒ£¨œxo…©¢Œ¬ÅÕ˜ƒ“žˆŒ‰etŽ ›Ÿ±Â²´¦©£Œ}dKels”“Ž ‡c_vƒ’ˆ µšŒ±´t‚³Ìœ`bv™™„ws¢±¸§¸Ø«Ž€•´ÇÆÀ®‰uk\s‡°¥© ¸²¡qfz­·­¯ž¡xs€‡££¿Ìº˜poyŠ‰‰‹–©ÂÇǾÁÙ¸¬¯¤¯²¯­—}{˜Št‚©ËÜ´‚tŒ•‘–©œ ½Á·ÁáÌ’Žš›•¢¾¿¤’‘Œwjg‚´³›¥©¨œ©œ£´©“€¢¯”v[ivn°²VVr›¾·£‘yx¨·¬˜nˆ¥ž“eRg‹œ«™k`w…ˆˆŒŒ¥·†“Š‚‰tdumz“ £¿À£¢©”seRD29Lf}ƒ’‘ž§“y~‹˜Œ‘´Ÿ€²Ç³¯¢š¯¿œ^av’¡–‡†~}©¬©½Î¿¹²¤Ÿ³·•}agoŽ–›žŠ†Š—£¥‡¡ÀÆ«˜”„qŠ…hv„ˆ…ª¹©‘ƒzŒœ©¼ÀIJ£Š‡€‹¦——Š‚•Ÿ¦”yhx¯¾­„q‚™ž§¶±“”ÁÊÏÍÚФ—²¹³¦¶Îº“–un^{³¼ª—••—¢œ”¬¸œvqj€ªœut‹to§Ç q7IŽÊÁ¡¤Š~¶¶›Œ}l‚•”•…_d…–¡ª‘lhjpy…†•‘›»Ä¥‚ƒ™pqzYT‹ª©±µ§Šƒ†‚ull[BDbg’š‘|Š¥¤”€‘•†ž¹¯Á×ö°¨ˆovŽtp‚†¢ž–tyŽ©´ª»Èп«›‘”±¤¤žƒsu˜²£•ƒvr€ ­Ï´°µÂ§lfq„œ‘y~x{ ¨¢¬•…ˆ”’žž«¨²Á¹®~|n‹•¦ °¸½¨£ªššoecˆ«³‹—¡²ÀÌÍ©š³¿Ã»ÉÒ¼¤¦®«‡y¯¤£“ˆ{vhv©Å³²r¦§‘~‰±¢tf]xª½†“ˆ’–£x8<–ÒƬ ¨‘˜­¼“zzyv€Š€‡‚£¨™“|hej~•¢¯¡Äâ³v€wjmxfWuŸ“§ “zut†žœ“…Œ—›‘t[‰º¾ÐÀ°˜¨ÁÌÔÀ¦›œ“{OS{ˆ”‡— ’—‰Ÿ¾Ó¬—¢˜—…wªÇ¾¯|{‹¯©–†owŠ­ÁÔÃ¥¦¨ƒ\aonŠ” †xz‹”«µ¢˜§©ª©§¨»ÒÈö¤‹ŠŽ‘Š˜¦©²·ÆÈÆ…o„‰rky“§¡ž£ÂÇÍÙÏÑɪ£’—ª°¥Žƒ…‹}~¡  ƒkreyš²º§€v|›¢ƒ†£¨“wy‘µÖÄ‹Œ—ž‰‹Žš…MVƒ¶¼­š™ˆ‡•´š€q{bw’‡¤” ¡—–’‘yiy…Œ¦¦ˆ³Ò±‚„vs{tpyohz{pp‚‘•zƒ›»¼Æ¹šŒŽ¤ |‡Ž²Óåçزš°ÇË°›–†Œ‘Šrc„°Á ††‡|€²²™‰{`WdhXS°ªŸ—“›€’ž¢¤‰…ƒ•¯º³®Ž•–xodt¥°«¥ž¢€­½½²®£—‘‡·ºžŒ{tpŠ›˜•Ÿ²µ¦¡¤¿¦‹r|¤–wv‰ž¤ª³¶±®¤ «¥—Šwptžš £›Ÿ†˜–“‹Ž†^Obu†¡œ~†Š¤¸¶–“ÄÉšƒ˜ªÂÀ–otˆŽ’§†~a\q›œž‰ˆ­­€_q„•˜…™¢Ž““–›‹ls‡“™’‹ŸÂÌŸ‚…‹„sZn‹r]dmem‹‘§²ÂêãÈ£Ž¤¥Ÿ·¯«¶³Åâæϧ¥»ª¤ª¦›¨Ÿ¨–›š¨©§™wz€mejmŽ¯­’rSp~q^}¡ª˜¢¦nt‰Ž¨º—–€xŒ¢£¡ªªš{ƒ¢¿°™žusž°Ÿ”ˆ‹‰†~t“{qxw¢¤¯­´¸´’®Á·³¤™•Ž}vŠ›¨ª³«¦Žˆˆ“–we{‹¦Âź•œ‰…„†qU]i|«·£ž°Û›™—£Àš‰}—¯¹‘eSrŒ¥ˆ{w„€gk|°ºš€w†¬´‚Ze‰§¡ª—­¥‰ŠŠœ£ §{o}Šƒ‚‡Œ³Ø¯‚‰•‹lb}|€snlmzŒ‰‰™¨¯ÊçðéꢰÄÌÚ°Ž›¶áã¼›«µ©¨°¨—‘ŠšŽ†€‚‡~y…ƒom]^qªÉ·°–‡›¤Žu­¾²—›¤—“–˜ ¨¢—|u~–©¯º¼¦lpyŸŒ‡€„}rprƒ‘“–‹z}€€‹šª­ž¬¶Á°£±§¨¨£®ª „|”°¹¯¯ª£¤˜zv‚“°Á‡}†•¹Êʯ‹wi~Ÿ¡ªµ”…Œ¦´¼®°µ¨¹ªš–Ÿ”ªœ˜‚ˆ‘©—|^r€ƒƒŒ¨–lU}§·®‰|‹š•‡rRwš¦¯·Å´vuœ®ºšwV]‰‡{Ž|€¥ÙÅ“…‘}cn³—Œš—rvŽ“©Ÿ’ ³¹¾ÌàÙª¢°·Á¹šŽ‘¨´Ø´§­° “™rh…“gjm•«®¡rd\U´ª®¢‘–©”¨ÛÏ©‡– ¦®§¢ŠŽ‡“œµ»ª¡_^m…’‚x—¯™“‹“˜‘š{…ˆœ¡¥®¬¡Ž•³£‰™ˆ„‹”¢®˜‘™¢¢©´«’œ‘‰„‘ªÉêÅ’’¸Í¸”wo®ËÑÏÒ±ª®¯™‚s†’‘‘…˜¤¯ž”¯®—of—ŽlXr‡¥¹£tR[™¼º¥‘“Œ‘ž}Re«­µ¾µ¡ƒywŽ¯¨}`YYvŽ|†€uºÚš~‰‰…ŽÇ¸¶ž‘‰—©¥®·­°·µ”‹¸Í¹¦ª¥¦™‚™šš²À¤“–‡‰Š’€ŽœlZ[q™¬¥³ ŠjRCPd¤¼­zª¬£Àξ—~x…”²³¨†{™¦™‡€‹˜¶¾¯¯¦…rbž¥“‚–º¼ÃÔ³“™•–„¯½ª•™©´µ ””„Œ†{€‚—ªÁ¬ª«£˜›­²€€ƒ{z…‘’±ÐæÉ Š›­µ¦¢­²®«Â¸ÅÔÁ˜”˜Šyal„œƒ¦·µ©•¶§lZ~ ž~ki¢¤¢³²}G>p«­¥•ˆŠ–’|U]–­¶¹œ›¦‘}xŽzWSWe€‹•|fn“°ž’Ž¿ÚæåÚÉÆ´¥¤­¶ÄÄÀšt§®»«›¥¥”‘¢¥Ÿ£­¹¥‹Ž…Ž“ ¢•|jdVv‰›·£›‰g[QRawŒ©³¤~oƒ¥±¶±”ykopˆ›°¬‘~~Œ“†„„ËÚÖØÇ¢cW{­‰q~•±¹¸À°¢ šŠ–•‘š–Šxs‹¦¿²ž•šˆˆ¡™Ž„…€›¥¤ ¡¥£¢~†“‰’ŽœÅ̺¢|z~½µµÎÖ²¢š¢£¯œ„ys``x|’®ˆµ®­—u_™®£…m”º´¶«aKP„—ƒuy|‹¢„dN‡©Äµ ¢§wfz“QUi|—ªª{Ye…£§¥„nkb°ÃØçøßÅ­ž¨Á¿ºž–“xŠŸš«~z„Ž—¨–¦¯¯Ÿ˜“›’Ž™Ÿˆ•”‰„‚Ÿ¬º›ŽšzYdmy—­¢”’——¬²ª‰‡’“ww„›‰zo}’šˆƒsx²åÚÖ£hPv¥²“œžœŠ—Ÿ²¶šw\Qdelx“ƒnf}š¼±¥¾°’¥©„xy|ˆš‘°º¤—˜Œ”‚‹…Œ¦™™¦µÃ±˜z‹›²¯¤·Á¢{cauƒˆŽ|`Id”Œ–‡yŠ®³¨—›‡€‰jr–µ®›“ˆ’£¸¨”a\`pujwtŒ´Ÿa8_•Ç³ŸŠ‚„tƒ¡zWg‘¬ª¡rTd‘¢­£ŽqkqÎÐÐÐä÷Û¶²£Ÿµ²‡Ž“q•™‘rXy’Šs{˜©°®¥—{†¨ºÁº£«}^[j·É¹§ŠjdlxŠ–™˜·­—•˜ªœŸ£¨‡Ti}—‘˜ž”||`^_”¹ÁØ„[xªÀª¥¢rgax—¶¨oRNm­¨tHa‹¬¨ ¬µ“š·Ž€˜››£®¿§ƒ‘•‘yx{‘¥™š¨¨¤™„ušž¢¬®rRQ]zz©£gDj”°—‰†ˆ{£ ¡°š’lz}£¯Ãª‡…•°Êµ¨…Š„{rmoz{‚ˆ±˜y:=q™¯š™Š€ƒˆ »º…]ŒˆŽ†an©··¼¢†lzï͵¸ÊÇ­²¾³¬¢’wjXh}•¥®˜•••••ƒxkk†Ä²¡©“{Ž¢­§±°ƒhRZSi•­—‡xy|{ƒ£–ŒŽywŽ¯°¨¶¹§Š‹·¿­„|Ž‰„ƒfRO{£½Ùà°mbœÇ²žycWUQf~«Äznt‡š©²¯koz‡“””®ª¤¸±¯°¨”}†’–™„‹“°¬prv†…Ž¢¢•‰Œ‘ ¢›¨­°˜p]kƒˆŒ¦®·„ch€££ŽŠ’’x|šº¯zfiuzŒ¤ÁÔ¯‚‡¨½Å½¤ ‹uicjkˆ‡ŒDR¡ÑÌ¢”“Ÿ£¦ÍÄG^mb{›Œˆ¯«ÁÁ³ubhåÚÇ´¢Ÿ²«££¡ž—Šl_Xb†œ¯±ŸÁÜŃ~ykvœž£§¡¯¯ŸŠw†‚~{pjy’{†…‹–œ›¾¸Šqwjc†´¿¸°­µ¢“¯³hPy˜°³¸ž’— ³ÝéÂ…Bd¹´‹qt{vx}›¶•ŠzŠª§³¼­‡yto†‘’°¼¯³¾µª™ŽurœŸ—š¯¬¥yt€}‚— š”‘•–”•š–š¤½¬€{Š¡³­¨†s|•¤¥§†š§šhgy™”š¿©•”¨¯žŽ±¬—tiflzsrŠ}~…_@T—ÍÙº£‘££– ¬ gXWr™±¢‹“ºÁ²’“pb°®Å؉§˜|\`q‚‹|q‡ŒŒ‘• ¶§¬©ƒq“Š~’’»Á½¼À“nio“¡™“}^Yj{‰Š›™•Ÿ¬¹Šjx{o|±Ë½ž¥®¨~—ª™Ž•¶ÀÚÒ¹‘”«¾ÊæÏ›WYŽ…—ª®¤‘up‘Œ’¨µ¿¸¯»µ™v}š³¶¨­¤¥«œ…~jw…’›¸­—¬ªˆ€’ šž¦¢‘š–šž—“¤«£•”¤®“hy¦Ã´››šž˜•“§›¤«›‡†Œž•ˆŠ~i|¾ËÆŠ~Œ„š“ƒdav„Žƒio€‚†–ƒnk‘´àÖŸ‹Ÿ†„†œ²–bdˆ®Ëª‰—È™¶¼šV¼Ãªœ…{…k_m†•¤’š¤“€yp“•booz–œ¤—¤¢¡œ¤np­¬tsqWYe›–œ  Œ•„zŠ‘~›¬§”‘§§‡”µ¼¬–“¢ž•Š†˜·Á×ØÈ~DWoŒ±À©•Š‡–’•­±µª®¸¼±’›°¼²Œ|m€‘“€zzœ£«­¯Ÿ“¦‰‹—™¥²²š‡†›µÆ¹«ª³²ªœ“‡ ˜„²¯—”Ÿ£ °¤œ•™ž³±ž„Ÿ»©|o…y]‚ÄÜÄŽnivttnUOVƒ–mi’œ™¬¶œvs¡ßà¦saqiahŒ±µ›†€Ž§¼´£¸¸µ¶Ê™q†©¼§£ˆ|‹”†—™‘¥Ÿ•™‚pjƒ–‰¡¦¤¢Ž–huŽŸ¹žl}Œ •ykffZc`uo€Š•{}…yjxŒ‡ŽŠ•›•£·³™²·ˆmƒ¤ª¦¡§–¡¦®±£vLHfŠ¦¹¹¡’¦£—²»²³ ²Ãºº¶¥¡ˆ€“¥°œwwv–¤–¤·º²Ÿµª¥”š“„Ž†‘´Æ¡ƒˆ¦¿Ç½¬“Ÿ¾¼¯•ˆ•™‡Œ†œ£–”¤ Šx…š•³Æ´›‰¦¬Œq…wo¯ÔÍ‘aXgqZdtpRYŸ®™ˆ¤­¼³”|u~§¾²rZtdQ…§«¤›†g]ÔἫ³ÒÇÌÇy™½Àºš„ˆ§•’—ž˜Ÿ›xty‚ƒ“ª¯š£‘…‚wigŠŠ|•”ž«Ê¦€jx‘ŽmwŒ|yqx~†œ‰w{‹tp‚™— ªµ¶¦ ®©ƒ‘•¤²¿ÓÛØÇŸz…y…€‡bVo’›Ÿ¤–¨¡†•½¸º¨™•——‚on€s‰›œŸ­ª™¡¶¾ÌÅ·¢¢°¸³¢¨§Ž†‰Œ­¾­ž­¼Ãƹ°˜¹Å²ª˜“‘“}‹¿¿¨©‘…xlxš—Œ¥¶’im¢–„gTfÆß©mak~ogœŽg} ¿©ygˆ””Œosmguœ½¢w†yc•¾·‚€m‰ÊåäÌŸœÃ¹Â·Œ“˜²¸´‘ih‡†rmw}€‹Š‡™©­­‘†ŽŠ”²…r~•|šœ{ŠŸ¹­‹yw}€ols£¡‰z}{„‹™¡šˆŸ¤†™–Š“¦¶¶¸ž¤¯“°ÊÔäéÙ½±l~Š’¬²È«–ˆ•‰‹’”§—„‚„š¤tR<it€ƒŠ˜šu„¤±¸³—ƒ‰Á˽µ¤ŒŒ¦«³°§Ÿˆ„¡£»½¹©¸Ã¾ÃЮ©ž¨°­­¨™†•œ’˜´º«šƒvŒvv„p†£”}f‘iasVH‘Ѻ…iy–€nŽ°–noš©±‚n€‹qty…yjcˆµ¹ˆy‚Ÿ·¨ŠŠŠ}„½ÕÖº™¤¥¯¯—‡‰¡›–€ZRht\Sheo“¥²Ðз«Š|k~¢¥˜ž®«™ˆ•zc^ay ¬‰€mtbbHAk¨Ÿ’Šgh{’¢˜”“•£œ‹sgjzy¨§ÃɼÅáб³³³¥£•‡uŒ†‰¿ÔϯŒxks}ˆ‘‚wjh{Œpi›¡°¥}wœ¯§©˜‡y™ÈÅ®´žŒž¬¯¡—‹˜«¯¥±³™–—““œ›˜œ–—™ «®˜‡Ÿ§§¨ª§efmv†„†Š‡t†Š‚vˆ˜gj‹~Sr™ ypo‰ƒy~ˆl„¶Ê­—–ˆ{‚—¢’uŠ±¢•o†—”š„‚Œ|Y„´éÑž˜–›¬À­p~’”‚cPR_Z_t}¦¶¯°³¬˜…s`„‘—˜µÆλ Œ{yoQ]uw¢’…shopP=P”²¶¨”hbj€˜¥¦„{tsrsŠ‡v•½ËÕçܲ±V^‰š‰“‡Š|}sp¢ÌÏĶŒs…«·ž˜ˆw|†¯·È¢˜·Å½¹¿Á£‚Š¬­”|ibv°ÒͶ–‘§Šy‰«Ÿ‘™ˆŒ¡¡¹­Ÿ{z~„‡‰œ¨ ˆu…±³§¡›Ÿ£´­·±w€ztyˆ º¡{z‹ˆŠœ~o…Žd4R}{w|ˆ~‚…—Œ}”¬Á´°’•Žˆ€›–ˆ£ž”~¦‹Œp€³•c`¬á߸“| ÕÕµw{}}la]noo‚“§°Â·qib}„ŽŸ¥›’“˜ž‰kmuz~{{‚jtŽ‚y€”‡iou‰œªŽxntƒ—´´q]b’ž¤¾À²¶½ÊÀȯŠƒrI=jš¡—…uƒƒ{yz”½ÙÏÅ¥‚˜¬·¨™†™£§¸±££­²¾½¶§ŸŸ˜rzŸ£ƒxvmxšÚçÁ¥›¨Ÿ~‰–¯¾Ä°›ŸÄɳ¬¡ƒ‚†šÁ¼™u[‚¯³´«ž”žÂÏÆË˳³­¨¤¥ª§‡„ƒ…”ŠxuiaD@w‡ª˜œ–‰ŒŠƒ„‰£¤¡•–˜—‰Œ¤¨Ÿ¤’£¬”¢¬ªŒ”¡š´°s–ÊÓ²›–ÄÝÄ“_[cci}•š’‘Š‰z‰¡¬°—b`u‰©¬œ™”qtpeVauu‹ˆ…ƒ…tn›••‘—»¶—Š€‹š¥¥’”ƒºª—z`X‚©ÐÝඖ¬•…„šˆ…dIUŽ¨¡ŽvŒ¢¤–‹Ž˜°»¯ŒŠ¡Âɼœ“„tw}ˆ›°±¹ª›Š|…‰³« •’‡±ÑÙÄ·½ËÇ ¥³ÊÖŸ—¶Ã¾¶º­“’—ªÒ•ow•¡Æº¬’ŽŸºÐÙÒ鱬²®œ„rl‹†|v{q}…iUJd‹»£‡‰y‡ˆ…ŠŸ™‹€•šŒŠ—¯¤Š›Àŵ±¢„w¶½°«¶±˜w¯ØÆ°¢¦Æ¢ŒTSgn€¡©¯µ´±œŽ—Ÿž ž–—ˆž¨ƒwxkfp‡•« š¡™„Ž¡Ÿ’—«º«Ÿ ¦©¨ ¡’…wˆ˜¥¤ ¤«­¸·¾µ“„‰rhx’˜cQUr£²®…¥²˜¦}„“ Á®’}h…—§˜™xk]¤®¹¹Æµ®š•¢«²·¾°¡‘›Ÿ¥ÊÇ·ÊÒÐÑ¢Ž›§¡¦’‰”«¶Ç˲©œ¡š”©´¾§†zm{ŽµÀÁ ‘¨¿Ì¼¾­ž•˜‹Œ|~–›‹_u~ƒrJCPk–·”w{}zƒ’¤ £œ |˜™ˆzt›¦ž£µÁ°•’‡–×Ä· «»œ}k¥Ö϶‰›®˜vo­¡¦«ÆÄÔ¼Ÿš~„ËäÓ¸ˆnsƒ—¼®¯¿¶¤Šš¸¸¯®‘‚‚Ž™—¨•¦²µ¸¬±­•‡|ƒ†ŠŒ­¶ÆÍÌ´‘t{{y€‘‡~”Œ’Ÿ‚vo{¢º¾± ¸¿º¸°Š|‹ŽnRFRo‰†“¬º—‹“°¼¹ÆÛâÛÍÊ­­£¡§º¬¬Ã·½Ñг©¯«¬…it†„Š{œ¸²­½¤„Œ—Ž„¡—Ž‘ž„’–©´¸²£›Ÿœ›«¯¶–‚‰Œ”‰ƒ…~‚xfm|rI7[l„Œ­¡‹|Œ‘©ÐÒ½†~šœk‹„{mˆ™¯žŠ §“¢¢š³¸°–«¾¬€zœèä·’~Œž¦ª›–«´§n‡«»¿­š“–ºÖÊȨ†…˜¸ÙÞÎÕ϶¥ˆ}u{‹ˆ‹ˆš§¨¶´³¢µ°¯ª°¤œ‰{´Þ̹ÂŲ “¡‡r‰Œ‰q‡sd‘•Ž¥²«ª­²³¼¸œ«Ã¯¯¦rx‰~€ƒ~grs€~·ÝËÊìÙÊÇÇÒßÏÀ´¨¯¨¬­´»¿ÉÀ—²´™zqƒ”„vs}œ˜†‹¢´£“¤¡”–šˆŒ²«“›½Ç¦–ŽŒ•¦º™Šƒ|‘¶¿¯šzq€xw~x~ssjWjjj`l~‚‰†ª¶•™¦›¶ÏåÂuUi–u|‡“ˆkv’…•š±µ”œ§‘§²’ž·°£ƒ–ßúÏ–}Š‡¯¤®¨“}dE^œ¤²ž–œ™¸º´©ž”…˜•Œ“ˆqfbnƒ“› «½·´³¤‘œµ³§©¯¬¥—•¬×Ë«·¨¤Œqzuj{–†fu“†snœª¤±·È¼Çʳ†~‡~ƒž’‘”“’«·¨zw}™¼ÅÃÖÒ¹­©·¯º³š’‘˜£ž¿É¢zter¦¥ŠŽ—‘‰ŒœšŠ™œ˜—ƒ{€¥¹¾²ÆÛ¢‘’‰‚‚ƒk{¶Ã¤‰wqombcwvnst\aƒ”Ž^ZiŒŠƒ›ˆ¦´«´´Æ°mBB‚ž„‰œŒt{›}|®¾±—’˜{{¬°¡˜³ºÇ¸¿åݶŒmh˜Ÿ–•†€WPUu•Ÿ¡§¬¦¦•‚“œ£ŠŠmN@I@7awyngh|‚Œ™¯«˜¢zr—›Ÿ¬¦šžºÂˤ™Š˜¥©µ·°«‹jhb`{jb›€|š ¶´¯Ñʹ±©|n_h„­¶¨¢ –“£±´°œŠˆrexŒ•¶¶°®´°®ÆÅ°„}dVx™±ªÄäÔ£”ŠŽ§ª²­ž˜§§±±²ª‘’—„~~‚{’¶Âº¨µÃ¾ª©‘ts‰—šuow– §§¨“mowo„~vnsqwhvqOWo“¤¸¹À­³°Ÿ–‰UFm‚‚º§ƒo–‚©´´¦}wq‚ ±—‹¤ºÈÉ•Ú汄mn„‹”‹…‰Š‘§„ŒŠŽ“—‹xlo{¡…VMDX^enz‚Œst{ˆŠ€›¤™€cPp•¯¸°¥¥¤Ôüã³’ˆ®ËÄÉÖÝű|…kff„km‘¬µˆ·²ª¢“‰•{^[cj‹ºÏͽ¯¤ ‘Žš¬°ª¨¤†r‚Œ‰šŸ®ÅÅ»šœÄ­‘™€s~²ËÙÙéßÆ¢”•§§¯½Â²®¸ºµ¬“Œ†ŒŠ”¤•›¬§¥§°¶µ§¨€oy˜¬‘hdt“›¡ª²™zvŠ‚m~ƒin|Œˆ†‹–c^Rz«œ»Óȵ¦š•‹}ˆ}F:mˆ™¿²†f«‰‹¦´¡iit„’›‰~­È»µ‘ŽËÓ«Œ‹†Ž¬­§¶ÁÎ˽•‡wy}wpk}€kwœ£“€}~€w’™¥©¨¨˜‰„ƒŒŸ˜¦¼¾ÒßÕÐƾÇú'ñÇËî -ðÑØæײ¤Ÿ¡…—„€š½´•‚ƒ¨¸œx…ŠŠƒUTn–˜ª»»¶²¼¤—–žž¬¯´¡˜•Ÿ˜ †Ž¢ÀÀrx¹ÔÈ˽šŽ¦ÎÐÔãçÓ ˆ”¼Î½¨¢¦®¦Ÿ‹¢¿ÙÓ²¯©—œ¥©¥¨’zw€‡Ÿ’‡œ lxŽ–¦œ¤jw‡h¦¨¢£´¹±¨£‡~…žµ¤°Ö˵¤›˜x€˜Y5d¥§§xc{¾’a’­ …bly” |v§¸£ÀŽ˜ÅÊ«¨²©’¶Â¶»ÊèâÑ©€see^Relfhpw£©¢¨¦“’•¡ÈàÚǸ»¼É¾¿ºÃÔúñßíÿó=74 -âÕÈÁÒÐÞäÖ¾¸š‰Ž ŸŽ¶Á®œ‘›•™•Ž{wsai‹­¤¢©œ‘˜œ¦ÇÞʳ¨¯²Öôé·¬¾Ù¨¢ÂÛïòÙ²ÂÙãêêêÍŸ¥ŸŸ¥ÂÞÀ°¡¤®°µ¤¶æøæµ–y‹…š¢£ips~‘–ž”“qx‹˜–‡ª–ft‡«âïØÛàêͲÇô½ÒÚ¾­¸ÊÁ·£•¢„r{lRP…š“r_KW˜œtŸ®¨rohŒ~k‘•¦·¥šÀƳµÆÞ—‘¥·¹ÏÝÞ«iSZWlrhbj’¤°·±›šºÁÅÛÝÈÉáþù98ö÷ý -ùó6=(ò!ûßì%0>D2Ö±‚Žš¿½°¨Ä°–² «Ã°ŸŠjHpœ™œªºÔÒÉè(-&') -%O@ÙÌÖìßçöãíþïôøðóæÚÚÇÊäùÞàù༠š·¹¹¶ÎæøÝ·˜§¨­¬¦‹ovyŽš››¢šiv}’~{Ž’Ÿœ•vqŽÂßòø úÆÒÍÀÈØÞƉ{‹¬«™ˆ¨•^h}Y\s’•x^E?–Ê…j€­³’oevƒj”¡©¢—²Á³Äã詧©—³¸Á›|¤¥‘ƒ„˜““µ¿§Œ“³µ¼Ò×ðûþ()($"+8<-"óìîçé ýÿöå)VUILWa\dIE9ýÝÀ²ÄÔÚ«~”¨©ÃÖ½¦®ÓñîÕ¨‚‡ÈÔÄÒØÔëõHj{‰…a6+'*/#÷íóùîÜâô  ýïø5E+÷üðΩ¦À¹©»ÍÙÖÓ¶°µ·«˜“—“{€–œ¨£ š‹zš˜s[jz†“™v‘¯ÊÒâöøòѪ†‘Œ¯´šer¦¸š„˜ll„wfe{†‚XZP˜gs‹¯•nt|‹‹“–x}–ž²µ³ÂÞíØ”—½²œšš‚¯®´½«†ˆ‹x´¾¾˜¦­ÕÔáÿ."#*)   ëÙâÚÞçãÏÅò .Zu„—Ž…weZKeyP äŶÐåÅÍãô÷èùçäì0ÔÁêòÕ¾Òæ"Ccp{qj[ED9=:A4þüîèÛêý  '+&þþ-F8òêÓ¹ÂÓ¾¢¯Á¼¸ ¤”›–™ƒ’žž©µ·°¯«“‘‰›©”Sa“©·ª˜’ˆŽÊàÊÊÚѹ˜{[isp‰o†Œ‚Œ©ÄàÇ~~˜y^MHQrxM_¤§t„£¤†qŽ°•‰„n{—™«Ç¡²ð²¯¬¡œ‡‡„ˆ›ƒtrvrpxŒºÒßÛÛþ ý=NP3ÿîîïø  úÜðñи»Ì×èãå [„oZ??Op–‹‹†~}aVZˆx< B‘½¦“}ejb‚{jC6LI Ì¥§Å»ÂæEYba`digior|uTPYE& þæõ$ùõîòýûúý÷âàÙÓàÒ®›š·¡ –—“‘¥§¢­ÍÊÄÆ¿’yƒœž¥¢ÆÓ«Ãɵµ­¥œ……ŸÆÚض¯¦xrlnwpP8b´Á®´ÂÙ¸‹‚˜gld:6=w¦—vJx²†Œ„˜³¦‘}œ£€yŠtz”¥­Õµqç ³›Šv}€‘˜œ§ˆn]igbt‡†¦ÂÐÐæ575FM佡ª‘ž»ãëëßòîÛâñ ÷èõ"o³šy^Nt‹ykYaz‡u^grrr‡·íYŒs`A79( åØšW0&î´š³ÁÔ DcZQ_bizskg‹†‡UG9)& ýÿ !õÿýÓÞòÖàð÷ÛÆÔÑØĘ‹ ·­¬±®²½¶–‰Š®§²±­ ƒ”¬²©Éç"äãؽ¶¦‘†w‡‰š¯—šq`b€xƒiQ:> Ó½›³¼º™|}„]FL@FV‹· ƒ]zªœž¦’‰›‰‹‹~Œ”ko¦®¼špr·ê‰‚upyŠ˜ °»§~jeq€ˆˆ£¹çßâå-2!íƱŸ”nWcdy®Üþ  àÒã -HszjR]¨’uWM[qzuXe“¹ÞáÿHº°xachZJ2ê±”™œ§bòäû -&AWZ]Ynqoqle~Ž’‘tUP\hDú÷ü úûñ/óàáÝöýûέ°ÎßÔ³š¢ÁÔÑØÑÄ̼¢Œ‘Š•§“š±»²§ÀÓ×ÿýöß̳¥¢Ž{}}itzyz~mquqhfhK?k¦» ÂÃaasXWSHWp„¯«xq‘³Ÿ’…ln—„™“–e”Ÿ§¼³vZÀ“ ˆ†¥²­²¢–¬ÃÀ¯¥§ÃÞìåóýè×ΟŸµÊÆ•spwš±Íö#33!õô%Po|imcyŒ‘{q_]afƒ}Š¢¶å>˜× 0úëÜÚä)4:FDU' FH@JKb‡ebrdfmq\pŸ«±˜‚syOèêÜç ÷ 0$&&!üõý -ýàäîòòúýîæüþäÙÇ®©”Œ‡¤Â·¶ÃÄÐÁÔÞɯ¤‡•Ž€rjw}wsqpvmWS[zyrYXw²±…|›¦‰~szsl``tŽ°·jTg˜°¦‡cNPr– Ÿ’’©‹gy•ªÃÆ‚To–§¥©§†xnƒ“¢º·¼·Êòìõìñݸ¡¨ÐÔÕÛ¼ºÃâú !' -&=/ÞÏÊUYDO_lqjh\^sm^Top_fiz“µÝ0uÑÇnÌ™udix§ê&X\UPc|>Ñtsˆ”Žt^^gjn^Kv›¢˜ˆ{xdDἤÈìõ'IE==MF0' +7:0%8=4-ü 9A2æËÏÁ¬z—¼¾Ã²•–¤±¨—ƒŠ~y‰’‰cjv†pWZPlxI/T{ˆl]n¥Ã’zž®ŠlwˆƒpvŒ­ƒgFb£§bfe`M|…ˆ’©^qŸ®Èï®Wb“’Œ‡ŽŒ¯ÄûÚù!!òÔÉþÒÞò!!/`­Ÿi>% ÷ùåݬ—«ïEN@GR€ƒ‡iG4RdZan‡hJGlŸí5\s–¿„2Ê|QC?Ez±õ5;GX`Sù¹ž¢•taWm†ƒqLITƒŽ~lepfF߸¨‹´ãTmu\k{‚}oOFUQMRA2DHE#  Y`M>úòóóÙεÊÕ̬Šv™•‰¢§’}vŒrc„}qB)@d{uZl‰šo`b„¯Ë›ˆ–²£Žr^v…ad‚nYQJgŒ«ŠyzŠqWSozf{£–syœ¨Éß©ah{†€zŒ’ŒŒŽ³ÊÏâú íïûÿ&-CV`WuŠ£µ´‹Y çÎÇ¿®ˆÇ*`N;Hs–€@õ7^†{mlb<HZŒìOqµµf(í¸…fN<_rºâ -"HK?꿹­¦Žpk{”Ž†qY\qk_d_[PN@ù覂 ;Ks¤µ§¡´¥›—fev~ssmY6Kk9,Kdjqe7+O/ -îɯ«Ÿª£Ÿ‘š·¦y~†j~yj^A2M`f–}“Žyebj“³”†š±ƒm`xiYRXVSJLd“»¢Šˆ‰tcnmji‹Å™›—©¿¶š}s¢ ‡‚ ”Œ™®²Õíóëèîú'0Sfbnpo€‰¶Ã©gîöÿþïÒ¬¯ó=E45IslNþ(:YB?OFLSN_±f€•u4ý¾‡yhP|¨Ä¹Ðï UQ0Ý°˜©²‚ww}Œ†wVCDLEEGE,  õÒæ*W]k†¬À³’†~sr†‘Œ…‚sQGNN9fwprrp;5VcFGT<#&éÊÄ»´±¥¡•–“z‚tihlinUuuZiˆ†‹”’m_bo{£¥‰”ž§ªn^tpVARwsX;`¡É´‘‹z}€—ŧp|žÃÒÉœ€Ä§®¹ÑÔÁÎÚãÚßÑǬ¶ÜèþáéE[>MPjsu‚˜‡’¯Ç´ˆÕé  öúþÓ© ×*3@I_|Œc-$%><YWH6Mû|˜pj`;Ù“gehu®Öôîÿ6“YHÊŸonj^bghd`r[B<V^WO5)&,#ýî7JQUmƒ ’os{y|•~kugM?IHv©¬½oL:atgw‰oG4õãÏ­´ºÑº­«Éб‚oo|w„‚y‚†ck“˜•Ÿ†aT`w¡º›—«­©˜Š\]oiS[•ze€«°¦Š‘ž”Šƒ™ ¢”¥¤qŸ¯ÓõÅ—«ÂÐâõøøàÆáÒÚàĽÔöõ <#0aŠ„€|qm}™”Š£i9ö¼ËââÑÓñÞ¶ŸÛ'JEMHMZ\C %2.>e^5.`ÊJÏà°“Zã±wj‚™Ì&]`BF»Å£žDÉI'=AT^WVenii}zdKB=%ôñþðǾÎÀÞ2E†¸ˆtpspsn–—zucGZ[Lf£å!Çq]a]T_jn_D+3BG4óêÿÿüÿï̧yie{ˆ•”—|lv{†‚|u­M@h­É±¡œ§Ÿ§ŽzivpTe…¥•€£ºÊË©«•‚­§Ÿ‰ ¤Ìܨ”µäÿóËÄ¿Ùéñû +2cw_Ik‰‡xb@&2KbahlW;ïÒ¦‚‚Šˆ„›¬‹†õxpC/!%(öü;I*)HA$•§èÛq* -þäØæôÿ[§Æ¹Šx¿ø»Ó,îõ,:@c\Pm‰Šwp_ccPYrTæÑíôðÐÉÀµÇNb’®¶|\PJRn‚]SFSWJEwÄ38ÛˆRQWGACA;Ufe]cpV?C=5.83$ -ö÷Ø‘VZm–†‚umos]Yh^iŒƒM<K¶¿¦Žm†©~vg_Nc°ª•}—¸ëÑ®›–‡˜“yœÂ¢‘†£²¶¾°“œ÷øÙȼÍÙßãè'&+0WaQe€~rn{zXA$ 6941ëÓÃ¥wNPTpnrŽ¬Î€ÿ¶+  .òüøñ •6É5E1 Ù€BF^\<19d˜ä6NÛì!- ¨â8ïçý295.HjudVJMtwœìØNçÒÎõóÝÓ!p¶ÓÜ¿ŒN5@]jX‘tXQMRPLl–Æ­†eKF=?Xk[Yh~si}•”tcaQFMcaA Þ¯}u~uzŽŠv`cjXLScUSBQq_eeŽŽœvcn¢¹§†\YN^ziˆ´ÈÓÀ§ƒ}„™o¾Å¬›¯¤¦§`JìÝÌ­œÂó$33:>NngqkN@Uzmea_@);%"ôꞣ¦}m`lˆ”›¢Í‡‚2Õô33îÛÚíÊÓ¿ÎÀähøš&iO蜞‹œÓ݉KNlÁP•|PT\ ËsêNÝ¿Óâ!20QqgC9*9tÕjW›ãÂß%E8$kŸÁб}:04JQ-:ˆ}cX?JMT_‹wVH[XFIMg‚oiekjr™«–lZNO…ÉɆ8ÜÉ ‡wa`–¾oK\QRQZmqK?1a…]@k‚—‚otμ£€nY\‘‹tXa˜ÔÃ’ok‚}Œ·ÞÀŽ¦’‚…lKéãÜÕæü+12D/C[€‰dWYI&4`ˆ‚\;(3[q[+!⨰ÅÃÔ½­£Åæüö 8Už~4Øæ..⺞”‹mbr §– “«Š‰‡‘µøÊN¼„’ÙoÂÄ­‡MÑ¢T$ðɸ¶ÑûøøNÁC2’öÚ¶¯ )/,0HcU!!  (T^Q11M]bDIuŽ~phfwpVZfv—\g_U§"ܘf9çtrW}¦—eWUffnkeM<E`zTe‘ªŸŠ¶°¤œdhx•™Ž‰‚fuyž¶‚dn”’Tø̘–—§‚r—vÿ.*#6Hw^/ -YE1'"÷èð 'ì¹¥œ³µ¿¾ëéÝäòöäåçáðHŸsÿÃÇÇñúþÜœicfJAe”¦•ÐN‘ë=J*õ×Ãë#üÑLŒ–‹eS0ñææéÞðüܾ¤‡­Ñó²ÃÏÔõ2u~)ê̬ŽžÕͺ²½¸ÅÜÙÖæÍêöÜÎ×-íþ#64:j™’ycZdts]IXe`hvdSkpiÅ^~º›c:ê ”ˆn‰fTWliF_nYJhy™tc„Œ¦»–p§œ˜on˜‡¨v†ƒ€·¾Ÿrr}…8‹á車ˆ”ˆ|Šœ”6PbWVI5# ý*.6ª~fddfíéòóõáÕÙÜàÛ¿®Ýÿü÷ ôÖÄÁ® Ÿ»Ö÷!CUPWƒ‹»à븄cRsvot¡¸ª¤ð.Fg/éáäïýçÆäÿùñǯ¯À˜Ž™¢¬èÿÚμŸp`’¡”ˆ”³Á²ºÚåÛÇ©„”¤¡•\UiŽÌ˼ÙÒ´¥·Ûƹ«¬ÆÓÌ´Àíìèãÿ.@#  2O_LQ^UNV]dqs|Ô§}Þš“Œ]ÆÀ›€ŠWO\IA_}cZyšŽmFir{£­š•“œ•¥­ºšŠƒ•œ¯Ø«’e[\¡Ñ³ph€”˜·¼cV@AKD-0<çs¾Mã¥|]HPHX\B9.8Xi‚‡„ƒ‰¡™u€’€2%=So›Å²ŸÌZ”×^|i\[wŒWj›Š««´¯¼ÌÔ×Ë­§Æöýúͺª“Œ‚‹nQ]wp®ôáÀ±¡yV]|‰{z„‡˜¢€s”ÄÉ·¥””§¢l[|™ºÖ¬™˜€~‹©ÍÙÁœ¥¹Ï²®¸×Þ¹²ÏÛØÓïêÞÀÍö+AA=NT<Oz€q~Ÿê±Š@4£kv˜gÔª”‹^XTLXhu…yo…u[HQhƒ—¬•†™ª°£‹¦Ê· Œ†sw“‘ŒÍˆZx—U*~Å¥i_€›œ®ÏÌWD.):XO8&ï–GÕ'¤Jô²‚twr~‚ˆ}…ž±ËÄ°¨ª Œ§ÓÎÏØñÖ›ox¥ ¸³ºªŸÖ#GÄ.“Ù:AOf}V:c”Š‰–€„­ÀÉæçÚõõÙöëѵ–qVHVcrM/l~‰ËÞ«”†uq}Ž—™º¯°¶©}w¸ËϺœ“ž§¬¯¼Ä»¿¾ŠŒ‡¨Ùýз¸À±™ÌÓ¶ž£¯ÑºÇ¶™®Ûþ+1Ozƒ}ck£øy3L€¬lEV|†a,Ù§…–‚gf`UYvžˆYSv€†^jŒ §£’§·«Žo~«©•rrej‚zh¥ÆžgwTB“Ƕ~}…›¡¿ßÖYcfbD,ðvÚ{âj«zŠ€x{Œ„ƒ•¬¨¢Àƺ‘eWl‰«É¿­•–qxxoh\r¡§¬«°·Èô3u³C–Ü <_Jg¦”‡Š“±ËέÇÑÑÕÛÍÁ«¤§’Œe;L_liPWt„w Ì«£Ÿ˜Œz“’Œ´½¾ÙÊbÖÉÀ°¨¸¬»ìêѺ››Ã´¯¸›‰¢»äÿË“¢ºº‘®Ä±©‹o|–º±•“©ÛÜ×½ÝøòGqfCm¹ý8‹¥.¡:!-auˆy%Ø­”…pVmsYg~[MZz…}‡µ«¬¬µž–Œ‰Švoƒƒˆa]feqtk‘¼¬yo€t‹¾Ã£ŠŒ’¯Äá¼qsNöš-œî{Ní¥‚‚…Œ‰‹‰œÍД€®²—‚n€‡£ ¶²šp`djpLh”’‰¡·ª}•‘•Š’¶°ÃçO¿%Nm¾¯”†œ¶É±¡¦¯¿½Æ¡Œ~’¥¥ŠUKo‹¬®”zw––Š‡ ¢ŠlCkœ•“–«¶Ð t²³ºÂÉáËÁâ쮉«ÙÛÂÀ¨“¬ºÄ¢q’·¶§‚Š½Î¢s@IÐêÁ¹¾ÙÜ¿¼««°©Ð ,6^±ïûæ¾™H4KSV[{t>Ò—uflvxzw‚{_Kjœ«ª¼¤°¼¡Žˆ}€kez†€tko~x‰‹´Æ‘gx…tµÇ¨›Ž“¾Î´¼QÊB±¦”©³ šŠ„’‘‚~¨.Í~[€ºÁ v^pey”ª¢iVKXec|ºÑ¹°°ž|q…}ƒˆ¹šŒ~®óv*÷Caª¹‘y{‘Ÿ›Œ‡¯ÈØÕ¥xusz‚mlYUº³¨£²Ñͱ‚pD.Ušƒœ§ÁÖ¦¡¦«ÇÉÙëä¼ÑÀ¡ƒ¸Ð×» ¦‡š™ƒŠs„™²ºš‰™¤Ž€kqÃòûî·”¬©ª“ulpg¬ØØñ=…©ÅÎÑÐgY_e{–š|HÌ„m’ €pƒ…tjm¢ÁšŒ–˜“Ž†zu{zx_i„’Œox{”¡xµÂ¡v’„³µ ˜«— Ÿ¸Å {ømñ³gYa€º©““ ­¨ˆ€‚žÞõά›ˆž¶Ã·jR@Kr–­¹Ÿ^aŽ‚¡àíçâè°Ÿyn€ŸÈñ˦~ªîóVpˆ±£y[ax˜¬ÌàèÍ’~YPNspfFCz¦«ÍçÙ£~^<:l™”Ž‡”­¤¬ÌíÖ¹¼Ðäçëȳ®·™–¢¨¹ØŬ‘’Ÿ º¼­£Ÿ¦›x‚–¥Ã¶³ÜúÜظ‡{Ÿ†xUB6Jz‡q€žÍö<†²ÙëÖŽ~s… ¿Ñ›7Æ€ƒŒ„hkqeVerŽ‹‹„hUg†vr}ƒ–ysp‡…|”v–›t‚ž¯‘–§˜thš¹²­ª — ´C -Í‹evŒxjh„ª™¨§²¥Ž‘§¸²›‹šŸ…›¯¯}yxš¥•ž°¢”Ž¬¥yx´ñ&ä¯}mwˆ¥Óìåªw’tz`fk§Ÿ–ra”±«‰ªÖ÷Ü’†zfm‡xH1Yz¯Åéì¿‘fnŒyuŽ¿¿¼´µËÉÌÇùöáÜææ·˜„”°²¶©¡®Îо¯Ç³“Œ¨ÝìË­—x—¦µÀͼ¥œµÀʺŸ…”§©|R3!#?^IÿêD–áõÖz‰’¢Úè¸WÞ‡pnbcyvTBWcto…bP`bmx}‘‹juŒŠyu~‘’Ÿ¡¬£¬œŠ_UÄô—˜ˆ¢¯©okjml}Š}p|¡¿Ðǵ²§±¹¸¤ ®Â¿¢“’o…·ÓÆ·«®¾È´••¢¤±ÐÚÅÄØÍáúØm†Š¨È·©„¤4e(t]Tf•¥£—oo§¾ª‡‰£½ 謟¦ŠdMg{lUoy´Õæ¿°”€Ÿ¬ª“»ñõ ,KD(ìíع—•¾àðæÕÈÒæõÙн±Ž™°½¿¤¤§Ž•¦ª¥¶­§–¨«Ç¹»Ã–zŽ{g[>/Dij* Íe#ü"§rî7‚¥°|a|ÆóËtØvgdVmjPFOo…‚}t^Xb†‚Ž“•œxWep“šœ­¯–~vnO‚½Á¤Š„—¥°²‡z•||t“¢²¹®ººÂµÁϾ»´±²Œt|®ØÙÛÄ­çpx¯‡ž¤¿áG›PžÞГv‰——ž ’—øŽ çHVrd„¯¬usbNp¶Éż–›éôů¦”vZm›Ï¬ƒfm”ú°¨¯ÁÝØÊ¿Ý;1<moldKP]M7 -$-^RôÜçô÷ñãÏ°ž—““•—¡ž¨¥¢¥˜ª­±©™› ¦jakaXktmy…”q7ÙYçx3bàQ|Ý’U³Á¤lÀзdú–zk[„‹lY?R}ˆš‘{…€o~–ž¤ž’W:GŸªz}«¬‘†Œv”²®žzrr„žÆ¶š‰œž–“¹Ïج‘Ž–®¼ËÒÔѼÀ¢’  £½ÒàïõèÑÑSãÆ6Èœ—µí5¨ ½2᪠ÖÚ‚djThuÅR·#;E1FAl»Í°U<W„¬®·ËÜûïÙ³ž•Š†­Î«wR?KlS†²ÑÓò&1:9G+Fz’tU33Qd~ta_t{—Šƒ]çæñòîóá¿°®˜„¥´« ›¬¯ªÅÒµÑΤ„uehhw‰’Šxtu——™¨™uNú+Ök-22Gsùı氈˜¶ÁΞ%º€mz•ŽuHEq°¢’œŸ‘o`‹”š¶ž…W)O…”eª¹®¦˜˜ƒm’©„zy{„½Œ–Ÿ³«–Î^¼ZÂ|y‹•³ß Õ§¢™š¢½»±ÊÜåóóÓñN¥kÞɵ¼Þ&‹Ô€ÕÆÈðé…XekŽ¦^òF}‰{4<R§õêКhYuœŸ®íëáÅ¡Œ|dpZTgtzxCS¶ùý -%\†Še=Oˆ§‚XBIVi•²ž—‹ƒ}T&âø& þéÐÉ««ºÓÙÀÃÜÚÙãæÛÕÔ“spu‹Š•ÖåÙ±¢±Ÿ• ‡~kE#îž\Ìs*箧ÚÖןÒÔÚëèí¢Åž‡‘¡—~``†©µ’™«Ž‹oU…Ž‡» zZM[]tš¢·¾©¨§–tUgwŸ´›rp…¢ŸÄÉÆÜO '“ßbkƒ¬õ>=ï©“ ¦ž«¤›¬ÇÌÊ÷ûôèóÜÍÅ×ᲕÄéôÔ¬˜’ž÷pze‰¡µ´}GF}ÂÿÞ»¥¨­©ªÕ÷õÞÞÝ›|\P$)Gs«ÇÕÈj²8u¢§švPStŸ­}p…‹™£ž“p`SC8 ,úäíþö÷(ðøþðÑ·ÀÒÖ©wºÃØÿôÏ­¢§‘žª–‰{xW4àÕ¤‚øF?‚*4+¥ù ïáŸJ枪§Šcwš°ª‡š|jqdzw]†“Ž†pKO¢±®³¢Ÿ„hal“¨ÚÁ…|“›ÏÁ¾ÑäÏy.KÏzo}£Û)1‘Ÿ}~®×ˆ’ÆÝõö¶±qgõàͼŸ¢’˜Ûíœp~º#½x(T³ÌÔÂÀ·o'þF¤û ß»°¾´¦—¼ø'"íº‰TB>-0a½öüøË !B3=Rn¯Ç¾ymŒ©»²·ÈÆ»£›Ž…hG>?Q[?òê êÑËÝ+, !ÝÒÎÅ›–Áçᄃ±äüßÚ½©¤¹Á­¹¨š¤¯ m^QDS(•ô6”E4XÍcQK/Æ ïªgΰ¼¶€z¤½¦yi…k|qNJ>Vuhx‚_e˜ ¯¹¿¤…ƒf‡}…¿Ãðݪ™˜§µ¤­Ëí¯›ö°Ž‘w‚§Þý¿¡Ÿ˜Ÿ–’—ÀÔÑÊšcq›²Ç½­0òÚ³‘’‹¸È?TþŒs»R> yåÙ½»³¼¨‘ƒ?= àùÝ´››ºÂÊÃÅéË©‹[J<C<Šò.ý A,RR?8V‰–·ÛÄ©ÊØÒ¹º¿Ã¸²™y{wWOY„©—M ãÓõØåòïÂȻξ¹À»Æ´ÍýØÕÓ¾ÛàËÀÃÉÉÚÑÄ̪œ¡¤e`v{t^€˜Æp{§¨y墷°~ûýùÔ›NòÀ©º³µ”žxq‰–zUB6:Gxaƒ™Œ‹§°¥¥¨ „”ey–­äÒØç°—šÄ‰ƒ”ª´Ãú쩇ˆ‡—šÄó姥·¾¾©—ÄÏ»¨­«yVf|Ÿ”¶ÿEP Ì ŸŽ£ô÷Ãçd:9×ô  ò°’¦¡~wrc2B‘Ⱦ“™¯·¼Íê &ìðÜ—„˜¥™}q†¸óüCiWg‡y\Ls¹·§ÁóãÙáǼ§–™™²Õ£„m^€¨Ç¹‰> 7MINB åÅŧ“‹³ÑļÊÑÇôüâìùäÔÈÀ¸³Òæ×»ºŒyaXntt‚xIÚ(Æ¿ëÝŦ‘¼g0þý¹öâ¥m(ײ²¯È ’•©š}’“mO`d]T†¼²  ›¤®§€Ž¤ž“ˆ~§¯·³Èà·†±Äx{t{j…£ž¥Œ—°ÃÃÎãâúÄÈÆÔ½£²¼§œ¢§}iei¨¾ëÿëË»»®£Ã!V ÈÁý†Dþº2;§…‚}rQV{”„žÃÔë-t/îÓ¢‰ÅýÝÕÞö -^”Æ¿»—|Š¸ÑÑŽÀÌÄÀÌÈúÈÈäýôѹ°›ÃÑÐÜɈbSWiz‹~a,ûßßÇ£‘—™²´ž½Î¤¶ÕÞîÿ ñßþ°¦Îÿù¬ƒ…dYCZ†ŠŸˆc e‹úÞöá¡}·üm{¸€Ð±lÒµ¬¨¿£Ÿ¬®˜˜¢nM_pp¯Ë²£•‘‘™›…‰¥°ª˜‚“…†·åÀ ©”muxszvsŸ’£ÄÁµÅØÙ µ«®Ãñ‘¥ª£œyŠ› ™ª¡žªÃÞѳ¿ÖV•q̧@B“Þ!(8Gû¹‘…†›••ŠbPs~‡’ÃBqŸªŠ=Ç—¦J{xM$7l”˜‚trdu¤Øåدœ†§½ÄÔãüçíÝÆÚåíðóþÚžfiˆŽeLLõò϶¯ ¢”–¶È³™¸ÊÒÓ öâ´¶ºÂñÜ€\„ŽgPVz€—ˆzZÁYçáþÖ¬Œˆ~ž&P&¢£‘BÓ¯…¦ÊÁÎÁ®­¼¦w}‹—‹’³ª®¤•swŠ¤³³¥³§ƒ–š„¬ÒÁ…]U|v‘ ¢¡˜’’š—Ÿ¨µÙã¡–©£¸½”t†©¾«¬°¥¯¶ ª£Ÿ¬¾êЯÇh”kñŠ“%š­ÍÕö( ½—`Rjq|s]CVœÜÚáEm’‰”{5 öÄ¥ÖHnm_Y@1J‡m_Weohy¡»é÷Л{ž××ÔÛäòÕÖðäØß¿ÒÿÒ¥v|Ÿ­ª«|suU1ïìì̬‘|€ ¾¹œ’“³Àéõåů¯ÂëãÅ–x‘‡~g^j‘•|hV+žÐ Ýßá¼ v|‚œ£ -áõ‚µs* -íÂ¥Ñçæã×ÏØ×™ŠŸ´r†«‹œg]uª¥¬¹Æž©­lƒ§ªhID›‘ ±¦’†y—Œu}•¸íð̹¡€}—’vpp’³¨žž“š¿ÞáÔÅÊëéËÀvgþ©Òg=£Âªµ»²Ýýﺆf7?]|zd8A¯3lkk~mujx|U ÿ常Þú9]“®­€cr“—‡•»Ñ¸™š Ý) -ÑŽ ÙÜ´²ºÖÜÓëä¸Ã£§ÛæÆ©•‘´ÍÅ«¦¼¨†gaL?îÎɇ‚¯¥ŸŽ£Óß×µ¤±Ïöܦ¤¹™x|pUq„‰xn[:9 p¹Úý÷Í°­Ã̲¥õ»æØŠ²I ôÕäéðãé𳃟¼®‡w¤—“†a^d…¦¨˜™»Ñé¦ioœ»Y[Šˆˆƒ{tndq}{lv•®ÐéäË¡Œlt‡‚€na}‚‡‚š¡ÃíùͲ°áøغ¿ÿ$Äí¯„2œµº­·ÅÒÕåàØx|jVVTaoRšEˆ˜™¬®Št/ÝÕæÍÎÌì^ÎáÁ‰Š°Ç«®Ñùûá“­Øð -¹—´ÞĤ¼ÂÌÐÆĬ³¯©¼çÙ¸«š•–ÂäÑÝÌ¥”€ ›Qèâ¢x€¥™ˆŽ§¤Ô÷É¿¶Ìø% &Úæå©pkOWwvorwosiuÃ6 ÿñÕÓÜëôË—Ú›£ŸVaßÓÛÜæ  $꬈”­•€§¡wtoqj†¡®µ–¨ÓΆ…Ÿ…´Ë³“~jp{‚ypefxœ¢Ÿ¦¯¦ “}^a‹“Œ‚ƒ’hi}•¨¦®¸½Ë­ªÆÑι©¯ŠÚ«ž\¯À ¡¡½ÝÙ±¶¹¼ŸŒsZB9Rl†ÓbÚ¾¬¿ØçΤPﶿøãæ'xßù໕’œ¼ œ³àîПŠŸ³ÒñÊ”ŸÑóÜÓë°Ö×´±”°Ðã¾–Š…˜Äö 㶫©¬Á§h.Ńu™¼ª£Â»Äðéïäü H5ãŠuv_w‹„“ª¼ª¡} p¯.ôÜÙϾÅäâ’p«‡†’ýùλ¼·Àì *¹“…°Áž°–oyŸ©š—›™¥–ª·¯m±§ºÉÀ²”™œ™š“…mdzŽ§²µ©«‡ŒxmŒ×ö°of“¬¦„ƒŽŒ‹Ÿ§—Ÿªº¾ÇÆʺ¡¡¾~•bª´©†y´ÃÈr„‰r]i`Ucz‰¨×&ŒòÒ›Ÿµ¼¸£bùÀå4E. R’»¿´©«ž´½¸¾×Í¿ª°¬ÈÖÕÖÙÛ¸žÈÞîïÒŸ–ÇïÍ¡‰€²àʈ±Âíù÷õîÜ¿º¿Æ×íФl9êÇÐü õòòRW3äÛ?>Ζ{Ž¥®³·¹¹µ–PÑ"‚ -߸™“®Þ㹎›å{[XïñÆÂËßÄÑöØÁ¢Áɬ¡˜{”›œ‹wx”‹wv˜…šÝÆ®ÈÓ¼¤ľ®¤…ƒ‰|‰Ÿ¬¬±²¡£¥ª¦Ø!5Ýy¢†|–„§ÊäÏËÞ×É̾° ž¹</I¹¯Œ}r`fqÀª~`N<=grr~ªÖCmšäÅzz_Jcg?.NŒ„qf}‘°ªšy…™—§µµ°ÈËÍÄ´Àäé㾑¯ÂºÁÏßéÕÆ´¯Ø¸ ¬®¦ÆÏѨ‘¯ÚóôÓÑÉÇ·¸ÆçúôòÞǾ”ae^9$6Jn–{6 ûôñùúô 7 ø°‡q‚¹´Èƹ±˜s!¤ôaΪ‹–¸Ä¤š–•²EGIÒñÛêêüøÇäèíãÇÁ­¼Ò¬„ ™‰ƒŒlxs‡y„²£«çâ½ÑÌÒ®²º®…zˆ–—Š‘¢­¬£ ™žª«½æ'*ë«Šutj‡Œ›¦­Àí':=Gݼ£–Š™ê½Í–Îœpq„x``‘οŠSB3Ev•¡­Ú7g”µïÓvz>3_gŽ•¦ˆ•¤¶Éžjr—³¼°©¾ÖçîïؼÌóþܨ¢ÅÉÇÁÖñóÕéܪ–ÐÜÁ½ÝÕ¹Ÿ”›Ë×ÞßËÎÇÆÒóêÕÕÑí úâá·aby‹ ¢–POB$ïûæÕú 36?÷œ€‚‹²ºµš„—œwq¿AÖ–z˜¸«Ž~•ºU\ZíÜÙüïÎÏÊ᳡¦±ÄÁ‹‚Y[u~dv†¬¶¡¤ÃÄŽ©àÅÏãé¹® Ž†ˆŸ®“Ž•—¢–œ£¤Ÿ©¬ÁÝÓÊ¿®zt‚”£¦¯ ¾ò‚Õé©-ξ°©¢ºoz>Ÿ¾‘gd•ys£ÐÃm]Yq’§Éà8V~ŸÅÑ©‹¤>%kÀÊ¡ot}š§ÊáÒmv·ÎÖοÂ×ÜÎêå°´ßüÖ¥¶ÎÛ¬¨ÏõðøøÊÃÍÔäÓ¿ÃÀ—„w¹ùìÎìïÙÚäíǸÃúùæíÔœ““ºæåœpo}`ô ö8D4)äÌ«“šš–•±½ª]ðY¼Fú³…Ž£¥Ÿ–‘‡œÈ­Êšøùïíüñ¸±¿Äž§´ÁÚ§jl_dzlr|¢ÆÛÁ¨³©~m¾×ÉÓïÖ©¢—¤©³¶™ƒŒ‚’‘—ž–Ž‘”§´Êµš««¶°¨Ÿ ·95Ø¿;°­¬¯¹ }’¼À’ˆ”ˆ|‡¨ÑÖ¶•‘z{¦ \hH.ƒÄëÌÓèî«€§ïæ qŠ™É˺Çîþ¸’ÍȾ¼°¨¥Ê¯µÑ¾¸× ÿÉ·ºÀ¸½ÐàííüööúèÐѺ­››¤¹ÔèÿïÓìõâÌÆÁ©´ÛîÈÔÖ»—£¼Ý׺–¤«‹6 -5D2JhmK8;C,þ¸——¯³§Ÿ¥ŠizÏD×¥”›•†˜Œ£ ·ìݤúõíÙ³ÁÓѸº«§Æ³‘~ihxŠ°Ò㺘¢˜€gÓ»ÆØË”Ž„œ£–‘’ˆ‘Œ~~˜˜„t~nrr‰ª¾µ­²À½¹šœ›Ý´ÏE ¨w’ ÜÛmˆr¨×¾”‰hQ^ ×׺¢}v¤Vƒ~Y%ø eÀìëãñ-&#ê¢zœµÞåÖËàþå¸ÈÁ£‘ ˆ‹«´¡ ¯¹Íð÷àÐÎàôÞÒÏÕèñô鬩µ·¼Û÷ôäÎÛçÞÌÀª—ÃùßïÞÇ®Œ²©µ®šºÃ³vI:S>8V‚˜ofomQ0í÷¯¥’ˆ›¢{w®÷·Œ}o{‡˜ÀÍ»© ûâ—ÿöõûéÞýÊ¢—›¬ÕÓ¸‰Wi{ŒÈâƘ†š¶ž[e¨²˜Ãº||‚udzƒ“‰Œ„mxxy•œ–‡…™»Ã¯¯¯¾Ã²˜™ü[ï2¢ÖŠnmӺǨŠŒŸÈ¨pTrc5,i¯¼£Œ…½ 1RƒwR82MXq£²ÂÖùKr])îs˜¥½îßÍÂ×ÕÀÄÞ⺳¨´À²–‚¡ÃÎÕÊÓáÿçêëëÓ»»ÍÈÓÜÜʱ³Ä×÷ÙÙã"àÄ“¶ï æÁ²ÍéóõÚÅ£’Žž¹¸œ˜}ŽÁÓ Y@]K<.Xpffqklc3' Þ¤––œ¯¡|ôî⬃‹šŒˆ¥º¹¬®ÕÅwåÿñ âž‘˜¥ÖÝÜÅyl€€¤ÉÈ–kz§ mn¢ªz”¬{z~„{qr€Š¥»®ªŒo‚­äõÜÙꥣ¶»±ž«¾Å¬#Á8"˜¬Ö¤ƒO®¹±¢¢–i8 B{bHUŽ …›ê E‚¹¬‹Q-Xƒ¶ÓØì  íך}‡‚”Õæ³±¸°ªÛ  õáÔ×Ѽtƒ¾ÛÙÏÉÞ䯺¼¾Ðîïñúôôâû캺ÄëëÀ£™Ç ,ýéÞúÿᦥª¢Žªº®„‚~‡™¯®}MVa52(?U`nnl‹v@Ú¬¢‰Ž ¡‘$×ÛÇ¿²•ooŸµ­žõÙæ­,6 úê·¯¯¤ÄÙß⻋–r¨Ñ¨rZ’€d›Ža|µ›¨Ÿ”‡…œ¾ä Ê’™ÆùëË´ ‹‹‚‰²ÎÔ·¥(¢ÜdÏÇž¼¸ƒ¤²ª€qweT30‡‡gq”ŠŽµù:HOW‰ÎΧU$8<Q_œÙî±”’^ZŽ»Ç²²¿®¯Ö ïÙ¾ËáíƦ—”­ÙËÁ¬·îÞ¼¸ÕÙí#/$?.ô×ÛëÓµœ‹ƒ”ž¦µÄö ëëè  õ¼¼°—”om~–„¨ÀœqdkZILMRXjd[rtiL9鲂~” ¦FF@¿¸Á¾´”|Ž¶®³°Ÿž%&(àéêæï -ñÛ·£Æ´¹¼¨¥ohŽ´Ï‹Lmš†Hd’†•Ö¼´¸¡win{~±¯Â/²eƒÅÜ«“Ž…‡»¬«•‡é2M™£ÝwbVƒ¨©¤lX€‚aAsp‡§¦° y¢¬†Uz¾Êªy`qš—ƒ±ÃÁŸjP} {^U‰®°Á³¢½ÂºÔçäÖÈÏæäæ¹€†©×Ô¼¬ÏÝéÌÍàíý "öÊ·¸ŒŠxœ¨«´ÀÌÖØÚâê/<*Ͳ¨¨Œhlf\||š´ÇƯw^zvcTkD0CN[[?4)%"ù ‰˜¤°¥T‹yÌ›Ÿ«²¥®³¢¡ÌÞС´DP=Ñèâåþ&þÞ¶¦¶±¥¹¨”Šsœ´¤__…ŽLc·ÊØ件´«‰tgz‚¤>+LYŸ\où”–¢‹‰™Åú®•{Pˆc |¾Š„¬¦o­ª³ªœuPb‡²„q”¡ÂìÿO¬ÁË©zŠ½Ü༦¢®¡§Ç§Œ`SJ[†v™¬ÃÄ¢’¶ÉÁ³ÑíöçòÛÆÁ³¦¯Èéר³ÓãîòïúùíãÐÕÝîïòôáŵ¸¤œ¢˜Ž”»ÈåÝÛ¿²µÄãø2E.ýÕÇ·–Œ“yq„‰£Åº¬‘T4N^fO]`d\eZZW:/ãÒÉÄÀ±zÀ¸Ó‚w‚…‘²À×ÞÍÝÏ® Ï…‰VÉáÞðÿùÞº¨¶Ç¾Ë¾Š›wg|‘ƒW\~©~˜êøäÎÉ¥´ÑÈž}ywž&.Fe§Í˜DH©˜¦¬ºØ йž‚q‡½Ü©•v°±ö¯æÊÀ¯˜grý˜’ªÌìVŸËáõçű¦Öæà‰ˆ¤´_>8[`^k…“¢Ÿ¡­ˆ‹³Â©®Ü.è××ÂÁÅÈÕÍÝ·Ÿ°è ãäíñëÒËÍÓ«ÇáØËÄÁÌÃÄ°¤Œ–±¿øëƯ¯¨¶â (ùËÎǧœ¤Â©Žv†•šo+.F`WqŸ²¦s|rc@ENhXÙÄ»®‡ééâhJU`„çRT Ï¿¨¬À³Ø²dÅØñ õð¿³×äÞçÛ“–~f”Ž’xn•°¤èÈÃô±µÚÚØĶ™˜â—ÝbÁ¹(5£Ì昣¤ºâ5Ń–¢¿Ç·¡¨¬½‰Óßû’²¬›¦¬©“‚“±Ë±sah•â\ÆðÚØú -Û¿¥«Á´•š ›ŽnP8DUOE[qXDAkœ¤ÌÑÉÏôè¿ÈØÀ­ »Ì¾´¨®¸ÁîýÜßú ßÈ«Ÿ§ìá·­ÁÙ¿¿Ê´•|–¤Ûб¬ºÐï -éÝÍ¥¼µ…h“ò‡e]e`ht|nF>LUP¥À¹˜—€~Ž–…wfrp;á‘œ›‚ôå^EVbµ@ÝÍAÏ´«¹À§¨/ äˆÊ×ê þüêÐÚõÞÚ ktv‚£Ÿ±—’™§™x¤Êž˜$ؾÄÖÏÑÕ‚}â0ÛÑY,)=ŸŒ––«ö6*ËzËþÞ¥˜¨¡†þìÛnŽ‹ƒ¡¶´‘Ž­¼²zl—üj¸Í½¬Üóؾ¼ÇÏÒqxstmgcdU9 - =‚¡¶¹ÍÙÉ¿¬¸©”“­Óìɘ¢©œÅÖòÔ²½ûùü#õî캺ºÖß¼³È̸ª²Ì°g‘ËßÈÉÀ²Ó¿ÍÖ½¶“ˆx›Í·~K@Hdˆ«¦–„’‹€~•Š’™•¤²À¤gaom½Ÿ¥˜-$ -‚r‚»×HRðÂøæÆ´XB(§Æê!4ñãÛõáÜ°{z†‡®µ´²Ÿº®‘j…µš`覃Ž–˜©„ffx¬ÏÊè@q.Á¡~kuË-K霈¨Òàí˯¯¹—r-$†wo}©´²¤™¥·ÕÛƬŽ¬d‡¨®«ºÖ˯ÃÕÛÔFAZZOYWDOKüÙèú)h¦ÖÌ«´»©~¥­¡¨ßñѪ™ ð Ç´Æ߸£¥ŸÍèá×åÜ×ãàÒÌÔÇŸ—°¹–}ŒÆóð˪™ºØåÛÛ nuˆ–¥›m<A`›åè·˜˜fUiˆ¤½³›˜œ·¦}bxˆUÿ¸³GbT¼•©ÇÂœ©-·™ªåóLjÀjp_Î:V_A<!éÝÝØÔ±‡‰“£¶Å›‘‡¦½ jn©UÚ‘E>]n}}e`u¡¸Ûÿãœb^a_—-ŠAà´£¬¬ ˜Ž‘ÆÖ®™Eħˬ‘‚—È¿§—²ËÁ²“ Ë/z¹µ´ŸÃÉ¡†Ÿ´´fav|akgA;> ÌÈІÖæǦÂÜÌäîÚ©›¿ðûèض¯çöÚøâ©…‰‡jÅú áÓãòþäÆ—š¢‘ˆ¤ÙûìÙÀÁ×ÜÖÆ·nuoŽœ‰vu¦Ìbx^û¦…„zp´Âª„xy‚p’«“DÞª€ZÃÁæ—¦¨¬µí³š•¹Ô­‰d†Õ¬ÜÎC`OEK?*óÔÍáçÖ™±¢£©“‰y¤žw^«È«ÊöÍ”kYaw’€ŒŠŒœ²ÈÈ…UQ[•`ßʶ³„]kl¢èùôÈ̵2óÖ°šx{™³šwWZ}ŠŠ‡µf©Ä½©€‡¦¾©‹“¾Ã䓲ÁŽxl^$ýáêýNÈÒµ«Îï×ÈÜÌ¢–µçùóØÉʼÅÜÞÊ”uŠ °ÆúüîÿíÀÍöçÆ „¸Õå.;ûòåÉ®–|louqz›ÎæÍŸÐî"ºúÎmôº¦¯Ž‰‹¥¡~fjqg…tŠ¦¨q#Èx—‰˜˜‘¡ËÀ€’ °u§¸!)9ð6' - 6çéêâò¡~œŒt—Ÿ‰yyqˆlk­ä¬ëâ£to‹¸³œœ–ws’‡”›„•£óV} ɾ»¨˜vvõ5óØ -âþ—“¡ ‹_u¥‰xvŒ˜–ºû@€ÉÊÜÙ¾¡ÄË»•®ãÕ¾˜|¢¶—{iLÞ¿æB‡—µ’’šªÐçç÷ßµØã²–– ÓëÙ´œ­¹©§¼ÌÂÐÉÕ¾”¡ÝàŽ×ûö¶¸çóì稕°å÷Û÷÷ÜÐƳ‹VBCQdzzŠ½ò äü"eîÐ_÷ñÏ•hrŒ•€\DjŒ|y„os—³•eÊ–KD¡–«vtª›„‚¡ÕØ»š¼Î¿GNhý 6-ûôäʇTms]˜Â y¢‘|p_ìÜ•¾ôò¼ˆ€·¯ˆƒ’}k|ƒ’‚¨ö.LÜÇ·»½À·’Æ)A ÚÀ%ëcx’ž«yl™Á¹››«¹Ì.v¦æ üýܶ›Šq‰º½®eLliq_G=${¼Ýç½—®ÖôüÕ§§¤Á´³¸±Âѳ”y ÅͺÈÜË«†¬þáºÃãèòßíùýËÃÐä×¾Âõ궦²ªY4OrlžŽ€¦å -/II~«èÛ’7õÍÊ­†my‚zs`Rs¦¥‡‡—¸Å½•Dì¤DeUέ¯ªn^j´¿—ºø3Λ¡ÖÇÔ…Ç»û -þø øëÖß¹”KH~x’É·ƒ ®ŽwU}É阰ÿ2¯“ —…}ŒzšƒŠç[|1÷Ѻ¨ÈÎÔ¾®Òk*Ê–¦=N#kŸ¨«›‡_|££Šs|¢ªêO•­ÃäìäÝǬ•ierˆ¨¢qI?Rt‰˜uŠ|v™Ë½Ãáðô -åÌ̳’’…”¿²±àϹ°¬§š‡ž×ÓÏóáÄ̸ÑñÒÐâf.ØÉÔÛþÚÉÖÞÜÕÊ×篘¯©”k9Cs‡¨®¬Ž¡Éf“«¿õ®~1Á©¶³§—•œxy„ƒ|¥Æ¯Ž¦Â¼³¶™P­G™· ·™zcTiºÓ¹Ýr›1° ¥×þåáµ6ãõúñçϾÂÏé¿zu­¯œÃ¼”«‹xu~×ýÐåpëµ´‡„imsœ²ž•ÿ¾/Á““ˆ±ÊÊÅÅ |’ó|Z’Gšb ±·ž‹mSV{‚}‡•Âè%…ÇŲ¸Ä¾ÓéÚº³‘ft†«Îecwx‹‡Õä¹¼ÓÍËãïß櫼·˜¥¯Çͱ‰•…„»ãÊsu°è»Ä!æËïü ûæfZèÊƬÓÚ³¸ÓçÅ¥ÅÁ ±§‘Žt¿ÇÅ®®’k— ‰¾ù/'þǤrн² ¯³ºž–¡³““Ÿ¬’›ž¯¸­Y¶gí*ÅvTAhœÌÑË ¶JÀ¢ÎÞäݨòUŠêòóþêÛÍÕë ã°–¬º³ÃÍ®™›˜ž¹ÞûïçÞ£½n_z|dpyŽ‘žšìïó˹SDGr¨Æè.iœK¡Mk´‘˲°¾²”‰f}‡§¯¹í*iÂçÈ©¥£·Å­“‘ˆ‚pˆ²ÁǧŠ©ª ™¦³ÐùÚÐØèñа«­š¤¹Ä¸³§¨Ï­„q¥±¾ÕàÆœ¢±¦°V%ñß 6äÝÿõóÖ²ºÂºÖ̺«¶á©®ÝÜɾ~¬ÎÑ—Œfk–Ù$aNüâ»f˺²Êº¸¨«§²¬”œ’‹‰¸´z;Ò†$MOºb:F™Í¿ÄÝM\ÊÌâäßØÕ›MǼ -- ï)É¡ªÅµ¾Â–œ¹ºy{´É>ªúPÕrQadkw¢¹¼´±YͲ'‡‹68iŸ¼Ä•¨³šv§5¡¦²»Å»½²‰ƒ™›šÛ2u‘°´¹ºÑðÝ œsl•Ÿ µÊÏÆ­»Ÿ£ÇÔܾ逖ÆÕØØó廽Ùÿßѳr›¢˜—³µ»ÃÙÏÛʲÁËÐý(&âô%óõíѱ± ®ÝîÖ­¯Ùÿ'𯋔¯ä§ÎàÕ¸sSx¶ÑôŸ•ÅaÔßd_$þá’'ÏÛìÓ­¤¢›—’’‡­¼©ˆ~‘­¨ˆV¶_ z C4\¨ÙÛÓÑóåä×àÉèëêÑ׶ä2†#GH7 ñ -êÂÏÊ­§·¡œ°¸ ld“Á~Ô+°ÿ‹tmq†£´­®ªf!íò.uIe~ž­¨êyåñ“­ˆ´cyY°Œr‚˜¥¬ Šœ¯²¹þa‘‰¨áèëçìÕ¥ zk|ŽŽ®¶ÀÉÀ¸ª¸Èà¼yzŽ˜¸Ð×ëãîÓÔÐéè;°_Wœ¯¬µ©¥§Îûó³¯áÖäçÿèí̶À½v]‰…†¤àäËÜ#í‘ŠŽ¦œ¯š…£ž¸­]]šáÞßáà:Ð&+4/%ó÷ ÃDò÷ﻀ†~|‰…”˜¥­¬±†oz§ÜÊŽ>Ò„ûêÚUFW™Óäèäæ·ƒŸ©»îþß¿º×ô®ðÔÿ-A+ëÆä&ߺ¸ªœ°¤ ž©µ–u“Ê©à²)8™£±ªŸ”Š„|•IÙx–~sq„Ž¥áTµÁ$ʉ¡j–h–vWjnhm{€žËä*Jž~¥ÛîòÔ«¤Ÿ§jn‚´±µ¥Œ‘Ÿ»²zgyµÑÜ» ²¸¸±ÈÊÉǯš«ˆo…˜ÁØË©µÛð×±ÏåõâåâÐѤ†‹k{¥Á¥ŸÔòâÚÏÕÓžy‡˜¤Âµ¨·È¢Ž½Ñ²Øô3¥ bf[) õó›(öÔˆx••• ¨˜‡y’©Š|…¢ÔáŸTÎwI¿«ªC@^¬ÚÜ͸„RU‘¶÷Ú³ÆÞá:DSÉìíÌÝ'ꨱÛ¦œ£ ±ÕΦ°Ù‰ªžƒG±²·©—s[Kv3Wžëý´žv}‘½×ó,EC'ù›®—Ð_Œ“shk|uo„•§Ë"Idƒ‡v‹¯ëïÒÉËÅÁ¦ƒ|Ž†vtŠ“j…˜§…ux–ÑÇ¥¯¨‘Œ¸Ì㶱ÀÇÂÌèнªÄÒÌÄÕÑÙúþóÏÃ×ϵ¨–©ËïÄ‘x©ÏôôûßÁìýÒ£œ¨´Â¯€™»áóÐĸ£­ÉôãÁ¿öTäQŠ‹g$ëõœFè“ŽÃÛàÒ²§ˆigyŠ‡‚‚{f\÷†sQ`3„CEc“šƒdn]‰¯íýê×ÑȮբÚ¦èû éÔõ嵧¤©¿²©ªÉÓ­—¹š»[Åzp÷‚¢½½®ƒ\FFrÄc™GÿÚ¶š–œ—¥­²Ïîêûì±ËÅ‘‡¦¥‡˜aQ[i bbfƒŸœ´ÖàáíÔÀ¹~g|˜–†–˜¥‡Œ“¬ž“„‘µ¬¿ÜÑ«¤¸ÔÜåßÚÙÞäöõ ìñ±¬À°ÅÖÏË´Ãس–…v•ÄÖÍ·£ä(@ìÎÅÌ­”¡¼·Å­‹ev¦½üïÀ®š¾ÅÕçÍÙ6Çÿ>`zo4.6F05üœJúâö¹ŠjXdYWiŠyYFQ1à³…Y¥T0Gq„lKar‚˜²ÜëéçÏ¿¡žgcÚíãÒà粦ÏëÓϾ­–œ”Šv–©õÄZäý …™³§†cYGXe–ñ ðþÚ¸˜…~Žš¢»¹Ÿ£ÆÍÛí¤’°¸’£ˆT2,Sˆ ~„‹”•†—¸½ÛóÓ¯·ˆ{ŒÌɧ ¢¥“—Ÿƒ‡¶ÄËÉäÕÌij¸Ï çÖÏÉÎíâ¿„^v»ËÖðçÁŸ²ÎÛÅ·Œ‚¨¼ë!34ûÚǦ– ¸¼²«ÅÖÓ±Žw¨ÈäÒ¡˜©°ªÁš­®­3M8$Vo[:>@L98;#ÂhN4-# ¼i;32(/Qd~~‡§ŸqҨZ‰E"Hq‰{V`~¨°œ°´¼Íïò¾œÑ×üˆÜÿîäàöÄË,ѽ¯§~z†vqvxŒ’ªp‰‚pmWPhkm«ôïéùéÄ°Ÿ•¢˜¦±‡¯Þ!(Gͪ™”tupK5+k …­³ž|z{“­ªËéòÕÒµ¦¾É»¶š”¨·“{Ž˜Ðéܵ‘“³Êå×ÐÓãüãèј‹‹u}³¾êÑ´©ÍãÞÜ™‰«Ãý !)ð¿ËÒ¸”˜¶ÂÂÀø #ê±¥¡ÎÞÉ–†“³¡’ƒ„Ë+Ï[•kPNbB.;*2IN/úÆv[6,$×…`- 5?hž¹Á¥Šk¿r¤6<)=]¸ëž}™¬ÄÇœ‚ƒÁõÚ§ÆPbJ²æûúÞôöÎÎ <7öÙÎŬ‰|gjq ïÔ˜€{„Œ‚|ƒ¯ÕÚÎÙÐÍÓÆÊÁį¸ÈµŒªÊ0-H¶ŸihiYh”Œfb‘å,‹¸¼®•š›´Ù×ÕíïÜ£¯Ç²¼»ª¨’€”­ÌÍÚɬŠ~¶ßáéåÕʾ«ÍßÅ ‰˜±»°©§¨¹àËž³ÆæØÑÝÊ·»Æâìì "èìë±og–Áäþî¾” œ¨¥£“”¯¨±žœû|ìi´Ÿ_:RN3 -BEᬃyZ/Ï—M/#! Jswqz…™”„p"ÀW„*5(HÊPF×­ÁØÍͯ}„³­ÕõÙ©´Ø£ÈÛöîý Ûã&÷ì­Œyv‡kmpŸ¶¬—›žª œŒŸ¾ÍßóÁ¹¹ ¤¹ËÍ»®¥¨¬—€»4KEž©Što…‚§ž”¶L‹­¹Ç¹Ç×áêË¼Ö õªi¡¼¶À¼°{p‘³ºµ¯®®âèÙÏØËËãÔÔزÇÖž­Ãà㿱®Á½ÓÎœ{·çûìãçì¼ÄÅÁºø#,(ëªig«ÏÚâÅàè«‹_v¬³¤‹§»Æ¶îxß2rœŒA.Sn9ðó E$ñ«¦vMù¸˜k.(/0Ii›qyxŠ›w<ÜUg,K$lÊpˆÊæóãñ⟗¾¶«Å¾¦x¡(6XÖ$'åéúÿóʹ¢‘‚›¡®­Íϸ« ¬«¤¤§¬¥¶¹ÁãÚƬ§•ž›«¿¤”‘¢¼Æ°¤Ë|ƒS™³¨£Ž”“Žyw­?o“‰¦²ÉøýäìÕàÛôóõ¬‹°Æ»¦•|qv‘“¨²»Éõ÷ÊÁÍÁÒÝͮƱ´«´šÎèýÌžš™ªËêߺž§´îéÏòìÆÁȸ¬ß ,,àXl©¿ÔâÑŠy™£Œ€Ž¨šz¥Î åü)ewgSDIqkò8R²§°¶}h]':YN?Rhƒ‚¤£q8ø€tM—HQ…#o¹µÆçõ аµ¢©¶Æ r‘çÈþÄò,L`(ÚäÌÅé &÷ß²¢•­¾Â¨»Ëᕘ“¡¸µŒ¦æûÜ£•††Ž•³£™˜µÜêàÉØœ¯et—¯ŽdkÅ>Žº¾¨ À¾îéÂÎøúÇ·Ëƪ µÂ¥‹šª´´Ã¾¸ÖØÄÐÚ¯™¶Ê­­œ“¢§¡ÁÓèñÆvUj†žËÓÜÕ¡˜ÌøÊËýðÉ×àÆÀÆæëû¿{b‘ÏõágUm†¤ÉÚÔÀ¦•}¾ lÈåèAO?T>=Zj9CRö¨ƒ•»zì†YBZn†˜uQ`ucf—£Ÿ·£Šf@¢|QªafØ늑¥Ô)õÜÐÔßÝ»x›/IIÑôCM âçõÖÞíª•}‰{¤ž¨¼¿¢‘‘Œ™¨ºÅ²¦®×Ò½¥‘“‹‡Ÿ¿¸«ŸŸ¿åòù˜µm…š± ™¶ÅÄļäD¨ÐÇÆà ÝÆäƶºÖݶŽ¥ÎÔÍ´®§™°ÖåæßÖãÑßɵ°Ä§›žÁ¥›¢³¨§ÀÖѳ¶®¦¢nwœ›µÌÆÝÍŸ§ë ï")Û³ÒåÚÅÃàø϶•°âÍ|f‰o‘ Ä" íÂœ“¢ý;‡ËÒÞ)2GE÷G=3R;󼙥ÅkÝXcƒ¤¯hVosfj•«­£•…QýˆlB¶‚…Âй¯’sq‹Îú$2KIË¡}“ìÃð´áÑ;"ëøïÑÆÜá÷ñœ†…t«¹ª «¯¢ž¥±ÁÃÇ© ¨³ÀÎϹ›Ž¨ÀÀ¹¦¥Ç÷òðÿÎу™š¦›˜­Øïöör… ±¸ÎÕ¶¤©™‚ˆ¡²¸¼õþêÎÉηªÛä×®¤ž¬©”Ÿ¿ÀƘ™³ÍÓÑ¿¬­»ÆÉĉ©Ô㺪²¤¢³ÂÿäÌì(Ìž¯ÐúëÆáðȹ碲½ˆŒ™´ÄÈç óçÌ­Ø\°äê/'>#õÂó>B6@9áÕÔ¶TðȈs€ŒŽ{nX^^e„˜§|s†‹7Ô[zN¤zžÔ¼ˆ ¢uoš²ÊÑ5™€C'&Ê£©†‹sÚõÁÊüØÔæäØÙç "½ŠŠ¦¿ÉÆ·¦¯¶Ÿ›˜¥©¢¤­¨±Ÿª·ÂÍË£žš²ÆËËÎÉ¿’¢ðÝó®~œ£Ž—Š™Èé1Šy•›¢”—††™¥¨ ÍõóÒÕʾÃÝÔÀ ¹È¶hv{Ž¢ºíÛȽ¾×éàþ²¬¯©’ ÅÕîÕ¬³©¹ÓÕúõâí íÆåçÙÜÑÝÿáÉÍÐȺ¡ˆ¸ÔÓ°¡¬™£²¿ÝæßÓÎñK¦×'L\<þò Üä_Z@7C,àǵ‹;(¥vrop‡“xw‹€{QI‘ŸV#ÙrĪ“°£¡–‘’Ÿ£§Š•L.äÎJàÔ›  ß±ÈÒ´½é$ -ù鸨»´´¶ª°¦¤“„„…~yŠ¶Ã¨Š«½µŠ‘¬ÈÈèÒ«›¦ˆ~ÚÇô™¿ œÀœn^mœÖr‹”¯¿¨ÀË£–»ÚÛÆÑö À³°¶®ÄÒ¾žˆªŠˆy€„›¬ÁÝü¯°ÜâÌȵ§˜ ¿ÌľÌÅÒܺ’¥®¥ÂÍèæíçßÚÐÇî=!¾±¾Ê»§¨Åйž¡ÃãÁ®§£­¢©ËèѼ¡15EA<òÊñIwq<5¹¬nB:¬¤°’‰¬­•…iftih„\-ö‘ įdhwŽ|š´ÀÃ¥˜}‰Òßì -ÞáäA88Þö»ØÀÎ-' ÷C'ëÕŒ“¡¶É¶µaSaqw|{‰µÍ§ƒ|ŸÓèÐËØ̼§|y—«¨Ô»ÔzÁË¿ }`e‚µáh•ºÑØ̶̪»äÝÙÂí´¤£ÀÖ¨Ryq~±ÜññèؽŸËüà ”’¤Òöþðë𶋎‘ri’™±äóãáëÙÍØøëɇy¦ÅÒÆ´ÔÙ“jg“ÈÚΞ­¥•³äþàíó6ÌKWõù&@5ö+!8^`/1&ݸ˜aJø³ÆóÊ–£”ƒw~gZUtˆ“šYÏnðÛÊlSj€³Ò´°}gˆoy­ꉙº«°ÈÖúÂÉ·!øç÷àÛæð"#IIñ¡‰–³ÜíÒT:;RzŸ®¨½¡’‘šÌ æç ’›¢¯ÏÐÊݬÚs«­€fWoŽÙ.Rm‡­ÊÕÔ¯³Å§®ÖÚËÇî÷´ƒ¤¸»Ð‘Xe¡œž¼®›«ÆØÍÁ¡¦£ÈÀ˜¨¼Ðüþô½xVd¨¼Æ»ËöúèÚÙÚíýîìÎÎÒÀšÄ÷éÁ‹”§‘‰‡¥«Ñɧ”™·ã -nÉ(:ðþOg`>$#>IG.ñ±¦²²–Cö½ÈíÀƒ}{”€dj†zs|QÓgêøý™Œ‡›£–ª¶½²‘€Ïơ̂ܛ·¬˜ÁÚÙP<R4üãÚõ=)&1RY+ùv_u¥†DçŽXGXq¤³µ§š«³Çî Õ²Ÿ³ºÀÍÒ˼t¦‰æ{f{–’‡v}¦PU`–›¦ËÑÂËÔ°›¦±•¶ë諾ƾ²”s€µ¾À»»´½¶±±§¥¡¨$êçÁÐùûÿÎ_h“ª×áóöæøöÿßÖ ! ôÅ·ß±±¼Ÿeq}‹ŸËÂÄ¥°¨£Ž³ÕÂå /~Ä &,(5L7&1 J]0å“š¢©£¡3èй»¨¡•¬²¥˜‡”›“šN˜ÃÀ¶´´š«ª«ª˜—]XÅbçÐÜâнÌËÆô‘À¿ñ!$éïÿ870=D=óds]|üûxñ(׬†lmˆ¢¦¤°¹ÄÛü Æ—¿Ä—ž»¿‰q†€È~t‚˜ž’ƒŽ¦]qtŽ™ ÉÐè鲚¦ÄËÁßÏǼ›ƒ³šµÑåç÷Ø­žŒ‘ªµ¯Œ…ÖüðÆÆöøøÍ‘“®¤šÄìÙæäêîæÿýé,CL1÷™¬µ‡xlXUr†’­ÓêÒ¼©²®¸¯Áǹ¼ç/pÃ+$'/+ -3FE$:A䪦}rvD÷ß©ž½Øµ–Œ©¬¬•¨§¢¥Q)*àF( ®¼Ð·ž‚ŠªåÞšs2q\4èüúܶ¢¥»µ Uß -'' üöîÞQIDG1픓—¸…Ô*&ôƱ”‘Œ‚ƒŒª±ÝT|!¼•„‡Ž™¡¸Â¤””-£“¿­·ª‡‚…÷ƒÄ§Ÿ±•ÅéñëàËÂßñãòÿ³Ÿ«—½áʱ¬ºÔéôÈŽer˜¾ÔÆŸ|‚Ü2øïäÉÑæÕ¸Œp}ÒæиáÞÇÎÿ$&@ ™R_ewT;n³¾¿Ìâ统|” °¢Ÿµ²Êÿ*rÝ$ 04SZ^L "ºšÇÂZ*=?9Ä¡™¹Ï«–~sxŽœ¤–”šŸQ$Aa<û…¥Ã¨{Ñ0+³’7oò6ìóúÞʱž¥Ä¿¢Iœ®øêôïËöDRK=.ôìÒ½ìÓò֧賮³©‚m^eqx¼ògé(Ì®ŸÉÕÑÈ­¥ž'“°ïݧyu‰³ö}ÁÁ¿Ü¼€šÐéìàÚÒ×ÙÍ¿ÐÔ¡y¸äóÙÔ²¥Êé±zl¯åÖ¾¨‚ªÔÌܪ©è3'í½|ozËǵ¼îðÖÂùó*æ–Ë%4ЈgylUW±é¬©¦È¢gf†Œ}h~¢Æ·Åîoã19#ó@l}T(èâòÑî°=#çµ›˜›º­ww{^ctŽ¡¡¡_8;û^Nmzª°‹’šã.2ø¹‘¾i ʳµ¼´´±ÈÌ׶Û;ÛâýòíæÑÏ 4>;õíÞÇÀìÄÁµ²°Œv]ct¼ÎhT­öþ¾ÉÖÑü -üÍ‘“$^a¦‹atˆ”žé`ÀÒÊѾ™®ÒéêÓdz»”˸¨ÞØÑß¿‡dƒ£Ü°ww…¶°«¾¯Ÿ”«ÐòÑÆŬËü2"èLJ€ršÅ´šËØîÙ¯ªÊ§ÈÞ Ð€_sloª×³„_t›™ ”~Vd‘”¡«ÒVADH6*4 ûQrH èß6êÞÅ;ýÿ彚”¤–y˜«³«³­nHF{¥£Š~\2íFK1|hvz}´Ø è·±ÛçÝÉžºÀÈÐëíÀg…‡èõãÌÝÛÓ×â4D"ò¨ºæòæÌÆÛÒ±Œ‡‰‡¥ÒÙøN‰')»±ÇÐÏ´Õ]Ç‘|ÜõÛL6E`}‹¦å+z½âÏÐõ¹µÀàÞíÙÓÕÆ­¥Ê¹~zŒ°Õõê´|Š–£¯Åü·œ“ ²²­¾ÊÕáçèãÕãø3)뢛­¯È§zÁ@1éÛ¾‰~ÇÚÁª©ìæa}™¹Ï´…Ž”ªÄÕÃ|RyŒ‹§»BYMFBHYI!ûè<( ÿ &óÅšdóÜÄ·¼¸Á±«‘••­À©_16Zƒ˜|€P(Õ(³sPT”Ïú!Ü¥“…u—©¾±œšª½ÀÖó¿ÓÉöÕÞÌÕèçÛØéñ*S8!¬¥¦ª£°¾´ÉâשœŽ¢—ŸÂدm}¥ɘÀÜÀ˜’5äz ¼Zgf{ŒœË%`”½âàæêåƬ«ÀØÜüõåÌŸž£žn­ÀÝéÜÀŸ˜¤¹ßìƲ©¢Œ~°ÛÐÎÜ*ÏÉÌã3bÈ­½”®’`œ$ôÖ²„ª½Ðª³Ñ¸…€•”±ÇÙìÉ°ž ¦¶¾Ÿ‚¡Í½»ÿqãD;>*  üîÉñ*AZvBïî´gjZôÐéöñÍϸ¬–„…•¥hA7@Uzšœ†F¾Í¯ÂmNW‘»ò,ñnƒ˜ ¾ºÄ·£žž©·þúϬAUØëìí×ííèñ'aZ<¤±Çª¡°»Ÿ•¥ŸŸ“‰”¸Ì&±&Óù¨ÃÞî­Ó$A㤜‡–™Ów¨¨¬¸¨ q”¶ÉÑÕ˼Åĵ¿ÍÓåöùÒ°©¶½¿‘—¯ÂÕÜïÜÜ–TY‹­ÂÄŸ°Çª•ˆ“±´½óþó°¸û!þÐǨ`]un‘Y!ßÚ;¤¥Â´¬©Ð䱋¦¶¸±´Ð»ª¡œÅå´¬Þ÷ðáRÊýÿ , ɽÏðÛ÷=bsj'æô8æqD2ñí÷Õ­³¤…m~Œ‘¢g6MfWŠ¼¯‡A -業‘Ýxu†”½þ*´{†˜™­ºÀ«•ž¨¤½ó)éØ´Ê´ ø íÍÃäíò @5ÿ쪴¬˜“ƒ`Qer‚¨¡Žƒ•¨Á÷X˜FíñêÙ̪Š… ¾À‘zy‘ΛÏi’¢¯½‘»ÖÎÊÂàè  éÜÿñѽÃØÅÆÙðˤ¡»âáàΗ˜fYz¤•‰‡~‰­Ã™“œ¿ÃÓÍп©úaD%Ì’ª—XX¹ñ>ƒ:îëéàÈÍÖÙµºËÙ³ ·²—•ˆ˜—“ºÖãöèÕÇèïÝï|ãݾÑòô»Éý0;;.>ùíôÝ{+'ðÛŸ¡›ni”yp‘jXrvhÊM Ó¨b’~ ôº¤vwˆí7^ ¦ˆ‰}®»·¦²»«¨Ú/È»±»1hµ÷äÁÐéóÿ -!öõ‹€„{sdWJOeŽ¡Ëßѹ³š©Ò  ìíÊ£ˆ—x\~Šv}dq–¿Pm/Xb{Ã@±ÙñõáÅËì÷üþüØ‹|±åäÏß  -·—Ÿ¶É¾Ä·¬”ŒŒ‘y^w¢ÏøÛš§ÑÚÔéôáÜbY9Ú°½Ù¤ƒ R^YáäÕÃÕûûßʽ¤¨ž“Œ‡‹x~µÛå´ÂÈÛé -ˆ¶§ž¯í'æñ-JE-#1öðͤl3)>?ëм ‰…‹|MYs„†–Œ»ÚpìÁpPDí檣‘Ê0¥ÁeÕ—qy¢¯ÍŶš©WAÓ¾½£ßÌ7êúçÁ¾Ñèíóø #‡snYUZ|—››­¿ÛóìÚË­´ÔÝÆ·¶®£ykhqpŽ¤šeTmw£.xŠ¡·[¾ÂØôñDZ¾¯«ÊãÐ˺¥‘¥ÈÙï4!Ó«˜™­ÇÍÖ²¦¤‘…xjÎìôÒ¨°ÙÞà -ôÍÒú øõ¿¯Ô,g\7 -ÌÐÆ¿ÑÕÝξ½Á¥›”…†}v{¤ÃÕó±l§ÅÙù8s¯´²ÖôéåÛ1#ÿÿ., â뻌§jrpLE5Ϙ…ƒr&$€©¬ÄÒɶ[ïDzjõ »àÿýû«m„î¡xYUˆ²ÄȽ©ªæ`Õ²µÎ½Çeš¨íöÁ¹ÄÌÓÛ÷)1™†…|ƒ£ÞèÕ³·Öøé¼³©µ£«¨´£ŒŒ§°¢‹’ªÃèÔŠd]s¤”Íå -üŒÆÂÛëÕű«£•¾œŠ¬ÆѬÆþøóÜ·•¥Ò¼¶Í°¥««¨‘œšÓäÕîñßÖØØòêáÄŸŸá 5`9 æøYoC襕˜Ÿ“Ž ³Ë˽ŸŒ¨‰–ŽŒÙ÷Òƒ}«‚JžÃÅ!‘ÖÕêí2ùÓÆàØô -ÜÊó0&Ø”­¼´ƒ„c>&ù´•Ÿ‹e5nµÃÌɬn·°»±7°×ûå$9OSw^·{oaˆ¡ËìöÙÎ$È)ñ+³ÒÔÁøù?ÜÞ°´¯Ãñÿ›–¤«©Ëñöçä×êÙ­µª—¢½Ç®ˆ„ÝÀ¢¦Àï ÿܾ§¯õÚØlÄèÚÇËÝåËȶ¯–¦™†“±Ë»Óüñ»²®ÉÎíØ£´¯Ÿž«­«œ­©ÂÙ»¸½ÃÂд¼ÉÑõ¶.!QXJf|ARgTÅ•x…Œ¥®¯£µ¾žµÁ­ºÎ¢pvÂÖ±‚€Ÿó*ôýêþþɼÞõæÌÊö Ýá >;!$ñ»´¯¤pPI<误­£”ƒaG€Å½¸ÁŒ7ã±ÇîðrS.©rr¦×âéaƒQUd¹“ˆ|†¢Þ+K è#ªî¦ª¶¦¤Z®p»½µÊý47“”œ ™¡ÔöüëîêéÌœµÉ¾¬·¼Ç³š›á æꛫÇ!SN%î¯Ã‘£<i†Ñ.E†ÌÛÔÕܸ««¡•š®œ «¯ª‚˜°›œ¹Ò×ßâüߎ¬¨š“œÊ½³š¹ˆŽº÷ø૳ؽÔÝÛ6N=C`dtŒy‘mXôš€{†ÓÛТ ¥ˆÁÙ»±¹§¨¯«¶¼¿°—Ú<Pu·åáÚ*þß´›Ì⪲Р- -ø!æÄ©˜uG  -ýæ·Œ‰—¢¤ ‘˜ ˆ_2$ñÏe~[Å—rŽ¡¿õZæânÇ°°¥¥¨Ý#8ùÐÞ &ÒŠŒ™‘oä•Ãà8On]J'+q{‰Ž…–±ËÕÀÃÍ×ÖÁ¬¡ š®³®ª¸Ìî⼩ºÌõ7'믠€ÅHQÊ-JÁßȼ»¤©µ¤²ÆÀ™¦¤›†‘ÊçêÏÏ·¦Œ¥Á­Àº¿·†¡°ª©u‘¼»½Ùùà»ÂÏ°²¾æ#FHiŽ€sT]rj>ð⑃µ±Œg]…¨¨Àž¯ÊȽ¿’z¯¨“¯Û`|žÒðàîëÕ·ËùçÎÜñÿüðéù -ëÖ¥›^1÷âÏÇé÷Ý¡{sˆ©ÆÜ¡Œc`]cbJ3(ù„ñ)PåÖª’“ºø39 ðîÝÎÇÀËÒºµèêdzµ›§ÄËœ~}Šw™{É¡Ê•ÓÇe)0;……“‘¤­®¼Â¶·¯¸¯¬™§½Ë×êþéÛÍÉ×Ü÷ôÅãïɱśéwUo¹.~’£Ê´£³©¤¾ÆÝâìå·”ŠºËúØ¢•ƒwÎàÐÐÀîyw‰ ŸŸÌ×ÔÊßÒŽÆéŦ¹ÉPd{ˆŽu9"L`8öÁŸ”‡y˜kk•ª¶âÙÁ¶UJZikš×/a|“ÇìÎà0ûüõ û(A÷¸³Õ <:Í´žj1ÖÓ¨ÊÝ府‰Š¬ÎÓµ’bd„”€T"Ôm¥±ÙÞÍ¢•­ß뵨¾ÁúÅÉŶ –“™»²¬Ä¼|œœ˜+„ŽÍÏO>ó“O*L˜™¡·¯œ•—œ«ª±®¢«ÁÈ˾ÅÖçÑÓâäáçõôõëÒ§«£¥ÀÔo±WB`¾fº®´Àµ¡£®·ÍÊÔëì 烄½¼®¬„˜”‘ƒšÌÇÁijµº’p{Åë°®§Õåï±ÁäÊ™œ¼D]iˆ¥–bRUI#䯒{¤§—’©›‰|‹¢Ääô -Þ›†{^M[˜È GRP‹°ÒØʸ¼ü$ñ74Òá Uc<Ù´†0ýëÀÊËâóôúᾬ©¶±³¸–‰•¦‚3ûëÒg}tâÀÅÑÀ¥µ¿à㽧“Ÿ¾Ê¹¥ €yºÉ½³¶¥Ž’¥´›²ïþ8¿â‡‹Jè„RY¿ÏàÚ͹«–œ ²¯³¼§¹ÎèëÙÕÆÁÉâÛéçÛ’ž§“ ß|¦Ul¥”âѵÁƬ©ÀÔÕÂÂåüñÓÁ‡b}‘¤½¹°}o£ÖÝ»¢¶¡±©”ŒŽ¯Ã “„šÁÏ¡ª»ÅÔîËËÛ[`v¸×­‡g[8 éÁ¡†i’°ž¬¹ËÃÌèÞ§¹ÃÞ/k ¿§Š¿öìÁ¦ÅÎ$ææ6C)3FI60ô̾döÙîúßÑΪ¡°³Ä¡Œ”U äܵ?YzíÕÎÄÍ·ÑàÛ¦‡ˆ•ºÉÃÀ¢¥€„¹ÀÅ®¬ÄÞ¿°ÉÕ§œ¤dÁ¨ Ä•«Ž.ÂUAÉüá²¢Ÿš«ÅÚáÛèѺÓÜÚǸȿ­ÈÑÏÝòüÉ•€–‡€œ"++Ÿ±´ÞhÌÉœ²ÏƾºÎäϼÇÆà׫’j`…¡¹É§¢¹ßçîÅ{ŠŠs€’p€œ·’˜¶ÈЫšÁ»ç$# ô1>i¥¹—€_tyå˦‚m‡™£±ÖÖ¾î笫ÆÝÛâ GVW€²ðúðõ õ ë ô+@45  hNðæÿëÙ®I FbA%+ÿþ÷ÿÿ᪥µ£º¼˜~ÄÐÃ&z-Ϫ±À®ºÛÅ¢‘—µâѽ¹ÊƸŒ‹ÂäÞƧÈú -5 ½”=PÀZo¹´WòIç:nFá½±º¶ºÎêòÞξ´¦œœ¡£·³­¯ÃËÅìëƈ›Ÿ¨ðº÷šÃ°‰Ÿ •ÔŶÒÑÈ™§ÔÜ¡•—¬ºƒ]\y«·½¼Å¾ÑÈŽ°ªekxow‰ˆªÂ®˜¥·¯±­·¹Ôàû·«à4Z‹±ÒÜÓ´Eà•ª³­»Ð½äîöÔ××½å TÄâå!>7÷6%âÿìàï'( EKó*,Þêþþî²`&U~‡W èèð äÁ¶»±´§²˜dº±›G³½E$ïħµ««É¿ “—äÊ›Â÷ûÔ«¸ãå៲%DmN㜚éÂëTѦcõ¦hù/n%èãÔܯ¯µÒËÇÓº ©¬º¾°Ÿ“–¶´³ÈÓÅ»»Àµ¢ªî„XS´¡‚ˆ¤ éæÍÈæÜ»š¤¢~|…”usnœ¾ÛòôâƧ˜€uŒwge•¬›œ±®š…››®ÑóÕÍ̾Ÿ²³§ªá#d·ãúäªgÛj†ÍÖêåÍÆÏóèùêÌXi¶á 0KZ]dF/  êÛÜØñ%=S<:Eùáõ ÷  ìÎÆ…BN†º•=ÿæóñçÏ£–Á¦~u”¥˜Ž8É¢mESòó¾±¹º ¨ËªŠ ò1Ãrº ×®Á"ï”z×H|ªxóÂît¦x ²oXò·„³ÛñÎååÔÀ§£ÈàËÖÀäößÒÒɪ ©°¥­ö    걜ÁDµž†“éD«ðïÑ××Þ¡^CWXh‚myª¿Ë°Ÿ²ÁÞÕÀ©›†meyae¶Ò¿Âº ¨·ÜÑÜÿ௙«”–•¼íA¸ýí ˆi÷‚Š±ÏßÙ»¾½ñ>™ÌºÅº¸Ùû+YfRRC(-.óÉÊõ÷×ìIyˆ^UH7ñÌ %2%2åÍ«~l§ïùzñÿïÍ£‚œš~]lƒ‹…Hঃǽë®ÏáŬ¦ÂÓÑ·¦§Ð8p(›U«?†9ÇÃ-‚•Q×¤Ô -0y¯@ô×2²Â_-ðÏË·Ý âÓîäÝÍÀ»ËÞÌÄòþÚ²µ¶Æ¸©¡¹ä$PðÇ£˜„¿”­ˆ¬±øAœÒν§˜•…bIZj‰›½¼²Àŵš°®§£–§ƒ]bw“ª¹·¶°•–¯Üòã¾ËíÑ ‘‰|w}ag«_ø!ï½kBm­±ÏÊÐè#1hÓ2bµfà›¾òíë-9 -ý þëÇÂ%!d}L(257CM[[Z6Ù¤™Õò×=õýãç‘‹}|€t`c^:õÌgg/¢·ÔÁ“—µôÜÏÔàñdÆeÁ|ûË:ÁêÔBݦ8øðöìTrEûå¾Âˆ–iKÍÑþæ ×Øàçã߸½³ÄÂÂÇÌ´¨‰±ÞÚØëú/5Ç´Œ€|…x‚!,4ºµ—Ü\š—†ž´¼§xjŠ¥«ÔéÁ±²³•vŸ²´»Ä³ƒBb©Ëß”Œ¥•ƒ…Œ—·¸¼• Ë˸¡‹ˆrv_JN“" Ûä˧L,T&Ñö'b«¼´õ7MO`0¤•ð(èöóïæìÚ¹Äüé -$(Q[YN@GND41Ghkm|X"úΗ‘®Ñ¥‡pH ùÓµ­}r|Ÿ¸Ž~b_5üñCúꣳÈɨ°Á ÕÓýÁ%ƒÅ‘7Eš*æ2»ÿÃWêæÁÊü6Mê`7*$?òÀÊ%$ ÖÔÓϬœŽ££°’~r‚„}‘§ÊåíýéÈÐîÁ†wmqŠŒ¡œæ¸ä¬©v™è;‡¸£³ÊëÞÚ¶¼Ï± ª±¶´¾ž‹fr€±»Ìξžih¯æÔ y‰sh‚ƒ}‚‹£§Ÿ¢À¸Ï°©¤ŽrVY€Ù_´ÄÚºoa^>D|ƒ¬æ1, ãѸ‹‹× êãù%îîÌœ¡á<ìÐã.00IeonmXGI?:Gvyki_(Ø¢Ÿ©©’t~{>Øѯ³Ÿyt¯Ç¼œ„{EïëÊÚƒÞÓ×Á×ÚѦ¤3Â|áÇ,ôU¼²I1ï5ùQxPûÕÎÚÐÎä -/)èâGíÏe&ìÙ5ûã¡š„dp–œ¤ˆxvu„™ª¸¨¶ÆÎǧ”°æÐ’ˆ™Ÿ›­ÍÎËYkF‹sœøAœËÐÐØÕ×ðÝÈ»‘gf‚¡¸¾´ˆlo}ž¦¹¹Íº‚G€´³‡ekU^‰£›ƒ|yš¤‰¬ÖçϹ²›ˆˆ…B[*¾Øµ¬‡fu¨ÈÙð1IR%â®j82G£ÚçëÓÒòþå´¬êòçÑÒýChoflmcnaK0!H?$'+Tn2ÐœœŠ{•Ž\1ÔɾºÇ§¡ª¦£”€Gì×W9%ÏÜÝÆÒÚ®ƒ¤‚r-â9ÒÕiñRªÀjõÞÕñÚ×ÁÈ×âØ»ÊöàÑ3÷¸©ý¸~!ã%ÔÚзŽ}­³®˜}{¡ ªÎÙ¸†€“›˜ˆ“Ìà—¡—ªÝåÊ" ⃨«ùGÅÛе§¡Ä«wWhW‰¯­»²¡‡Ž•˜ ‰²£[K‡~tbTKc“‡gux¨¼Ìèë̱¥£’|ˆr=1»‚ æΰÂÐãþ0ôÆž‹O,Bk§áúüöýöþÏÀ¹±èëÍ{‚WZ]GNKA0/N_Nꦱ‚ˆˆ|> -ÝÁ¾É÷ö¾™„‡z’‹[(¡º„Ç«¿¯Åæ豈³±°n`ÉýÏ´z|B -λ·—œ£ÔðêÎÖÖ¹Öø ïÀÉ™t½Æ‘-äü´É½¢†‹¬­§“pxž¸ØÎ漢x’ˆy~—·»œŸŽŒ½ßÞÒÛd¦ Ã+p”²«ª–‰vcu‚hf€¶»À³«Œª¨š¥|hi‰ª]Uq{„rK6Lƒw£²ÖõìÀ¦Áɬ—ePgB9x8à ÷ÓÏÝù"7"躞‡‘–y‚µÈñ&üóðêåÍÈÀ˜­ÞìÃÝ+&4M?%9*EfdÏ}' ìÃÁúàøûÍ›“‘ldx_ÍzV$¦¾¾£Å - öÎðj{ ÷,„·ª5ã¾Á¯·½£ŠšÃÛØÆÏÛÛûîöï£àkVa§‰0Áʦ×Øν²¹˜‚{Ž…œ¯Åä—Ÿ¹ÄŸ…}fOXy™¥ÁƬž»àקt…0|„Å?Kw¥°¤¤›Š~¦ƒtˆŒ ¡§´§¨§m’¦[f[stf`K¶°XT•·èÍÂÏËÓ»¡tpE&W¾ëáßÏÏæ"<?ðÓ§†ž´­×!';¾´¦ÌÈйªÂÜêüéÌð ö ÷é÷ü9SH4?b‘ ¬w‘¬º /DøòÉ›™˜fO_Uò°8þ·¾Á­à[mù'o–RÞCLAО›¸Å̲š›ª·ÃÏÎØðÿßÎׯ¶;3/M›“¯¤Êá⿲ÌâäлÂÒÁ««»°Œ‡›ÒñݨoLFƒÎáÒᾸÎýÍyL]âéÞiŽ©êù'ŒÒª±¾“vŠs”¾±¡±±½¦Œtt‰y©Ë¢”Šwbnm[Zj} çÑ~>9j®ØÜìúÎÆ´¨l?23/©S›¹ÙàÒöêæ%窄–™¬Ôö9]Mîç︓¤š­ÉÙöÊÑßïùÛðßÐÄÍàÝéí3]R/^ð2Ç™g˜Çï;M2íÔ×Òœ€qvwN5Ü‹Í­ìÔ³¢¹ÿì4õº§ôUZ+üÛòêÐÚÔ®¿Þ͹¥¤³²ÛåùÝâæú௑¢ûçò¦Ù›~²×ŤžÃ`@ëâê×»ÀÁ¼¬ÁÍèúåµ€bcªàãÀ¡žÎîœgi“ê¿Òz}rŸîaËïÈ …«´™ƒ‘€¾°¡¦ rdyk†¿À¡¦ƒ§¥—€tz‹|œÝ¹iUe•®²ÏôþÒƾ–}aRW+ó¦gÁ¿¾Ù!ÿ7ÛªrU†ÛÏõ0UWNÜØûÞž€¤ÇØþïóêãüüâʵÁáþçñ 3WR); ý½¿ÁÅ5,*31øÝÆ·¨•wp’8üsbHÙ•©Èz“ŒíàÝÂÒü#/% -àÄÈ¿ÐÖáÂœ•—Ðö#L&ïÚ’lhb¨ƒ áGCŽn‘’Ÿ¨ÁʆyÿÏáæ͸¨« ¨»ÄÞ‡•µ²£¡¥Ò3#ÉŽ‘¦Æän`-MCu¶ÊΦ{”¹«xŠ{v•¨|WX~…°Ó®zo ­§šÅʲ®°ŸŒfYHƒ»ÈÅÕÞ÷ßÌ«rYM]?þº´(¸ÒÃËúÖÃ’š ©êø>> ïõÕÁ®ß"DV=.óC߸Рêþöüåç /ó -FF6 û×dú úñ-4Ù¿©€yx‰©§W %aÌÑÀØ:3óðööáêõ÷ݼ¹¶˜ŸºÓíΡŽ©ÞG—b+*(í¢}ZNk\©‹²šŸL•ªÉÇÁáÓº¶¾¢„{}‚—…‘½Ê¾»©†„‰·Ù :?ûéÏ¡žîÌÇRqÐfž»Âª“‰iaP<e¨¡tet–·²Ÿ›“”¹×Á›ÈÈÀµ¯™[>RTE€Íûóÿõݾº˜uVY)ÖÎç ½JÎ×Ä×âÛµ¢›®ÒÓÓ-6Cñ÷Ú þë÷÷_V5ÿ /ß­î&ð  -ùì5N%ë6E9òæߨc=?üÏ½Ò é¿¨˜¨œz›µã¥8ö,ù¥¾¯ÛA­sH85>ïÖÓØУ‹”–˜²¿Øýü½ ³Ïõ&\D,-($ 䮃YkÛp6¼èÄA¢²Ñͯ«¯¸¯~n€Ÿyƒ‡–Œƒ†‡ªÈϸ•qZw² 1*%ò«‰n³}¢v»ÂÉÝ%„°³»‡wpqO8G—ž”’½Òŧ€z¡Þåß¹†¡ŸŠ‘]>DnŒÄÙÐØää -Þ“{X#2N²r­Ôé鹘Ñßì 4 ÿûîãA÷Þù-׿ÈÈ =èÜÌâ 4AdYäM\*ó¤e^WÇ œ¸Ûî붑ª¿±›´ÀÀ{   kñŒ”¾v¹)¼Ù*W$ôÄ«ÅåÅ~avŒ¡¶ÄÅ×÷áÌÀ±¯Éàäáê 1CLI´‚sÃ×6Õ“4gÉËЯ‡‘yp†¼Ùѽª¦¡“‡“ŒŒ¨´‹swŒÒÌ®ÒìÍ™’Ã_zrŸÊ<[†{zzaD,H€·ÖÔæ䦅©ºÑÕµ’•šqq‹‰šŸ’†•©ª¦Æâ /"öȹÇK`†Èú1¨!Ú¤Ô -͸ÎÕòô]Q0ùúß¹µ¾ymÜ08þõ$FRVU) -i€?VPð„ll)ß›Œ£¸ÊÐͦ”¤¨›rv¹‘hOÃꃨ®Îø*[a¡ã’ä´¨½ØïÒ‰cŒ²ÑÝϼÁÊÊÌ£¡¤¨Œ‘§Ó-em-ߦ«™öm6e\•ÇÆ´¥|ƒ˜©­ÑîÿøèÖ¹œšœš‰ˆzs~Š™¶âìõçÎÃÌÌÉÇÒ·ÁÐ+&Ÿ¥˜—ÃP‚™‰‚†€eVæÀ¨¿¦¨Â¶ž¡p]oot‰v{µæÛÍÍ»“q{‚©Äû$7&èÛì×ÓØçܵ¸ÂåTÌàŒ«ã üûû áÈÚæ#a-TQR"úÙ©š¡}‘ö#&"(7<B3$'9=LUnnSA-¸QQ.ß¹³¥¯¨´ºœšw\u­·e,íl„cÈÉÕé(J].ß””¤ìèÇ©¬›˜­Ç×ØкÂų¡©©¥„’˜Êï9ÕŸ|™n½¿~¨À«¡ªª¯ž—ÈéìËÁöýͬŸªœ¢®ž€Š¬ÊÓéóâÒæìÁ¯¥˜•²´²ºÔt˜\‡š©™¹Ii†›‹|Š†ƒ™½¼–†¨¬¸«Žƒˆ™‹jWj™¼êëÄ©¶¸œ}\] æJO*Áœ¹Ãâã÷æÏ©ß&±°…“³ÂÒçþ47 #0>&-Dh3ÊРקœ»©°Ü=;÷ JJõ()+^{TB4ú˜+"秮ڵœª£””²¹Ä½¤ž”¶æÏ–xµÑ+¿œ™·Õùò÷åòÌ‡Ä Ò¼Å×Κ˜²ÌãϺƽ«¦¾Î· ­®—«¹Óè䶞”œJ“æx“õüšŠ˜ÃÍ·‘¡Êº¼Áð0.÷ÃÄ·²­³³»ØêðÇÄÉÚϘ¤¾Ê¸¯Œmez#&„Ÿ¹ÅÇù,=s­––’ˆ«®†u™ ©vk“²¶¿Ÿƒ’ˆg}}…›šu™´§’seŒ¹ä*?A÷ª²Õâùìá’‡«RŒ¥šš×ñ÷ëõ<ý(`/ 9?=òí¶àñ¼Ï¼³ý0JL$ûâÎöü%+<ow<( í¹n/ãµ´Ö¹ª³½±·ËËÐëùíÉÅÖ¸A–¾ÆçП}—×ÿ à°ÃêÝĵÆ᤬ÆîõºŸŸ¾ÔÆÄŽ¢¡½ÞÒ¨¹·œŸ­Çɬ¡¨£?y´yRs‘¦¶´ª­¢¨¢ÅUR@줎™Ÿ¶ÄÁ¿Ðë䎰ª´® Îþõ­iRNpçÔÌi©ÃÖÕäõö6‘°º«°Í¤}uÊ͵k8s¢›©¶À¬ª‹\@Ng”¯š½ÑÒ¼°„yv¹*¼Ÿ¬ãîÙÀ”`;_ÌQ”£œª«Ã8_D'7$!JCȇ®ß/òïñÇ·L(ñâìãñêô SHAg_;ò};%À›µ§ ²Ê¼¶ÐØâÔÆÜÛåìÛÁF¹ñÌø½áÐôØ•”ÐëÙ³¡µËßÊžš®µ¸º´«Ÿ‘ŸÄ—ž Š—ª¸¹ ·Àª6µ¾$~èÎßÑ¿·Åö³Âî 4é´ll|˜³ÍÐÇ"WÚѧ˜¢¨®áñ‡v|qt†ÎvTŠ»Ëêìç9€µËåáÍ“¥ª½Þ¸–zRd•œ‹ªÓÈ™ˆpQvºÉÑ×ØÙIJ¡b.&h÷"æÇÅÆÎÒ¯™pJIì|²¼­¨¿ï ,./=cX<-ih1üòð•“á 4çóí¸5­¿óõàÜîF/&Xl? þí¢´ešº´’¢ÐÓ½½ÎÕÎÁ´¶ÝðÝ‚\4dyÜóÖÑÒÉÑÌ°™¼"öѪ‹š¬µÊѺ£¦®¯ ŸœŽzk£™Š“¤£•§µ¸°®«-¬Çƒ™0Ü úÞÍÓÔʽ³¾Êþ©±¢Ÿ”—©¯Ôánûð|º‹±Ç\8÷Ψ£yjƒ²§f.“¼ÅÖù*Ql®ÑÕ´›ž–„“¥”§±Š íÝÇÒ¢‹¨¡Œ±áÜáåêÈnSÞ äÅȶš¡™¦‡\ ˆµÑë)*)*,XkM_•^àíõÞÃ`=ñ'ÿÌùàÀÑÔúùî×ê 4<!ïôþøª±eD‘ÓÒ§œÄãÝ»´Á×ÏÇÜæâÉV¿Ò‰•\qÌ0>,Ť’Ÿ‹’Èõ쬠©¯©ÓéÒ©£‘‚w†œ[d §‡§©’ˆ¹¹¨™ÃgÍÓJ܈À6ùàÒЮ˜©À¨ƒ—Èíàukj¬@&…`ù®¡·Ö< ñÙÅ™nm“´¢ž`–½àíTn©Èµ¥§’€w‰·á ýÖìI*Ø»»¬šÁÌ¡­ÅµµÖù»ì -5ƒ·àüØ‹‡‘“‚¥†‡ØlÖåIS91#ÿý -BF-!1\b: ø $óÛ<w+ÂÍ ùÕëùöíáÁ²Ú"þúõèëÛ³¦â -Í`ápy¢ p˜“¯å³À×èèýÊhì#‚“‰Â#[€k/Õ™–˜Š€¾ÌÓÚÛ¿°¿Ñ¾°‘‰z{‡¥¡ˆ~˜ •„Š¤‰”¾Ô©’ݼî»aÿ‡åš)Û¼§œ‰–‡yw˜Ú¦K;|½rRz¿ǵ³¼°«ÑíñæëÞÜѲŒ‰”¸!›ŸÅõJs• ©±«”˜–†ˆ°ô *îóÒ±¹ÄƳÁÉ« ¼’¸ÔÎm_i”ÙãâŽMJ™|kZg¹)§"! ÿçúøç;<">B2"$ôåë奵ùã¥ÙççäûΫÑþ$;ýƼ¡š‹‘Å×›@áevwacOvrr•ÉÒ×Úù ¡:'4§œ¨Åìužk8ëÞÕ˜›˜¸ÔÂÕßåÁ£¹³´•oiv¦ª´­˜Š¥¯Œ‡§³›•½Î¯ßßøŽ7‘,Å:WЦ¥Œwahrso™àåž{–¼bBGs߬¥ª‘‘¥ÌѼÁ·¬¶™¦±¦•ÀCZ_¢¦Ù9QŒ›±£¯ ™š­±ÒóéÔÌn‡·ñÜÖɽÁ¯Œ§¬Ÿµ¹¿Ç¹~Yn²¬‚NC˜©zZ(9‹Ò\û2âÀÑÃÆÚ Nb`%õ07ïïò¼®·Çö$ãšÚ ͯÖè´ÞÛé ÿ¬¢x^yžœ£¤\î‹YGaxTJ^v–§•|¤½××ÛéùÛu½‡VÂÇ¥È -k·”@(ìÜÛÅ£§®”“ŸªÎùöÇ–‘™£³ªm]l„¯Æ·²«·ßâÍÌÍ騾´–À½ú‡æNË‘ƒH³{‚iPTm‹—™È98íš™´:÷PÒ©Œ}›ÄÈ¿Á±œˆyk¯É²¤Ÿ³ê–¥r“º :PŽÂ±¢ž‘’§¹ÊØ̸˜\eÁÆÚªŸ­»©‚¤¤z¬ÛáÚš`PVuiR5#Ey@;B|,‘öïÈÙíþ.Ec]=(èòøóïæ 饹Èã9²ÒïÀÄñ-çãØÏÜÜ£md†²­¤\ü™vETaicp­¥°±’„ “œ¹Ì×á® í®çÍÙß~¡~ àæïÆ©ÄëÕ¬°¤€…—ÑúôÇ•Š¤¨›yio|¤è÷Īž²N4õÙ¾¦¯¯¥¨yáœÅý"jÕU ’X`r{fuˆ«¾Á½é)Cõœvtò³Ó=ꙕ’ž¥´¶¦“}†“¸æñǧ¢°Ô õ™•ð*O”Ê¿“ˆ˜’ž¯¸ ™›º¾†‘¤‰ntqy~¥’ÈøÞÍ¡fXLRLAEWVyw6l–ÔQ}¨ê þ+:ù!3*öëèãéñWs,òóìÄÂÒÏÖ ùÓÓÙå03 ìà LJ†¬¬^ø¼•‚_rxa`fk¿¸–xh€Ž‰‚•·êßO"Îæ²ç+Kxgý¿¹Ï¦¢°àü̸­˜Ÿ¯µßó綢–¨žˆwxp‰± Ú©£³‡‹S"ÛË°§£ž˜+›w¦Õó@Ïvo}—–‹–¦´¯œ‹™Ö(®mhþÃÌ&º¬¦¢wux™¢±¥£• ¼ä÷ɨ¦«µÚ€]µÄA²°’‰–¬vh}’†‚Ÿ¡¢˜u…Œrfvzpˆ“–¾ôë½»wZ@GHOif[€¥…´à^˜¾ü(9ôòÒè íçÜ -K€‰C×ÍîÔÆÝöÖ×êÓàâ7694ÿàßèìÖo°|y•‚Y^YQEQP’ Œ{cd²²°Îàžž4ƒÅ^M1÷̼û¸²¢¡ÖøúñÕ¿Ä®ÎýöѦ› žwq“¬¡¯Ý´Õ.E=Óº©–™§ŠúskÈëØ›T­^z•œ’~~†ˆŠ€y—÷-Úp±‚3ͳŽŸ’yjz«Å½©š›Àöüí»¯¦¹ßê‹¤Ø +]‘¡¡¦®{E[‹•ƒœ‘Ž…±œ¡¦Ä••±»ÍÝඤ–tI,A^b^Wr’¾¤­ T´Ëâ0=åÊÈáßMH)ã=ow:-ÛÆ éú-ÖÏñðáó'#5⯋ Ú· -We‘|`DA?6 #l£”¡“°½æüä“Æ“a£ƒËE3ßÆÄÊ̺Ç̱²ÌôøøùèÑ°¿ñçÅ£ƒ‡˜–›´ªÁýóðÒž©¿Ó {˜™¤¢b^ƒ²Ú²¥ZŠ`q‘œŒ‚z{€¬…hÊ;U.‹ä󙈅ˆw\Xc‰®˜“ŽÃù⺢y•·ÉRZ*€©Îø5}Ž‚Œ¦¥o[Š“˜…”©‹††—½º§·Û˱Ùí¬ˆvŒºÑ–c6J\^]tz•´¦¾$xÑìæ7<â¿®ËÞoP  Ò ?hd$)êÔÞî )¸Íüû&49öíûࡃwC:-AG…ŸŒ†vXC>HD%8zž¼ÝâÔÎÓö¾Ô—{ϵ±£Ì!üÁ¯ÀÊà×Þðà­¿ÑÈÀÉÿѥĭ—zo¤°¡ŒšºÄõäîîÀ‘’•Šƒu”«Å¾es”¾È¨|ƒÓu‚‡€‰v‡˜®½t]}ÌgÓâïyw°Ô…{hYj^i–°¤ˆ€‰ˆ¼äó×Øر€‡š«Ø½E€Áã3qynp˜³zly–’•‘‰–¬ÀÖ¿ÈÞئÛð­ou¡äöªsW">stjŸÄÎõZ¾èõ%äôã¿Á͉*øè+\e[8 ηÙÕɸ ¥«Ú42K%Þ“‘‡}: ÷ˤ‘„…{icebNJKK_q†‚ÔêÒϹ‚„!ÌmÔåýâ«œÕÿäÖ§³Íêúúúß½²¼®—”Äô+ §‚›š{¤Ã§’¯ÉåúÐËÏÞ¹¥«°’}~œØôÆ OŸ·½É»|Å„\nv|´Ä·š‡™Å9®ÎË0ž‡‰¦¼¿ÃÀµ¢”s‚Ÿ´È¸½´¯–›±áw-ãY”Ã*{•¤®˜®§uwŽ„j‰–”¬Úøÿײª·†½»Ÿ˜ªÂÚZC.1SXHqÍÖüY¦×ØìÕ¿ü ÌÀê;Yú2buWTF õÔÑß¹Šes—«ùK@! Ò~N<YpHãÖ·|e¹Û¿„b=0BapaYTo–…y©åʦ‚vGBè -Ýÿ÷ä±ÀâÞÈÅÃÒîåÞÜãàâΫ¦ ¤Ü>5ÎŽz”Ÿ ©·«¨®»ÀÑÛÈ›™ÄàåÙÉÁy¨Öæ¯ -]Á˳ÁÕš P„^Tw‹Ž—µ¶“…•Ž’§*\}±Ùû«´ÏØÌÍÍ»œ§Œ…¢ws†sŽ ’š²¸Çûa ó}Ê -f˜ÂÍŸ•›wLc`^xxŽ•Öÿј‡}Š…^¯ª¶«©¾‡[dQ0757H‰ìô"u¾ÍíÕÈÇ9ôø+õî.ci\lxføíÏÃÁyGaªŒ%©oì†7$F: Û»qj{—³·¼‘W(9Rqg_{„•– À×ÈŸjM*x]PÞèÀ»ÃëÜÉÙæÞáéË¿ÇËÈæûݵŸ ÑFq¹ ˜š³Â·³´¡´¾·²¢œ‰•¸ÇÈÖË¿¢‹ªÒÎ’uÍÕŸÛ¨+p³Šro†ƒƒ„q†¦ÆÄ©£E¾éÿ“Ô¯ÄßÝÙű¸­®º¹¶¥‰Œny‘š­·²Â̸«ÆñN?D¸í)`«³“z’‰dH\‚’—§½ÀºªuuvrcT^‹¬£± £›}|Ÿo8#<vóÞ”Û¹Ô²Öë 0/ýøåðàÅå-j`Yx†Pøõí©¢¬jF•Ò¼¿)gÞ4IOêðþß²‹tw}¬¶§­¶I8CI\avoŽ‚€”‘ »Ì¿„HÛ¨€ëÇ¢œ”ÀöðåíâÉ´¢¥¸áúõçÐȨ¥îe¼ŽA÷²¥­¸Çž°¤¬´ª¥¡©¯¿½Ãĸ¢†’¤Å¢‘ -~ÃàÈîY5·õµ|knhuŽ¥Ï þã4¹ -Ø:·½ÅÚéÚ·µÁÍÓ -&«ƒ³ÃÏÈÀÅØθÃàÑðŽšVšé<•–‰ˆœne‡¿¸µ²—†m^U`vmHl€¹½‚{†„‰¹¶ª‚=  iœáÿ¼Õ|µÖìê %ÁɾÁÁöWg`]Œe"÷囃„v•ÅÑdz­±!ªÍÛéÒÅÚÑ’^€«ÂÈ­›†ŠwIO^pYWmŒ…uo‡œ™«Â»‡öÊšä¼¹ž¥Ç9A?0ßËǸ¬}žÙüúÞÁ³¦Ÿê -¥&ؽ©ÉÓÝŬ˜œ µ»Á³¹ª¯Ä½¸¹¿¤›•œ•ˆ w­îØð õOõ²†zuƒ¯¿·ºããµ›àS¦¶€!ØÙÔµÈÛäô C…µçÖ@ ûÁ­´ËÖǶ¬µÕÈûÉ».š–œz‰uy”ÆǦƒv~[/Oxwm\ilt‡^ep–±¿Ê Œ8 ?–·½ÉãèU—»õ  - NEé×Ì*+@H[{‘m)Ýk\…¾ÌƘhÔÌž—ÌÉ¢·ÊtSˆÃÆȤyH]|m|nr…¨tEX™¸¸¼œy¶ÞµÀ·¸Ø$3D28Õ£»ÂÀ¯¥±ð"Jü¡’€t½a3XÈªÈʽ£Ž’­µÀÊÖÒ¿®·­µÆ¶˜š¡ ’øS¡ÖäþÉôÔ½¦¸¸°‘¨°š•ˆ–€¹Óÿ(õÛ±}©Uqƒ}€•Áø\*³Ž/dzÀéðáÏ·ÁÒØ¿Î~ÄPŽxtl€ž›®²‹hZ^s…’—†haKFA‡xg‡ƒ“£¯ÀÃ…Cï `¦¢¦àù1ÁýôúçB+  Zs01o£¤Y©€lr°µ¬‘FÞ‡Þé·‹¡‹¥|p‚ˆ¯Þ­y_f™¥´‰y|¯Ÿ{UT˜ª£«uðÜåž¿ÊßNoC ü㲜ÁöìïÄø›ÝG¯vc_›2 K¤ᶦ˜¡­¹¼µ¯„Š†žÁÙðÜı¢°À¸²• £»¥øA̽լęϤ°˜”“€‡}Ž’¦½_*Q¿)ãȯ·ÓE`ýúvÿü©‚F÷ä%' Ò»Ëóñ´‡ý¤q¯AZu¦–ˆ˜‘ƒkXw“rg{utV^Ž²ydn†•e2ðØÊ4²ÃÛý&r‘ÃÛ³Çøý#K06{`EJ[so3ûÊocš_8!è„.^¬Ò§oWu†v‹uaÌà’†Œš›¢s›¤´rj‚—ˆ›<Ö ¤¯êx£•<îìñ÷ó˶½õüܽâ o¾†qu‘ÙcÈl¿‰…“™©¿Ö躢ƒŒ¡ÑóòŪƒŽ·Óë« ¬§÷(_Ë»¤Á—u4¦—”|s€œžœ›”‹–µÀþu’UÙ£¬¼Á¬–¦ª®©«Ÿ–µÚ)4$)2÷ã·¼ÛÐÖÇ¥¦Þ^çˆs$r³‡ceh…kfa~r~•ž­·œƒˆœ{gd™z;þìãÚÞ9¶×ÉýÚD‰Ž¶>( -4@F+&;çâÀ^60]Yಬ~H_vŸ~h~•„_wml¦¸¡²«~qk}œ«~˜°«µ™†|ƒ‰‚Ð|añðÎBg–†OôêëóìÅÉÕËÀº<!TÑœ¡–š™¶ -°u~“¦§òÿÉ—™”—„šÒÏɶŸ·ÊÙ×¼¨¦Àû:¼Íº£?è“–…~tz’²Ä·¡†‹§²µÑéóמv|‡xG^sŽàôÚ²¸ººÔþñæâÈ»»Ôßß塼‹·‰qMrjACos_phœ¶Š ÄÈ’iefnhhYWh4 ôáîñJµÕÚ*Þ–ëûÞøUç  2"öߦWˆïïëõ©w3úÝÈ tX¢TgmtkŒ›”sœ‹ …š¨ogl‚’¡¥œ¢¢ÃŸnpi·¿mUyƒ^8 æäò "ãÍÀ«»ÎS̼­½¨Šyw•ºµ» ¯Ôߦ›š–Š†¤ÆýÊßÓáÔ´žŽœ¼êä/Ñéӵ߹Ã}}€šª±¢»¹¢¦¬´©ž«­´ŸtZq€‹¦³ÔÙë严¬ÀÓÜ×˵²¼°¡±Ûý﯅œ¹¹ÂÎåTÖIÕ07ZŒŠy‹µ¼×Áyy’~bGMeyxje]v^! íþ-Ciˆ´çßÖ͵ä -_§Ûß­†FISOU‚ÇØv¼·À ~xdjzx}qz„…t˜¦Ÿ•‡‹ªj‘’zluŒŠ‚€¦Æ¢qV /LÛ&¯ôE¾œ]6ýöíõçÉ´ÄÔß=Ÿ[Íš¬»£ŒvfcŽÅÙ³¿ãÚ¾¥žª£†‹‹›ª·ÄÎÛØÔÆžŽ‘—¾ÚÌ ½öç§Ø“~‡´ÕÏ«¶æ -äû¸•w•Ä¿¬~^™ÐîÜÓ—…“›Š¾âÐ˾›‘Œ¡ ¯ÀÚñé±”pŠÒìù˪¿ô8ŽÔ”õ!T}ˆ©äÇ–‘tjs…Œlbc`dWq…‰i êîÑý&ršÑæœÀ ù¼¹±×ò 1]-íŨŒ†®lòz_y|qxŽ¥rfr„y’˜”jy…xmŽº†a«»„[~–žqJUdpˆ~v$MJ¸Þzà´h&*'  üïæÑÕÍæ'2⟄œ£—”ª–›²ÏÓ¿ÐÕ¬…‰Œ®Á¼›Œ’’Œ¤´¾ÌÉ«†‚uˆ·ÖÈýþ]ãñ·­¢¯ÈÔÕÇÈõ߶¬ºÛ  æ½¢šÞøåÒ¹‰kkqš·×Ä°š‘†Š”²ÕêäâÇ‘•²ÐæÃÇïùÞíoN¢p…Š•}–‹tœ™{‚ˆd\pŸ‹e1ÆœÂÑò ãi‘¯–£úî‰m~£È«šÍÆšXíš‹ºË²y< H„m^dkŒŒlgh^vmpŽ‰yft…š„Ž™Ž°¦x\Š¢’@-@_y†luM“s¤vãNcšJ>XELH3!ûÜéóûâæßùÛ•}“¤®¼Ñƹ˜Œ³¾ÇÖ¾Œ~n©ÏÔ³«©’”š¤¢£Ÿ€„’°ØÆöò†Ù˜¿¿¯š¢¼ÙÕÏâÞÇàU)€TùÌÀÖγ£ŸŠnoŽ‹ÅÇ®¤¦´¯ªËÙãÙÕÈ®µÌïÿíֶǽ”z© nJ{wvY}œ¦ˆ‡z†~zj”¥€a7 —…¦´ÐÓ¾ä4Tj‘‘ûŽZ¬ÎÌK9H=žNAk¥ž®¿ÃÔCsOFZLVXIHIPbo~—~†‰™™ž™º–‰œ—‰sv~€”œ½`nƒ‘¯¬w2eq¹y|ÁÊ¡Œ96bclzPëàüåÏÐ×Ì™ƒ—ª¾ÙßȲ‹Š·ÅǾ±‹qmƒ¥ÅÆ¿ÛÖ¹¢‹‰š™‘†¢·ª€–µí¥Ç­ÚÒÆÙÂÖ‡¢£ƒ{~¦­¢Œ›²¶Uëa>YóÑÖÞÄ£–—Š€ˆ”¡¦ÅǼ­¾ãعÂÄÁÄÖßîöòðÒ×Ù´“œ©§«Ù"­k;³ó #PŽ˜zuy…Ž—”‹oCëèÜ´¼¯‘–’•¡ð-=r¢½øžªøúâÖ„ÿʾ´Ô8¬o®ä+I?NUI.8PcGTn’t{²ØË„q½š‡ywy{‡~~£¾¶¶ÙùâÅ}ï"uwš€os`Rô¹á#Bgu;úòÿãÅÍß³{w†›¤Ùòâ©“~ƒÀÒÁª•„“´ÂÄÀÂÙðéÉ­Šv{•‘£½Ì©”¨Øxxn¾Ç«èIׄƒv‡ˆœ’€wxnhh„è1Ҟ݉ëàáʲžšœ¢²Æ¾ÉDZð¨ÃÞÐÈ¿¶ÈÒßì÷ÌÅÊõÖàöݳ½çôöëäô1·KÔaÏ<\`l{ˆ¢˜‡[Õ·³Ç Òºª’žêY±À¹Çö öýØNóöCt‹uwE§€åþ. BeZL^{—‚m|¥áñΚ€¨°Šws_`wq{•œºé#I-ºK£ÄÛUe£¥—Ždïª~¥ë5YTsx^HýôëÐß×ÈÍ"!¤—˜¬ìúÍ™~|… ±ž‹€ ò㸶êîÇ­…x…›¬ÛÞ»”©›À JÌÚ쬀Œ¬ÒÎË©„rjm]U~Ûw›[KêÜÙÀ»ÄÁ¾³ÂÚßÝÅ´ª¼¶ ¢»ÁÛÓƯ·´Á¼¨²E2"*áþýòÛÑÛÎúTã™1m¡Ó)Wr¦´a0÷ÔÁåéö°ª¬{{~ÂôñÛ6À©ð=Ö3*ù§xSt±Ó˜u_/ðá÷¾¯ðóñ)JKL‘±¨lKe{”Õﮦ·œj{‚aXj`g®»ÉZI°Ëe·92²×¾¸ÓŠº«‘•ÃòGu‡p,òд»Ó¼Ø[”Oͬ¢ÂÈËζ“ˆ†‰¦››"«ƒ4íÀÅòϵ­³§’˜¯ÅáÐÉ°¨áá*ËùÓ8¤ƒ¯ÚâçÇhT`kggš ú‚pâEáËò²¾ÍâÑÍÉÊËɶ°¸ÀÊ¿š½É®®¸«Ž–¯ºÍ5¢¸Oë×ÞçõLhG98n¯‚© WamGíÍíééïÒÌ¥—‡yo‘³ÙÆ·€†‘÷J»G;òûôý¬l\S1ú鲤°ÒáÞâú!h¨«„V4_dpŒµÍªŽ‡zhwvwwwr‚ÇÄÞ4GÁ¦‰µR)/’:j]¤ï̧·Áã,MWdpQ Ëž¦»×P˜r ×̹¤œ´À¹x¡•š¨Î6úeÔ!ãÇÃçïØÕ¯ ­ÍÀ¥­ÁÖíîܺ®Ú¸ÎK¿¸²µ×ܹm]X\wš›ÒF¸žhÈ“¡·¶¹¿ÉÝÌȹ£ ¹ÊÅ·³¼¶—•¡Š½Ã¦“¥³×Þ²ü‘7ó¸»Ü(d† ~S:û w èh§®™š¥àáøÑÕɉ‹™“°›­ÀÂÜ 6bµ<)ßEE6X57ú‰u`K6Ѫ¯«ÃÌ×ͽçñ=qnQNk•…œ¼­z€uf‰Ÿ´²³Þ'<±ŒQ`Ʀö6¦ôšOƒ]izêÉÝô%EbK/9A -Õœ™®ÜCoGÛ¼¢’›¹¸²†Ÿ£©À$ ÿæé˵ž¤Ã¹³–«ÆÔѵ¥Èô鲛ł×ÕñëäΦŒšª‘{w}€œÖ2G80¹Š—®ÀŶ´ÂÎÅ¢œ©ÐÞÔ´Ÿ§¹§¦™›·øýÞª¢­ÑåÖÞbË)êÌÝÔ 6WY_#ó_©Ø-·Y¿ëåìÑÙÞ⣢ÃÇÂIJ¬ÉË“£ð3i0þ5GLe‡T)1õ“ˆŠ~oF™mŸ±‰™©Àž£®¢¢ä!@VTx¯¹¢·Ç²t‘z“¤‘©»ûI=â‰2kívxÁù-‚3tOcåÏ¿>]P >OZTD Д¹Ïù1-üáÅ»ª¨º²§™™˜œªê"Üï{ðµ嶜{†ÃɽªŸ²ºÍÜ°™¦ìüê·›§=¤Ö÷òØäϧ{ER¥«–˜“œ—¸û>*𷓨°Ä¾´¼Ï½¥¤«½ÐÚÇ£¦ÆØÕÓ%`a+嚎 ÈÌö*ÚÝQ黸ÀÖIJå!ä¿ÜåóÒ®ñËË^¥êñÖÇûøüêïòðÞצ±¢r˜ã/ 6KrƒgT*.ò­}ZgR“dœ¢—–™­”’™²ÀËè:@w•—¾Ó¸‰WAi~ˆuOOG4+KoŒdÈ™¼ÐãD@ØÂÁý«ÏedƒzqcB-!8Ñš¸ÑããÓÈÆÖÝÔ²ž §Ÿ®´µð[ýþǪƒ?»£’„…ÂââÀ¡»ÁÑ̳Ž—ËÝÚÚÞþk¬ö2»«žyuÍìÝ•¢º¹Ñ 1Ö°¢¨›¨¤šÁÐßÅÁÑÑǪ±ÍÍȽÈýB¬dì“Ä À«¯˜š¨«7#I‚ Ø”•´ÞÆ¢®Ñ黺×ãÝÌ°¬%7 ä ìå-&KòëǼ±œ­Éã¶$ÎåEhiW:0ü¼ 'F,î›s‚Ž²±™€­ê½¹?JP_¨Ò­J#91ñËîÁ;ÉîTÜšïö%Þ»ÇÄ*C-7ªK7Yi9üÈÈÙæmRﱡ¹Å¹­¤ÐÙÞðã·˜•œ¡°Ü(¥ii-V%ªŽ–±ÕÛæЫ¢¸Ä®§œ˜¼ÆÏìæ€Ï6¢¡‹Ÿ ±ÍÐÛüʧŸ·¿Ôõ·“¤¸´­¹ÉÒÇššÄçàË»¨±ÄÕÓÁêâÿs4 EîÊ’Œ¡ÅEvó.ÆŽ™ÑèÇ”§ÚàÁÀÄÈÂàå֡Ÿ¼wä1:?:XM]ç÷þú÷ô öñ´uׂ™±66/V\5ès%âœ_.-LV%=[j™îÈ£§Ñ &+erŠ¬škåÖ±“Yßý×XÎÎΆý³ñ<>"â¿É ăÈÛ9ÙÏâãÞ·œ¹Ð W[)䦮¼µµ¨ÐìßãþæÌì¯Û?+úÑŠ»nF 6«À¦¯¦¼Ë¯–—›žŽ”¡¥³ÊËæÚÍQ:uªÕçßÕàùêÜ´¹¼ÏâûóÔ¾°°›­¼ÊÈÀ³‹€–ÏìÒËȽÈÝ×âY±ü •b‹j;dû¸Ž£°Þrå!µ™ŸÁûãÓÓ˜ µÇ¿¹ÂÛƨ‹>o^ƒŽ…R(MMGôþ)tU  çFQoÍýï2Z2Ú–Iîá¸~@ýϾšmˆÃéõ6*äïtÌ+¤ôݳQèfÀf-ÚÀÄ‚2ñãÑÁ¦å0NAÙÖ žãìb¸}£àꯒ¼¶º³¹Ïì'ݸ½º¿³ÆØÒÜôýþùAa1”¤iǽÞ{ëôÑŸƒ’›•ƒ‚¤ “¢§°½¾¿ÊÄ—â•£ä¹z„«·¢’¶ÍÎÄÇÂÑÍËÈÓÀ½À­•ŒªÞ峋›ÊÜËÑÄÑèÚÊÆË«WÉûn}‹¹0üܼ“•ß_mæ­—¢ñatÎͨ¹¿ÍÀ¨¯ÚÍÍÆxЛ—°ƒ@%N8.J_jyŽNì¬ï$911_…„£Q'6"â¶Ââ¨g|B'ý7WxŒzc9×çzÛ/ºvÛ« é -zTlT* þ·š¥œ£³Ý1XUN<"1jf}GlºÅÅ¥ª¬“Ž©ÚàÞ˺ëêöÌ·¥ª¶­Èî   =O4v¬ÖWgjÁmX6(+Ó‘}Š‰‰‰¤Ë¿·®±ÄÛαœ¡à&ï1X±~‚•–¿ÜÀ§²ÆÕ¼¯°Ð͸®²³œµÐͪŸ®×ÙƼÀÄÛ즳è:áœ4Û;Á§ «xG Õ³œÆçùß¼È9¿Ñw ÏËÀ¨—™¯ÄÁÖãõöŽŠ¶™ª_5ï&PQ:îa˜¦£ôQL(òÔug¼ÞÏØÈJ„æÅ»˜Š™ÆàÖ»žh\mŸ‚~óöqÜP…Tld"Ë›™¥„¥ÒÞ>^Pu¡vGÏw]ˆ¿ÒÏ¡·Ê»¢Ž¨ÆáØŵ»ÎìÉ sŒœ¶í%4 #'T-¨ÄýFòðÜðKb5ÙŽ£¥˜¸Êʶ³¬¼Éó£²î ¤B`ñ鳫¤¸¶¼ÍѺ®¸«§·¸ßèÜØëç쪞¶ÁÕÖ̵£”›”¬À°“Š³Ú“”¸IǘµodM#úßáðëëF Uófû¹¼«ž¼ÿæéüŠ^|][=,B>Kÿ%V…–©‡0Z8ééÑÛ”ƒ:J¾+WBÖÑzf\ü1GQK?H0#,ü´òÁï‘jäØÜß!øÞß´­ÞîÕÜ6‰],²¢yªÑàÛ²®¾ËÆÀ´®§ÆÕâçÐϾŒbXZiÈ94ü×Û™.iþ\⥩˜‰«à'd€[ãÕÝíÑ»±¸¸Å¦´Åû*ݬ†Ö øÅ°¥™Ãìò·“ ÈÌÝõôéí̵¢§¢¼ÇÐÐÞƒŒŒ“¥Å¼^|¤´G·sÖ¼Cíð&C& üXÙê‹Æ”œ½Æ÷BQëçÝê¼: WJD53CO:N:1NXr–ˆ“tM*=\À¯­Ù½†„ƒ [wi ÈÇa›ƒ|†Ç"=!õK5óÏ»Û)ÆíŠÀ¥ÇʾÓû>WkY3ùìð rü:j¸¢«茟Ó௫µ¼ÂÀÙÊÁ³åIUJöÁ‘d`w{žÕ# Õ¯ªÕ8i8Ý£›©®‘ŽŸ§»èG……Ž‡XG]i%ùÒÉÑÙ¯‰”¸L»KñèåƬ¯¯ÏáÙº™¬ËÑÈàýîɱÆÀ¸»½´¾·µ¯ž ¶´ ¦ÉÆ­†‚††åó/ײŶ&ܯÀþ&'%'í4ê·±ž¿Þö$Q-ÛÑÞAÖ6ü(\SSb‹ŽCQWgw|‹gnZQL?6饡ÙìÍ¢Ê -$KIG¿CDÿku|‡¿ó 8yo0ïÙí -ùßóóû ñÂÅÁ¹¨~¬±¶a %ý®‹=qœf€z«‹Ä¾¨ž®ª±Ñáô7îH[3÷¢2Ò‘‡ˆ|¢î#À˜œÃîòÝ©zªÄÀ¬¦šoTqÅ%e³ÏÁ›¸Ñ¨X ñââÄ–q VW†ºຟ¤¹ÃÆÈÏÁ¾½±¹Óº­¼ÙÇÁºÄÌÉÖÄ«¤­±ÒÇĦ˜­ÈÕãÛlÔp)¦¬Eи·ÄÚ迦Èåö ÷Å™‚’¬²Öøûùà¿åúO”%XÝV]mwh-!WgdbSscNIQU= ÿ -^jŠ…z‹xK-&2»)ôebˆ©¶ºÐIž¬@ÓËò$Úü§¯ÂʹÊâÕ©ˆ¹!Õ²Oúé&.éß?‘ÃDe0u;û¬ÎÞ­š¨¨Èßô7šFŽ×¼s /Xÿ·¯¨©¡©ØÌ«¦Àî㪉”Ž¹¼¨­¤x>A{¹öf•˜”°Êµc ÔÓÉÆ«…¨&}šâ¦±‘s‚ŸÄÊΞ¹Æ¿¶¸À«–‘§»ÂÇÓÒ·«§§³Òíس—|Š·ôðïߟ}½25@gDÞ³¹ßÀ²·£’®ÐìWlJùÈ«š®æãÙÒ»ÆÚC{Q 8]ho{qg1*4ak\I5XdQTvƒ( VÄ Vq€–”–fþšN=ã“-CE‰bt‚—¯¿ã^ÊÃböÙ Úµ¬­¥¦‡¯Òý÷ßÄ÷-¡Ækíé9Z'ÜýqAÜ4)æ?¢ËÜË¡šÅãö)¨™ŒùþÌ1= c$ÕÂÁºÀ×ØõðÝÌÓõ乜§ŸµÊÅ´«œ™ZW„‰­SH8,''Ô²¬´µº§³B¦¼ ³ˆ†Œ—¼Êµ´¸½¾¾«–”²¯¥®¾ÔâÛ½ –›¢­·Í°’lz™ÐûóÉ®˜ù2ˆ­àȤ¼¯§Œž¢¦¥¹ê>Ú±ñ+ä´®ÚÓÛàÃÄßqˆÕ0LuY]civ\?5Mu{tGENdxµÏ°XjõlÈ B<É[ ÃDÙwÃÇÖ|{ŒÅ)56 ¹Tçóö×®°·¶©Œ®êÿüéÏîåÞØe„Cæâ!n«Fx9œ«ÞëÀ«á÷%™†îƒ¡†6-ÀÂS1#öÕλ¿É³·Ñáã Ú­¦ÁÁ»ÏÕÞ£™s†œ¦ŽÀ ݹ¤­™¦Ÿ«¼ÁÎÌ^ÉÛzŠ‚•©ªŸ²¸±±¶±°’Š±ÒõóåÑàÕÈ–‘†…ˆ’¡žŒ{¯ÚØáÒ­|ˆ¨ë4Á©»±¨˜•ž£§µ½¦–ƒ¯èB %_rð£®Ùíäóáêð‚í+WXoFThr‹|K5?\Šh9:y¨ÄÔµÁ,­é/OOZHS@ý Û hý{pM°hˆªêR=îW—m éÑ×Ǻí¯ÁÇÞýýìÁ“ƒ¨ÃÉÂÇ+¤¼k0A2ocF﨤xºêÏÉòfK¾5Àí&H÷Òη¼Èª­·í Ê›­Êɳ±¾±»º¬’–¢¿·ÈÚÉÁ¢y‚ˆž ®ÇÑÁÈ}  q}• ´«˜ž¥£ª¶µ¡«´Øäýæ´´«‹‹Šnt~{p|¹æñѸ¸ r}¢Ð÷Ϲ««¥“´»¼³È½Ÿ¦Íù@8ô-ËÇå -ý@MñÛá¢s_E8QR[sn‰iXnUECB#'T”’ˆ¯ãSòðL{bB6>C)>}‡÷‚×ñ¬¡¯õôô;‚]âá¿·»Åª§ÓîÜäüú°€jkŒÂÝâí@²©I*@FÿïŠ-[¤nŽçüÐÎüx&oR fƒhàÜ×ðà»®±¸ÍʸÔþó óÍÄÍƨ±º»Â¦‹¾×ܶ³¾¥Žƒ’¢¬¨»Å½»Õ¶P7Zœ˜¥¦´ªªŸ­¹ÖÎŹ³¥³Ïâ溬µ´¦hTnd`…¶êôÜÐͪ•‡—¡©á¢«±°§³ÊÊ°§Å×½¾íRf9òá8A)6pLåÚóÒ’e&UtL'\lmPif*%E`hzÁVêø:[ZEP4(Q]lykH· - Ùo3ÐÃËéãíúæ :"æÎüij¶Õæòû @X¢wxŽÐü$@ ÈÆâ$6W‘h¿„‰Ôäû|Äv¨!,ÕW:œ_ËÁ½ÊèݧšŸ«Ñû úòùÛ²£¨¦£ÃÁºÀË¿¡§ÌѾª›£¬¤¥¬¾ª±³Ÿ£íýwJ)ŽžŠ©ßéÀ¤·Øéïη¢ …¢ÉîõÀ•³±ksp{˜ÇåõÓ¶·¶©¦©šŽŸ¤¤…•¥©¬ÈÒÑŲ®Æê×ÎÚÙÙéò Kx0íô0þì×zH,?jnüLˆw`tV #áó:h¹]ç990)#+3IbGBeosX<j3˜ @ër×µÛæãïÞÜÁú,þÜǼÌʲ½·ÆÍØü;î}å#Å°Í÷îå̱†}À37%20'.¬¤Ò <í(p‘X±æ{w±¼·ËÆ ž’Î&L*&ïïúÞ¯–Œ««¼È¼¨¼ÇÈ©ŸµÈѸ§•Áµ¶·§Â®•ë‹b8ã„žÀó&+öÜÐÑÞóÆŽ’ž«ÎϲƒŒ˜§…ŸÓûñÒ»˜•²ÓÒ®ŒÊëÓª­­µ¾âÞ¿¤Ä¿ÇÌÌÐ˱ÀÑê"13ýìù)üæ*òCShe__þL‰ptCûÛÀ× •Gÿ<]iS,:JkRHLW;,OZLÍIš›óÙ»ìëøÌŸÐ-!ëÕÑÖÍ»•jˆ¡¹¯%}[DL11%ï××Íʵ£ Äå üðâð1HùÉÚ*y Ÿ /’¯ÙÖ>P}£¬ªª²°¤”˜½/yC(&ð÷ ÷É´ŒŠ¶³Í৸ÚÝÇÅÃÍÖͶ‹ˆ‹¦¨±­²À¾ŠÈ2ÚÖmÇ’®È iDåͺ»É¯’„™¯¿¬‹‚»¦¨µ°»Ð-g+˾±©©ÖåѳònŠ-ÛËÚ2-ÝÏÒÊ¿ÖÕßѾ«¬­Ïùÿûòò< -Ahxi„Pri](ÝÇÝâйÒP/é6OcX%÷ (%8&<uiU¼[{¸Wë¹×9ëà( õ⬑wJ:fnnGç”'49Ì^3 òßÔßåÊÀºÅÉÄ¿ÈØÆÈÿ@? Z¯6¯~) |#%k…”‘™²·ªªØE©Œ.ýüóëëéÄ›µ°Æ×½¾àïßÝν´®™Ÿ¼´š¨ÎÉߌâBb•Ä¶¬ªÖ8h(Ʀ°Åг“š «oO£öûÌ®¤ÂÑX NÊ¢—ºÎéÆäHÅ7)õ ("ÞçôÔÑÍÓÎ̽§›³ÊêòóïëQ: QEšŒŠow‘s@õó"%Lj¿æʹÆÜs†íí&B58A$ùùüGrlj]AnòŠ¾ #þáÍù÷çÊxGL}†i[CÏœZ|¨+ßìÙÏÏ×ÁËÇʵºÃØáÖÔ?OA<zË;,î]æ“Y85Mv¢›‰–«¾Áœ†’ŸC+/cÞÓÖìöÒ¯¦·Á±Ìïá˵ §¤ˆƒ¢ýEþœ£Àº´‘£gD¨¨¾ÂǹªÃáÇ””·Ûêê¹——~cp©ñ Ź³¬ÞZ™vŠ®ÀÛìÌÕ/l3ÿ  $/å×æÍ­¬§›šŸ”™·Ôô÷ý=[L86†Õ.¢„UGa{mú¬éûzÅßÔËõízó=@7[1ãìÑÖ?C"!Bow[|žEGß\ -ƒŸäïâóöÔÆÔ§…¢Æ®¥©¼ÿ6P0ÓÄ®ÁÄ·•£§­µÕìÖß éÓçýúHÓmÏßJ’•aVLbbŒ±­’˜¹Ë³‘}…³ØqT5cÓ—¯»Õ  ÞàȨ›™ °Ã¹ª™ƒšœ±Î11®•Š›³ÂDg¹¨Ö¨£’{’¨¡–£´â -õÅ™”‰—»åùåÖàÑÀÅå;Óž¼Ñ͵Ÿ¢ªß! -ûôïì$fcý¤”‡v€qw€ŠÄÚßù#/"8?:C ô<^Q †°…R-7gfÞu°Þµ¡®ÛÉë«þ,M7"9RÚà·îIgX8);fLNu~@w/”+› Ó-*Û½â*?$õàÅÆ£Âõ% » ·µ©Ž„y™˜¬Ïçæöõáõ¹«„v8{…%*ã £ƒ˜”¡ÉξŸ´´¢Ÿ ºêXÈ¥ʪ•ºÅÖæèᦛž¦™…¥¤µÊÕßìý" ­•€“¢µÙ„®^® €‹‹ƒ…—ž±±¼Íß7Z(̦›¨ÛùààãàϺ¨»©›±µÖʨps »íìãîÜEäî|Ì]a`q‘§£Ø?7Ga55(/eXG^…£ü¶®…H%0$×s—À¹ŸŠ§ç2cí¼þ?LPPB$õÙÌÛ<HX<%Q=Kd@š«-šе÷.ø Gv‹ŽYôÆœ”Óù&7<4-茦 }md‡Ÿ™¤Øüí¿ªÇÍŽbONHZe$›G(kܲ±¾ÄÍÍÓñÚ½œ£©Ñð +ÛÌÏÇ»¥Àñ'í·£¯«’|Š·Éèúôú -ûÅ»¼À¦¶Ð½÷¤Ì`¬‰8˜¡–¯ÌÛåðõ ,€Ák߯ŸÁ?ñÊÌßĦ¬¦“ªÀ¼²¤£›§½§®®°½à÷å¸*YŸÛö¦¯dz”¼ÊâÿV¦“8 .J4!tæöœ…©¹£XïÊýüÁšÀ»§w’Áî™HVU?43õÔç1E9AAJF+¹ó%æG4VržÅË`Õ’n‰±Øô96ß¼„Œ¯ª•’ƒr˜ÅÞîÔ•“ —€J47:l¢¤[úì‚Nu6ÎÌØâç¿í2 -ʲ©¿ñÞÔê×Îà”t«3}[ 棪«’¥Øâ(ñëâÒÆ·²ÆÝåÉ·ãªùŠ•IL–±ÂßöÛè×Ïv^_b½Ñ=_¯¯Â³‘¥¦´Á¦©ÊÕÑÐɯ”™—¥µÉÅÃÞêdé^•±ˆ§Ûðêä1lñú@ K’ìâŠg˜&…QÖÐ10,ó­©Ä¼‰i£Èœš!7@-%,I Óûñ6F>(04-->ô"áH{dTFlA0Mið†Nl²‹¨µÍò-KÆÀ®ŒÆÝÀ¶‘cˆ«¶³Ìµœ„w}p]LJFŒÌèHÎûSÈÿÏ×Û×ÆH>üÖÆ¿ç úúß­™½À¿°›wkµx0)”éÚöýÛê߸¨¯ÎêÒÂÃÔÜØ´è· §z[~‡¡ÅØåêÔÄ»Àº¼.~ÒÈæÇÞL‰¶”›®›œ¡®¯º¶±ºÔáäáÁ¬–ÊæàÙÅÙÚí%"#D”¡¾ÝÙÌèÿìæú0*.r„…H+V8;$ÿú*(ÔÉÙ¯aJ‡¸È-´/<FQ4%!øîù(C249:2Jkã–B•›{Xc‹…Z4$7õ,|†dÞÎ×Ü -H?󧲣…sÁùÔЫ•½µ—›µ¬™‡soqŒ^UI”¿ìRÒV(‚Dµ®À×ÔüA;ãʵÈëöãÊŸ‹¦¦—Š{ί§âS£=6F=-ÿâ½£‹¸ÆÙÖÝÖÙϺ©òÄ°)®n{‡°½¶¦¨ÁÝàȯÔÞ|Ûç$—¸/½ ¯ªŸ·ÐÑÞÀ¸º¶»ÞÊÀÒx˳i0 \¤±êR„Ý›dš²ÂÎƤ¬²öA\‚¢½™r4"•nnö0 !!3CÑ»fdd—¸ ¬D+_y:*ýè5.).üAVenqÜ”Y‡ ‰žª­o4+óh²º`cKSkQû°•‹trØýâÍ¿¯»º¥ ˜— zsk}…hf}°¥’q?Ný|rÔX“™ªÓÒô %ØÉàâûóæËŸŒ••¡ŽŽ‚šÞ—« bCY`5îǸž‹—²×Ó¶ÊÔãïãÅ¥þÞ,ŒM‚Ž–›œ³ÙñûÚº§·Já®!óQÌÈŸ„‹¤µ¹ËÎ⣘’œ³æ<Ép!\ýoö°|û?WÂ|U”Ãå×Æ°¬×3`Nr¬àïמMY$´éù24 - -/]ª‡šq‚é+Ÿ}; /au3"!ùÝK1$19+:YLc<lV8ꌰ¡Ž—¨ƒ\.UûXMxÞôaAâ½u'·u…™Ôíͳ­µÅϼº±À´š””~l›Ëô†Ü˜ê&·-CÕa’ÈÛéõ  éÞù þöȯ¦§Ä»§±ÚEÙ<#·C$-2¾¥ª˜ªÃÈÉæåЭ§Û -Ūèß1VÑuür‚œ¾Øóù²‘ÁÿgÚ±lwÃyæzfz¡´ÄÆâ(ôŠ…’ãúŒWÑÁ;†Ñ!oC†ÏB¼Þ0…’··ÎÝìæ FSrÅåç'«h·Ì¯ÑÈàF@ 5>96ü•Ž³§{Z€¤ÉW`4>R#7:1ôúFUNF@ 0B<#êM9ß}™^6;ViŸ“u©E„V¼zÀ[qhæGÐií—ŠŸ³ÝüÔ¬µÁã÷ ïáãÜÕÄÍäòÚú!pSËQËJ§Ð•ÛÃêüñû#*éó#èй¹ÒÞÚÁÁ½Ýüõ>V`0èä鳫ÇÏÙûåÆÅÉÉ«¢ï Å¿æÛQ"Lõ¨Œ‚…§Ôá朎ؙqdx<ûkÉ~i~¤«ü'¼–—ɈþTMÆÊ°4}UáÏ/7hÈý×…ˆz°Þ6TXX“{‚0ðèÄŠžK]èȧÁÕB"7F'õ‡ƒµ¥€w©ÕX%â58. 7S5!öý'gb^R ù'D-î·Îe# -tn† “ú»p¡oÂ,b‰ Å;(जÃü úçùxä—}uà¼ÙÿtÚ"zÉÏ+ýôìëý.ýÊÊ:)åæÚÕÜßͽÁ¹¸ÌÑþ -ìõж¾ÅÄÂÏÚïáÐÀµÀ·Àø(üÆÆúŽ˜[ÌŸ‹˜•Ÿµñÿ¹‘KÉ7è´Q‘™Ò‹‰‚x}“à<'Ò¥¨ SL«ü½´Õ5œ­õÈþv@ÛbšÊÛßuÒÖˆ½˜¼Hy· —ššà-)92-þ ‘³§†…wV’ñ|~*$é DNQD(+Nj:눰ž·æOú&.  -v7ìÚ\æƒð€6ê£ îÙøŠ»jÊ–ž¸ð!=2ðôyÉíò÷‰‰_ÿ? ¡ç]ØU -à¿»Ûö æ¶Ú4^/ëõéæëëѧ®ÎÝÊ°×üþüôöͦ®®¤ º×ÖßÕÔ¿ÍÓä2ø·È+?¢ïd 䲜‰{®¿Ž•/‘M¬3>õ2ó¹“kie‡¡µ Þ©²1Õëñ!!c¼Ä¨ˆ©Ø3;¿‡„mKTxÍÿæóL‰¥§Aæ~jwuxŽ¡¯Ú*>7?-LQׂ¦‹‡k?fµ ·Óõ2%ý ä?5.AE.MR:Ëusu¯ì/@*0 îxA‡kË»U•`ñÉ+—©âevã«£ÏØ(34ßÅ·ÏV³!}¯@*í42”4$°jÝóºÐíýüéâD\ÌÝËÜþýÊ¢±ÒØ»²â.àÍ´¨¦±³¹ÕØìîçÙöûþ#)å—¾T—Èó*à 껶³«z{ƒ…e´-‹³…·œ_0,Ö¶ ‚w‡¢­¨¾ëæÈÂSáÒT1Ì?åÅÓá4¹ÓŒ€–£~©çò4)Ú¦œºû4h€‡êQ™‰[kœ™¢ËýRpsKJQL%÷¯««jQ98ŒÈÒoî^üG;?67 -,I>71%8BñGŠ.cSý5'DO+/xØË'Š8X‹õÑ -&ÙÈÃì3«;UðÍÇ´Èò#üÙý •¾ï]·—|=]%Tp" åÕðÔÂÀêûþôêü1e¶¨¯Ù د²ÄÀ©Æ8.Öƾ½¿ã÷ùðöéâè  -ïÿË“½oÕýANðòÑÀÀ»’yxÒÛÕ‹0jˆ¦‰Ü<ðͪ¯­˜¨³µ›”½Î¤˜u^´ÏÿŸ ý³Åëáá;„‘pZ4;„Þó íŠo–¾äò`þ‡Âª‡vŸ³ÂÐä~S3DVH%5ÎÆŒaMN‡Ô̾”QÿNQ]\+*Vz_N7-29 ×OÊ4é»%M[O89/TqQÑ€J¡ê;ñA¸·¢$ìãݶ§½øòÍÀ¿µ˜xŸê ºjÉk-<ÕÞ:ï û óª²ÍÜßåùæA¯•£»'⪞±¯±Ù7O#øÕÍÞÔØïúÿ-(4EâÐæûáÑÙŽîeúÓæ¿æè·ŸŸ›—Àjðq¨©`ù©²KÃ¥¾ÉÕÍ´©—™Žx„yM¢G?í兩ØàÆÉø29E0 -ñX˜±Ÿ„iŠ·ÜòÚ™göÍ»‰m°õôÿ-;x”p+I__-S>âÓ®xg{Ây ƒÉQWTraAR‡oX@D6"-Û5Òxhwp.#6WP$:0 ìãã& <ù#,­~f¦¯äH¯oå»Å¨Ç";Óš›Ÿ‹ŸÅÜLØZSûÛpr$8 ö³¨´¿èôïÏÐþëͳ°¢3ô³¥¼ãæ -, ùïÕÉ×êîðßôV“­­ˆ6ãÇì -üöИ"[AÌš«µëëО¦·ÉòôÕo*p£ž…L‚è÷Õ–§Õ --À¬’•†psƒ¤c™é_s›ñÇÓů­Ÿ«Æûëåãì>_^7=aqŸº¸©R(Ü+Ì΢µ?6^xœtS{›„SGpaAþ²’©¸]%y Öžsð-MRof3 :Z,ÛÈ+sM¼ßá0ø3M@áè";'' "(:ú æ+Ï™¶ÄÞPX< DkzQê–‰ª´—‹œ—ñZ¼ƒpP¾B .ùıÈóõæ¡¢¼ßðÚ¥“¹óíÙä,3 ÑÏîñØÎÌÅ»ï?}¯ÙãÀ†,ñê" ðÝ¡Qbüž€”î+ÔÆÌÄÿìlK””_×}›1¬§ãUÝ’ú¯¥±¤~…žÕ"À9JÅI  XZ÷‹}š§¹¯µµ¿Ùþ:3EY`x}fE >³Ùñ(`rjs~‡ÙðØù ùóñõá±…T îäÊ|`±‡ì„Ü4œ×:4öÅ×Ý Újõø߆oqà9FWL"ô -#.! -"(̧œ¯J -°…‡’ ìÖ¬ÍO§V…ÚÂ=Ú»©ª¥“Ⱥ9MÁµ…TŸ†>HWS0&?Gî·Á×ç軤±àëÑ š¯ß0Tqw-ѵÒ÷á±¥²uÛ æ³€b7ë÷'ìÐÓñàm.Óžv„HON)ðÑÄ°ñÐj÷Í2ý„§/z¸¦± ðR¹¾= þ  --& óêý-ŠŒüŒ„š¬¸ª¨Íòê&$6AEuqP$@€}¨æ1®8?ÒsVl³$‚ENHh52A1*$Ýk)õÁ•§RC« |$LWп͆<ôÇÍÜi)-×Ì#X;0<@%2+ìåýúï¯++öB‘_G6-9ž‚ -FQ÷ÎP€Á´Ÿ¯IY" 7×jz -ë"”b0(a?ó°´ÆßáË¥ªÜîßÇÈß83Iª£SûļÌÐËÝ$¥*ïŠF øöÛÌû 즄–û3¢ä¹—uU/Öµ­Åá]ŽÚÜkºÅµÛ˜zl¼ñl¯“Ÿl˜«£©²†#кÂÜ - -GDû ‡zœÒãØÕÚæïîáû Cx_2p޳ŋX%`œÊ Î\Š_:]g1üõ0u~u´YÓ»¬% -]ž%—i0B%ì"ýæÚâ°”ªÌøÇò3E:B2.û¼¼Ýÿÿ÷¬Àâ #ÊLÛ°¿ÊQ‰&ÑúˆÖ¹æ0³óŠþAwDß¼öoѪK5È°±¨ÇæÔ©³Úõõÿ41G—Ò}¼¾ÔOŒÍ ôÀu(éÑÅÅÆÑÛÕ£uŒª0k«öÛªTú¼¨œ¯Öì'¥r&fp·*詈`J”{I ”pn2a€w¬ tæãíçìø‰xp˜ý -úùôåÏĹßñî 89›ö®Ýkã­ß1IF^rRçÔʽÚ07q±dë†-û¾^O…”«ï³\®£™¼ÚÝè̆iS3Ïå)lR?2þø¼¿Õåôü÷§ÔDÀ <9ápù~±Â {;EìÓ(òã%¶-ÒEíõ% äå4¤õ¹8 3ײ® µßêÌÉ÷  ':èãäÿY–PòÑáA°Êf3÷е¶¾È¹ÂÊ~¤ÂÓZ¨±ãöÜŪëض™ªÈì÷Y³ã¬1Ö“‡dh{€-ý…T­¥žµ½ù3è/áÐη‡s†­ãæøïåÞÁ§´Ö -ûúõãóõÞ#îPÏ{œª€ý­„WN8#ðÚÌͱ‡¨ÖÖæ$\z‡dÄ8á{o¢–f‚p+TŽY]ˆ½¼»³€þëÆî:yˆ4 2!ö¾ªÖíâÜéöþ…¹"ÿÜž=lr #›ÍKà×½tci­8ÕÛùŠòà^±Š,'PU,~ÕÞŒ09bIðÂ¥§Îýàøçø'ÜàÔÔùïÊÚÛï,ªÿñiâË´·½ÊÓÑÚ‚s²êøŽÖ ¶ÏÓÁ¶ÎÒÈ·µª¤­¼ÆÓÝûûı§„qa–¹jnCAHIk}ìÄ¡Bþþû×›yx¡åñȸÀÆÁ¹Íö'3(âî)>Þsw,ê¢ÀDò ÙŒjEùÅÕϵª»®”—¯¾’²ØÙÿfDZ'½qi‚aO[Q?ˆ‹B=ŒÍÊÉÓ}|oÔÅÖP}Z Ò”®æìÎÒéåÑp¿@79܃X-lJSˆú.¹Ýøιuêa·áßÝó@]bJëú,ÝéžuvRôµ²ÂçõéûèáâùæÅиº»žÅôìóGyp& -âÛ³®ÀÐÒÖÉ‹“ÁÞúà -—®Ãĺ¯¡±»ÏËƧ—ÅÙØÝ;Á½È«{f˜»ÞÌe>hrVbÖ¶)äÒòퟩ·ÒƲ£¡Òò GUGöü_‘}0UqÄûúÇÄ@=j‹zMý¬–Á¾‡~·Å¹¼Ý´‡“®›® `{Ùo¡i¢T<qF…š[W£×ÌŽ"±íÈÁÚÝ)%þæĤ¦×Ó˵ÝòÝÎoíw_Ž¨é%"5tü¤t°m„ï3®Ú=Né|Ù”ÞAaI/âàôêå6Æá…EøѺÐÙÞð þöïÝð б­©ªš•¢Ôö¦³/’˜X(ÈÀÃÏÙɳžªÀÌì>ÊҿƱ™qÁÞÚ¿¢›œ°ÀËÞéâÜâãí¾~i‘¼ãáŽ9%a‹xG`ÃrZÒ¸Òò óÿ橸¼Ã¸»Ôê*kn@ùÆìHˆd%#ÆãXp·@µi@X^7Û·§¸É°rn˜²ÍÞÓ¶“…™ÅÎ’Ÿë5ŠM0¦ W0drNo™qd¨¸¬’{¨[ÖÓÞåÛÌàäàÀ­¿ÎìÎÆ¿ÎËÀìˆò£¦ÓÜÊF16aʧõ¬Å*®‡™9ø0$Ç×ÚÈÁé.!æÆÁÌÓßóu%²zÛ!šš¬ÂÚÐÐòÿññýççóÛ±¯®¨²¶¿Ôß¿‹|¥æLŒ•t1÷ßÝëñß³»Ü(/Eàüñå¯}k…ºÚйµ»­ÇÑØÖåìíöûá¼…o‡“ÅÍ”fOe¹6=â€Ñ1»µÏÇâö¶¡ºÊÒÝÓØúPœeϬ JNC!*P€ªƒƒÿ|ov= -ÀÎÜÏÜáÃŽ}„¡ÂÛĹ€ƒµÅ~[»‰¶ö2Ó—ˆ|j{ v}šŠv2ZVäÛÛÔ»·¾ëíÍÍçýìß±°´¼À ˆÝžœÊØÒBžiN¿×àÇþF.ŽÒãI¶lÄ%¾—çêÃðá³­·²ÈÚJ;QéÇp–w±ðüà ñÒÏÖÈÒ˼°ÀÛáÉÚÞáÚ¾¨™”®Ôö?p“f+ùõ௨¬¾Óêq¢vâôƒ™—¦¼Ç¿¶¸µÓÛççõöôÕÀÁpWj² ]u™êdcÒ:ö À¸»ÁÐû ùàĨ­µèêí låØSîËÀ×þ( %Ràûðƒ[î…QOÁ®èüû -ÌŽq€¨ª½¿¯Ž‘®—sqÞC¤œíᲉˆ€“vj…{ú'¿ÀÑžƒ–ÙþöÊãçÅ®Œ™¬©½ Ê}r®²ÁmýÙçË5:! Í(º”3Ò¨­ÁïúñÕÎßÕ°¤±µ½ðè|¹þ¶ý怒à$G<óÁš¡§ÁÌ­¥°Ðþ( -)ß¹¢­°µ×ç 1N?! -äãÛÇÖãÚòµ³&#º„ ¥­º¿¹¯³¹ËËë÷óèЭš•­±SdÖXÐR”‘ :Ž%îôÛÏ×ÞÞôùíÉ»¶“”Œ¦*£äâ÷ý ó-t 1%µ£' é¼ÆÞáε¥š´µ¥¯¨£µÀœW)M»õõ3j’J¾-«…grv€}}ˆY®ŸÙŠ»Ý£sŸÜñåÍÞñ¾’‚~„£¡»ú{¤E8:Lƒprç*]öÉÖ>jUë€'Ç€“ÕôñÚËÂÝéÿñ¾š£²¬÷pT>w<D;Û˜¹ú:?ܲ¢–•ª«¤µÀÝ$Mi_I×ÁµÂ±µËáïäÚÞùõÐßñõñÉOÝ - ê•ÆÝÛÕÍ®§´À´°Èëáδ§x†’rrîÊõË6¿9ê#¾š°ÊØØãäëùùôãÈ»' Àöè×—Ò.Ûâüûý ó4Xà;žEÚNßE÷м¹¬Ëûé¯ÁìîÄ´«œ£Á¤dJ?fÕôßð2vWŒÃ›¤‰^?‰‰ˆ~_*XS®¡Òß¡jŠ½À³ÄÓ×–zzj~‡¤îi…× uŒ ¾µÍühUµµ0Œ ¥ŒœÐáëÔÅÖóóûñÃ…ƒ‹ñ¡z0\ê&;ü¿¦¿ðüÙ»Ê×аœ™˜±ÁÍìE†™m!áºÎÈÌ©¥¸¿ÐË£¦ÉðÞÙïàèýÚº;ˆ ÿóùü¿ˆ‰øñÓ§¥¯ÉÏƦ©®ÂÂÉΰ‘ŽœšŠý5²¤çÿ"óµÿËX|œ»ÚØÏÙùñçëØÅÇêx [€F šÁ+üÿò÷ßí ù@OËPóšmõLëÎ’|¦Òÿ¨€¯íêųŠz™²whn†´äÍ~å^—ô¶¶¥]5i„‡’ˆ++±ãÛ¹|~±ª­½Í¶‘j|€ki‹Ê!§›Óa7gñCDŒ´›ÞÓkz¾ú c–å—¯Øõ÷õÑÝôéÛá¶|p{vìVÞ¬áWûµ#ñš˜²áÖÌìä­“—¢ÄÅÔ Gw„S𤦽ÇÇ©š¹ÛßÅÁÈÜâÐßêÉÀÀ©Çi¾ËâØí÷Ñ›‘åѽ•Ÿ©°ºÃÇ¿šÀøÚ¸˜­»“‡,Ñi06Sž·üœ ¼É¿¸ÍçöúëʵÙý5ñ~s-Û’@ãáØàûøáHoç^åƒOÁHä®}nžÙï±z¦ÞãË—ƒ|…`hl•””¥’_\®¡;5Ó¬®€GQs”¨– þÿ½Ô¹Š~Ž‘µ´²Ç˱›xq€{{Ý"R¹q™¸È3Hµp¤¼L7Žð%…’ꛌ³ë÷öóßðçáÍ´º—Š‰}ã«”Yw¤¥ -ö妚Ííàéï缡™§¹ÅÊè13ú¨~µÆÖá½ãýðîþðݾÕδ¤—ŽÖœæÊÙê!öDZºœz‚¦¸¬ ¦·°¶°ÉæùþöûÔ»¹¥“SDßM^F<dôWz§–®¼Ã³ÊæþèÖÆâøáò)+3* ÷ÒÑç÷öøÝÈÖIgÙaê/¡%´…–‹Å‰x«åÝЬ‘zfE_w‰½¼’ŽšfQ“o4ƒ ¹­šig|¢Ù¯ã¸Ù”™y‰•ˆ“¡ÅÂȹ ˆŽ“£ß MNdù’_e/pßÔácU‘Ué³UÇ—àŒ¬ð40ýÞÏɯ»¸š‰Ÿâ<¦øêI½¿Í×îâö øÓ²¼­¦¬¯¹°Ú,#èʶ¢·½Õϼ­´ððÿ年Ǻ”|…¦ 2àü(#çÉ¥€€‘”­½­¡œ¸ÃÃÅÔâéÛáëÞ¼½Ÿ¡pU -okhWn,Š~˜»ÊØÖÔ&øÓ»­»ÏßÔ¼±Öÿæ¿ÕØÌÉËãÐÀ¿¿èINŒsŠ«#¢ªzyŽeŒŸpw Å¿Í·¾‘47z±Üâ¨otŽYeª %IíLðÚË–ŒÄû´¹e› ‚˜”‡Ÿ®ª²œ©Í¼¬Åï91%”p܈ƒÁT;ñKþD`ŽµØ•‹ÁM¬h%3#鸳¨­°è/BLCă­Ïáü$?aU!Û˜˜˜±¨”ºÿ#òɶ¯·Ú뺴·°©ðúâ×⺫Àȱ£žÐKlçõÿÿç̸ƒi}£ÆÁ®§³ÉÆ´ÃÖÖË»³µµ­¡Ç“f"…`RUƒ3‚ƒšu™¹Ôæê Ha ±™›Ÿ¸åݾ½¾ß×ÏÞÒÁ³ÅÅ´°½äWKEï"c¦£pTYh€ŠqŽ¬Çª€™¬“Q_¯Þá§zlsqJqêû÷[.{ñ ’Ââ€0ˆš‘Á¹””–¥¦ ÄñÝÌè ä×çAÝ“±þ+ÓÐì:q¤–S˯-o‹4åã—¥ÄÛm0OBÙ££¿×û_œf#þÞѾÍàê<n†|EÔ¶µ¤µ¬ó[BéÒÉÊàò±§£À5ÝÀ¶¾ÎÅÁ½ËßÐæáu³•ÀÎÐÆñ¨•š•‘¡¸Á³«ª·ÑÂÎâÖÔÊœ’‹‘¦Ðžjü|jSQH¡4‰ªtxžÌ×åúG†#®œ»¸›¨°ÉŽ¼êèÁÌÚãÉ·¸ÄAL9À´Ú8øµ‚a^s†Ÿ€™ÔÜ®mŽª»ƒ°Ì¬‡~•Ž~c§ðÚîB/fûýéâµÌfx#ŽŸ¥¤µÉ͹Ž¸º­³î ãÎÑâþáÝЀ:Œ*ŸD︡ˆrŒëé7Š}=©Ä&–„; ëÒÉØÔÃã7á‘2 óáîäÚÜn±Þ%ý®l8 -î‰å¢C"ýÝÚçßËÌÅ°¤Î;×ÊÕßÓ²ÄåãÌ·â©ð›·ËËØßƪŸ±¦¤«²´ÃÀ»´ÀâñåÝØê켄‚„¥¹…ë\<3îšÞ±g±¢ÁƵ­Ò8´Éο“~–½ÉÉËr½‘ÒÙÙàÀ¿ª²5rcÈl…ògáŒlwŽšª·Ì®©yžÄÌŽx™ƒŽ†¾©…”¨Ï¼¹Ø/&Ž%,èÀÙävpƒ¹ÅÐÒâéͤÍç¼Ñú úÜÌÇãóÖß ^Ó/8þ¶Tþͯ±«±²©iüã.ÉàÆô#K5ùåËÅÙèÈ·ÂRMuÙ8ßÞóÜŽÑùTÆ"ŠëüðÇrÞÜghÓžaQ= ûRvEÎèóÚ·ÃäÙ¦¦Ýîaèàñïðö¢{u®·¼Å¼ÄÂÅÄÊÞãøóÒÅßüï«œžš£òÎîUgo¯Ý–±ºÇµ›˜³æúÝâܾ£¬ÌàÖ±£û¯G@ïÝÙÝÕ̹¾eZÄR6ãÝ@½iiSG^¡Çüϧ„xŒ³ØÔ¦—‹_ƒºÈ£qåϸ¯Æ-€€=cNöÞ p3£ìõÞ¾¼ÒÝÇÊéøçϲ¼ºÑÎæ)^ ùï„ á¦Ñè -øÄÇbÈÙ…=°Éé-Y'çØÉÃ˽°¡Átz¡»ÕÃÞÞ±©~{ÝO¸”$Ž ì©ÔñÒ—o\G/鯜¹ÁËÈÄÓ´g""òÔÖÉ»¢kÊ -ùÑæ¼w]oÆÆžÅÃÇÈÊÝèÙÚÓ²Íîï×Çɺ§‹×€BÆú½#˜.¢®¬«š“«ÄãîéÒÄÇÈÖ6韄åWð ŠäÙèÞÙÐÜ„¯eÙXÞwÀF²_Q?Aq ºáâΛ—¶Ê½ÎýŒ‚¬ß·ˆ±ÀÄ·ºÑ=°VŒ>YY ôòó[ÙA`>Ý‘Š¬¹®»ÕèãèÜÚƲ¾Ôý'+#Hš¸uï˹¥Çò,#ý?`jzm@»¸Õ&W+ÜÇ°¨¾³©³ÉZÿïHßÈ¢ƒ‡m•w¦Û…o5Å~sMù©¤¬³™taA#?FP1øŸM=Wk9õäέ¦¥ºaÛ×áúêÖ½›r“£ÎÙÙ̱³»¿Öéèʺ¹µ¸ÂÉäâäÝÖɵœ³õCˆPáÛÑ»¡†‚’·ÖàâÝÜÒÎÐæÿöÚÇ®¸ª÷iÓ¤ÕÚ××ÈÆì¼åpÇ)Ÿ2‘.©aMWsªÚÚâÈÂÁŸ·•‹€—Ö͉šÍÕ°­Æ¸™Èµ­´qž3VR*ñÑD£ÆCNêvµ¯°ÍòýöýûýëÎÍÂàñ¶¦Ù%3/ -ûÏ´‘¡Ò#ÿÿ“‡‹ŽèÀÂð(5õàÏÑÈʪ¥â+B;âµ›yy~“ê{±\"X È+àöeòÝúþÛÚ÷è¦];pŽgõÒ Ž“Ó²8úèÞíÈšŠ›¯œÃÍÍ·¨¤´ÙõÝŸº½«±ÏâîöúñØѺ§£ÝöÍÃÀÒµ’šš±ÒȺá×ÎÏÔÎͻɲš -¤–ÖÇØÊ·¡Ð×v®óe u½•wcyÆÊÀÌ®¦ÅáâctÈõÒ²¿äêⲞ¦ªŽ¬¢ßÔ>:HîɯT'wl¼TEàÚ翯ãý ïÒÄ̬vlžä -õɸ¼¾ØôêÊøžyšì)«ÀGW@"ÿÒ½£ˆ“Î3˜t¼†–‡‡®OÕÇ)ÙÞ*ׄ˜ã£ï/”R;HM*1WK6!?r{@ -H9#È•~Ÿõ#Œáଞ™Ž~¾®®ª¡­¹ÔåèîêßÕÍ੯Éè'²×îûöÖ® ªŸŠ™±¦“¢±Ànjå©´¹ÐÚ×Ø̽´ëd{Ý¿ÊŶœÈÈ‚´ÍA€@óÉtY†ÆÂÁ±Š…Ýá«‘ÁìÿóêçóôÅœš¢‰ ÏÏÔE¡-ø$í¿¯V`ruÉ"I>óéÞøâëêðå×æݽÁ­œ€… Ôú# ñýùÞ¿ÏíÔËÀú–:nÛª±ï<O) öäÊǯ„xÂ|ÕA°}Ž™ÉXÃŽáò7¦v®*x̨°¿ÈÎÍìÛÙ, ðÜÏåõµ™œÆ]–­ -¾y–šˆ¹¦¢¬ ­·ËÌËÓáßÕÑØ»¤²Ëæß’·ú(貕—š™‹„ŒŽ›´Â˜‚í©ÌãðøùåÌÒ -e.Ûļ»¡«G¿ËŸ2"CÎGA¡ÉÚ½˜—š¯ÈÔÆÌìåöõ -ü¹œž¯ÁÏÒ¸ õÇ 4ܼbz;…¦ü)ûX‰†dOñõíÚè -ôÄ·º·°© Û,RhS936þ˼ÅïèÅ£Æe+9¢ªÁðíÜÙÌ«¼ÂƈrÞ¼OCŒØ–ˆ›Ó(e]* þ%OT…µ†,Ñ|‚¤ÆÜ×ðÛ¾ÔîúøßÉÚÞý㟣¯ü¾Ü²%ˆ]Û—¬¶®®«®Ÿ¢¤¯¸²®ºÈÏØÈÂÊÔÔÉ×ÓìÿÞÂœ§Â.Ó§¤°³¥ž†gyš­º¹ÀØ þ£™ÜðóößÜï3UÚØÞ¼…¸ož®·›WDkï—Bo²ÑëωÀÑÝÛÙñó - - ðþÏ–’±Êº¡¬r ±%ÙțЌ¥«ø Ø¿¥ôÀ ¿õ§:2D#ç×Ò¯ žÆ%šœ¡˜c6*þžÝÙä˸±ð“Õ­šµËÕ×Ðä¢ÅÀkÕÔ¹Ó)¨‘žµØ0ZS8ôðôÉÁÅ8 Ë·ÎÓØÍÖÛÚåÔÎÄ°Ûý îæãÛÞà´‘¶+øÀ"»óæÕ´šŠ©©³´ÇÒÀ¯Æ½¶¼Àº»®±ÚçìÝãÎÀ²¤±×ùóÇ°ÇÆŵªŸ¦²¾¾»¦ µÃ¨”Ì4/æؽÃîæÖãИ€âþE÷ø°Ä¢^Бax¢ÔïÙ¥§¸Öëõæäÿ÷çíåüåÀ Àͼ¡¿s2sóòùÌΦ -ÈĤÒáÌ¡©GÅÔÇ¡át™>2dcëÚǾúH“Œa$ÿ÷ØÖÖÎÏÎÕÃÎ#jJè©©ÃÅÓ×ÌÈ®‰¡¯”qÀë'_˜†̪¸Ùàç.PPDæØÀ®™•Øÿîåü 乲þµ—¸ìåÒêðêãƶ¬›†¿oª¬ƒ†¨øJ⹧sW¢ÇÌËÞåãÖľ¤«¨¶­®½ÏÞðáºÅ¹–‚‹˜µÈÀÐäá͸¸æñ»¥ž£¢¯·Åßçõ"É¿º±Âß÷ÙÍÊ£„„g‰Î¥¡÷Óš²&Àœ‰Œ ÅÕÀ¥¢½ÕÖðÜâÿ÷ðöõÓæóÜÊÌÊÈÞlYÂ&þļ¶E/½¨Áº­ÀRldÛŒåos¯¬’s<-óÒ&7y[õþëäÖÁÈÝíÙÒç'1 -ϾÊÄ´¦±ÎÛ¥—r¸èRÉà!ÐÁ·ÖÝ<HG»¯¥—£­Ð'-üË°©ª¢¹óãÇÌÖιšš±¤˜ùN$Ë*`ò ‹‚S4Âð±ÀéìÊ ¦¤š¨²ÂÈÕ××Ī·¹½—‰˜Ÿ¨»ËÉÒÀ¸²ÕSUË›¢¯®ÅÙÅ»»Ñ¾µµ¾§²½ÑÓØÝÖ¾—º_–‡²±ß=…š=Ô×™™ÂÃ÷ÁÓ䞢¶ð$>'÷ÞÓ̳Ïüÿòæêî dzùg&>ʹ²}†x礞¹àõ ùX鉦?Wîš”> -ëÔëòÉ¢èdr&÷ýÜÙãÄÇáß¼¦Ìþê³¼šŒéÜ«–¢ª“ȧø‘il岬Íéý3/ñÀ«§»ÅÇÛîÿ õà瘟Š"ৢ°¿»¯­£«°ÀT¢£«áZZÇ‚qzˆžó‰‹ž´œš²°ººÁÙéÚɦŽ©ÁÓãÛÙÒ¿ÑÑÁ­ žÂóEmIÛ·˜”§»ÌÔ»¿ÃÁ ¶Ã½··ÑÅÒçÙ³¯úÍ韻Ճ"suDüÒ»­¾ÙØÕû ÿ²Ž‡•Ú ðè×ŧÈ0 ý3,k§"~6/ðÒÀ½—ßÒ‡±(çÎâç'Æ‹w›á39 óð¨ÄО{Èr·FûýêäòÈȵ˜„ÕÛðëÌÈÓ»§ÅÝÏ—…«¦Å[¦3¢í®Ààëâî -×ÈÈËØä×¹½ºËíñúýç°§ÑJ)àÒǨ®¬²Á»•Œ®óÕáýèûøRL¹…z¹áĪw\h‘¯µ¥¼ÈÓõ·ÓÖ®©µ¥¤»ø42æÎÊݸÂÞ>+ íÖ½ÇÓÊÃŲ±¿æÇÂÂ×âÊÍŲµÏÞÚÍåcT=œÀÏ%ÀOdIN*ýÞèñî'öíº¢Žh8v¤ÐÝûÿûáìArY/6<4]Çd-Ô§ÀÆ[A"—yÙ½ÁÖÁ¹µ«½ÛØ´¼Ëó¿“„šÄ½‘Sˆ`öÃwJ(üîÞ¿³˜xy‘Âë úݱ›«´ÚÊ–Ž”¬¯3u•sÇݹÁÕǼáéàÚÒÐÖÚÅ­œ³õ òÓ­¸fGóÒÍàæÆœ–Ÿ¶²“Š¹Bw‘[v 121´‡x‹»ä®°Œl†È÷àèæá×ĵ§ª§š ²½ÁË/mYîÕÌÑèôÉÁìáÏÚ -âÜÁ§¼ù=gLøÑͽ±²Â»ÅÞÚÕ w–§Â)îwqpnM3 - .0ᢀvd[5DÑ&33Sz|jP,B?SÀ»()çŒx§ðÒÃh°¢õ#ǾÝƦx‘ÀÙ׿¨±çß©Œ•µÈ¸‰Lwy•Äi¿,ÝÌǾ³žz{¨Õ D0ѱ¡¤³½¶§š¶'NÉy¬ ÚëáÓ¾ªÊûòàãÎÀ¶Á»˜žÈ"îÅ¥ÀÚ"<Ú¼Äà⹎Œ°¯»±¹ã¦ïûìÐ.j=÷Æžv•¾Àˆ¤ÉÄè õãöÛ²«º«žª°ž°¼ÇÓP6êÈÆÏë"'ëÅ×èÞ¾µÍ8íÎŶ¦Ò7÷]ù­§©ª¤¶ÐÍôëãqœlŠ€…Æ>ýtˆ©‘waB ùô'U@êœv[YYEDšõúþ2G†žbLWfERK#A¿¤àg\Hö¶äößÕ®ÝòÈ¿ÉÒ¦ÊÏÌÚ»¹¸ÇÃÆÏÞàÅŠ€»Ô=ÏVB9®²ÊÚÏ» ª×ó#8ôѼª¡©«« ¢¦¶)ü#ÇY7XôÜ̳ºÙìó㻶³ÏãݺÀéÉœ ÐôüòïÚüêàÈ°±ÊǾÆ$2^c…(w-ÄãÉ’ˆ—ˆ“¦òÿ.h`Ʋ³«©­ ¤»¿¬µÇÀ»ÝâÏ×ÉÂÃœ4òØßÔÉØá÷ûÓÀ¨¸¯«Á8/ª( «¨°¦¶ÊÖÜÜ-!²Úó9kÈ%ck}vƒlþïÝôOK齇‘Š”ÝñÛù"RŒ|D(891g€In´…×€ŸÙ³k9Á<IL¶´ÚçËÈÞÓ¶©¦°°³ÍÅ­¡ªÊ¸Sà}הʢÎê îÚÏΫ¤ª«­´ÖðßÓ€ |‘„2üâÝÄÇÉÊÑØ´³ÐþíÀ¸Ýô³”²ÎääçôØÀ×ÙÜäÞÑÉÒ¾Âà£áÜÖë1A¬u̪}€~—˜¡¶Ôî€Ãj皧´§“‹§ÇÄÃäÒų³²¼» ¼.±¨)ÚÙ̹¹ÖßàÛȧ¡¥°§üÕjº¾Æ··Ìåݿա¾YžÒÿƉ‡ó6:lœ©0äÐÐÞ,3! øêáS.úõðH_A;,5;J‹»µ´£-ãÙ/,°wⵓޠ±Ë·ÁÞ÷æ¹¢²°¹ÚϤ†—èI\äÔ­¸8¥>·fjÔñ4E@ñÇÕØÚòîéÛ¿¸²µ¿ç.8àê4‘›6àÏÀº­ªÈéïÞ×ÜîëÞÕ·è"µ“¢¤ÊàòèëáÒºåóñíáÛÊÞFOf->OQXÚÝbÇ“de‡¬£¨€‰¹ïy壜• »½¦{ˆÂÕäúê;·¬y|´?<Ô®³ª­ª¨ËÎá²®¦œ¢±³ösÜÉ!´ÙÝÁ·Íîïâ)ùþúÔAk#v cj¬Øº€,ï×ÔÑÕìôÚ2àêÙç* îùûP^UYyŽäé–ÿÞgɺž…3ü°Q±‚¨¹¬ÅãíÌÚÖÙÊ©¥¼ÝDzÜ«†–0ÏSàŸôšOñ ùÈ¿ËÙðþäÕÏÓÜ×ü*>%ÝÕö()@¬Ò*¶–ª¹çèǽÎóá»Ííµ šªµÓÚá ãÍòù÷úíÆà¤Î´ÀW…Ü“@™gn€„‹”¬†u“×;Œ\ó˜–­ÈÕȲÌâÊâ÷Я†v}¥ÌãéØ­­²¶´§¶ÍÒÉÄÄÐÕùùÿ/vqµ½Ó°Ÿ²à¤g,Ö2A)ʹ&—¥ãêªqEH5ÝÇÛÖûó‘n‚…~o‡ªÝïøø\¤—do`œÏa§T«Œ:õΦ>ï¹E²Ë×g’‘šÙíüÄ®ù8J‚”Kð°Ž|€vì¼æRí¤ ðÌ×Í°¿ÔøööëÎÌÀâøAB ¹Ù!)R{Löª|“’¥Âìòôþà»±ÐßÝ·Ëà຺²¯¥°Ìÿ1P1$  ÷íÄ­,?ó*=."Î’îwZˆ¬uWw² ¥¤´êôÍÄÊ¿áóôæŶ¾Ç¹ÑÞÀ¶¨­´»¿ÜþÜ ƒ §£´³µ±Ñãê>0öêH'Ĥª•ªÅåö=âΚ;Ï";,'Všøë¢|WVwh0ÚÇ×ÙjV[.ûüVÍ$~ÄÈ—c@S–w”3Å©¨4á”ÝEOqv€¦å  -üúôÝ),:~ U×z´ÐpšÈ)ôÒ4ô²š¨µ¬¸Æã÷ðÞóëÓºÒÏïWb+åóÒØ -4̸¨«µÅÙèñøø½ËÙÑÃÃÇðúή¹¿«°É)l» j5$ -ã­Ÿ¹šÑžZÂTõZôòM”n|¡œQS¬ª¯ºÉæõÜÐàÛÈÀðñÚ÷º­½´Ÿ‹¼ÌØÙÜõýâ©‹•©¸Á©š³Â߀™EðÕÈ÷bo󫨲ÍïL$ï‰õk›W KœÉšlojm`‚©cÍMùG[+ñÅö?g³ò±~A8‡Ù1KÆ¿… þ 0àYÿÅRÑà꓈Š²ÚõûðßÐÆÕéêÙŠÍ‘¸•œŸçˆ˜’Òwš¨À‹„´ÒÉÄÝãáé&$þϧ§íVwåÕåÚ±ÁÛîڼǺ²º®¾ãáÒÕÜÕϽ¸¹âëÕÆÃÄ¥Ð6‡¬’y`A²šœOkòÔžµÓ~‚ £‚fŽÁ»±¦°ÙúÙéáǧ²ÛþñêâÕ»²²­€„¤µÁ®¦¶ÊÙÚ¯©ÂÚÆœ§Ãåð+z|άÀ›£+ËÆØÝàÚ¦€Pø¯@.ïïTǾ8÷x‰ql_vÐ+nåEãÐQx@ñF], y@¯9%m¹*ú¥y\ñÍÏú& ñµ8UJ—‘®¶ÌçñâÅÂÊÌºÌ šðÁbÿåÞêH­O‰oÙ/ª‡y…—·ãÓÌÝöäûKHûÇ«§ïV`×ÜèÈ’·ñüÕü­¤£½Ï¸Ðïëà×Úé -ïÉ«¶ÀÑ>#9NGωàŒËº©ÕˆûÌ iʶŸŸŠ¬ÎüŸƒ‹Ø"úÔéÜÁ¬¾Øñäéë¹»ÈÀ´•€v‰”¡¬©®Ãåÿ þìÛ˱¯Ïç -:Y-⣅—ôƒ¹`ûóÖÏ!rù­H3øÿ™ÏDŽˆ%‘|YT¶^’ÈÂ!äÔè -NgN) -/R ¤¯°Æ`¦ *÷rÀÁñ0 ¹? ân¾¿㮺®¢ºãäÑÍÒÞà7ÀàŽC  0Z‰£†¨‹|xŽ¹ÐÒÈÉåûíÙ_(δ·â%n6åññÒ¨¡ÕóŨ­µ«Œ¶Öãèþûø÷ýãÙÜݲ£¼¹Ó  çêÓ¡†‰÷  ‹aÊ>´VÁ¨“yz£ÅÄ· \ No newline at end of file diff --git a/build/lib/WORC/exampledata/elastix/img1/slice086.mhd b/build/lib/WORC/exampledata/elastix/img1/slice086.mhd deleted file mode 100644 index 355618b6..00000000 --- a/build/lib/WORC/exampledata/elastix/img1/slice086.mhd +++ /dev/null @@ -1,13 +0,0 @@ -ObjectType = Image -NDims = 2 -BinaryData = True -BinaryDataByteOrderMSB = False -CompressedData = False -TransformMatrix = 1 0 0 1 -Offset = -67.6484 -265.368 -CenterOfRotation = 0 0 -ElementSpacing = 0.703125 0.703125 -DimSize = 256 256 -AnatomicalOrientation = ?? -ElementType = MET_SHORT -ElementDataFile = slice086.raw diff --git a/build/lib/WORC/exampledata/elastix/img1/slice086.raw b/build/lib/WORC/exampledata/elastix/img1/slice086.raw deleted file mode 100644 index 342317d9..00000000 --- a/build/lib/WORC/exampledata/elastix/img1/slice086.raw +++ /dev/null @@ -1,185 +0,0 @@ -š¦¢§¤™Z^w{ƒ’š’ƒnifo‚‘žš‰†s„›”zttx‹“¤Ÿˆƒ––‘’—‘…~vo‹db}„…‹š›˜…{Œ§€–œ™Œ}u}ƒ…y¨œ’Ž‚š¨§¦¤«”¤¯¤Š‰”©¶”®£˜’Œ•œ› ¦|Ž˜¤ª«™‡¥œš°¾¸®³´—‡‡’†“’†Š””†Œ™ Ã©’}’¦²ªœœ¡›§©›¬¯©¢–¥¯°Ÿ¢„“£›—˜¦¢¨¦™‘“•”¥™–—Ÿ™Ÿ ¯¨´šfelxunt‚†€‡ª¥˜¬²ÊÓ¬°´£‘ª¾ºƒ“­°±Žž ¦—ƒqny‹Š}˜¡š‹vr€‰„ŠŽ–•˜‚t‚›©§¤‹|v|›¥¡›§ª˜”‘“ˆ‡ŒŽ“”{qslm{dTa‹œ’—œ£†|Œ£š~~’˜ˆv{ƒ€Ÿ“Ÿ’Œˆ…ŠŽ„x}’•€}…š¡œš’…‘«©š…€Š”œ¡”}…‘›¦ “§©›œ†€›¯¸ª©‘†Šˆ|‡…‹‡“¡‹’Ÿ ¹¼¥ – ´½¹ª´½©²°¦¡®¯“‘‹ƒ„‰‹˜’•–˜œ›•¢‡„•§ £š˜š”‰¥Æ¹¦•qgo–Žˆ›•—‚ŠªÂº¯±¬§¤¨±‚†¡¥¤ ¢ª­¨š¡œ§§š”‘…~ƒ…|•››”€‰‰Š€Œ™{tn€–£ª®›|q{¨¬¥››‹ˆ€ŠŠŽ‰…šz‚n|„ov‹‘…”…~‰¥±š‘™Ÿ¦ ›‘‹Ž¢–}Ž”›ª­Ÿ€ˆš”ŠŒ™ ¤¨€qv”’ŠˆŒ•– Š‡¡§¤¨®§¢¬¤¡¯©¢˜©žˆ‘•‰Œ•—Š—™žŒŸ¥Œ}ƒ’¬£‰œ˜ž´´«¼±¥§£–¡ …“||¤ŸŠ›Š}ŠŽ›‡|‰Ž•–¦ §›“~•¾ºŸŽ‹‚”²¥ž—³š”›Ÿ©²™‚…Ž†•”{‡™–vŠ‹Š—˜…€–“‰†Ÿ–„‚{v„•šŠz~‰…„wŽ}[a…š±ª —‡‚rr€””…vqz„“–“˜˜©¬™—•‡†£¢ž ­©™Ÿ¢’€…–´´¢¦§ ¥Ÿ¥¦ž“›š“££ŒŽ—Ÿ«®•›¡“Š‹’…Žž—ŽŽƒ‘†…†‹Šƒˆ—••˜£¨Žˆ¡ª«­¦™’‹¨¾¯Ÿ†s†œ‘‘•œ«¾¾¶¨£ –¤³–v„ˆ›‡‚¡˜}ˆ•¢©°ž–—¤¦ž“–™‡€yt„ŽŒœŽ‚m{‚‰žžˆ„—žŠ†²¹¯¼§—¡¤¸µœŒ†™¨¢Ž„ž › ¥¥–›“y\c€Ž–Ž„ˆy…Šˆ€„w|{’‘¢—‡›Š„vu€•›wo‡ŒŠ‹‹  —ƒpw‘±¹¥™“‰xix€•w|„„}Ÿ±¸¦ —­¡¦°»©¡“uf_q„“–™Žƒ‹™¤ªª³©š—–‡…„Š¡®‹‚—–ƒ‰†‡{|„ƒ}Œ‹Ž¢«§—xu…’¡¤¢¹­‘„ž”Ž˜‡}|ˆ‚…°¾µ ‡µ²®œ²¿¹«¢–¥¥—›š™ •ˆ…¡¥Ÿ”—•¡¨§¥Šš¡žŽ‡zzkhwstu™…”†‰‘¡ž™¡¥•€‚£ž™²¥“‚‡Ÿ¶«ƒƒ‡ “‡‰Ÿ¢™œ‰ggˆœ®Ž{‹¢­ ‰‡˜‘‰Žª·°Ž„Š„‰}v…”‘‚pp‡™™£¬››sx¨™‹ˆ“”odlw—”‹ˆŒ‘ŠŠŠ‘¥—”Žyz„Œ†ˆœƒvqdO`dfuˆ•’—…ƒŒ–˜ž—–•}o‚ƒˆ¢‡‹Ÿ‘‰““‘•…ŽŒ‚ƒˆ›ª»Ã©“¤§¥œ¦¡™™ª“~€‘“ŠŽž¡¬½¾ÆÆÀÄÆdz¨¡½±–‰‰—ŸŒ“¢ª³›ŠŽœ«¦œ’”¨š”£“‚…—†‡Š”‘Ÿˆ–•‹——¡­²¡­ªª£¥‹~t€˜™ˆ‚~›µ¯ˆ|‹•Š|v‡¥šƒ•›Š•}š“˜žŽ°¶Ì²‡†“›ŒŒ“›…}‰‚Ž€…ˆ{€}•šž˜¥‘ŒŒš©’ƒ€y‡}lqo„‹Š~„‡‡…x‚Š‚•˜…s}†w}‡„Ÿ—{„…‘“¬­ž™™‰“—•š˜zzŠƒ‚‘›¤£¢‡’ŒŒ‚er€‘£´È¹œƒ¢„„†•››Œ~š«¬£·¿ÄÆȯÃØɲ¯­˜™—xryz‹“—£–—‹‡Œ™›‹|}‹—Ž“Ž€ˆ¥­ŸŽ›­«§“¤£¢¨’¨Ã°…‹£³ž•™ž—‰Œ”ƒ‡Ÿ”Š‹“Ž‚²¸¬« –—|yš¤§Œ§¢˜š‘¤´¥‹Œ•¦¤³Â½Í¶r{pq„•u›„u‹ŠˆŠ}rn‡˜–…v„••—­£¡§™†Œ†Šwx‡Œzu˜š“’›¨¦£§‚yŒ¢“‹†y‚®½®¥ŒŽ‡Œ•³º¥«¹©†€””°š˜’„y‰ª¨ ™ƒlc`‹Œˆwƒ€…˜«µ§•{‚ŒŒŽŒ ³©Ÿ¢¨š›¤«¢šµ¸–…mqlmtŒ}‚}‘¤›š|—”Œ’œ––{m…Ž˜˜°«¡Ÿ›¦¦–‘¡œ‘ž¥¥©ž£¦‰x ¸¦’¤œƒ”‰–˜‰•–“‹¯ÍÁ»¨’™¦’®­©š‡•˜£ÀÁ¬›¡–Ÿª¸¼¬Œyip{eipŠˆw‹®¦€Šž‰…‚Œ‡‹Ÿ¯»°¥“sumr§Ÿ‡£Ÿ›žœ…›ww¢Ž•—¤¬ª›Žš¢±²¦—•”œ‰‹|s¡~„•‰‚wwš««Ÿž«ª‘†›—‹…qomy…š–‘„‚˜ œ¢š’„{r|Šª¶¢Ž€ °ÄĽ¯¤¨¢¯¸¶—‹œš…‡‡±®€~‡ŽŸ¥›š¢¦¨•uª¹Ÿ–›•‰„‡ŽŽ‹š—–Ÿ”˜‚‹•‰™«®²…ˆ€ ´£’‹~€ˆŠŽˆˆ…¨¥ƒ† ¥¿ãÑ®¯”¶±‘¬¯’–šŸ®Àάš§˜z ³°‡ŒŽ†‡~}ƒ ‰Š~~‰š¡™ƒwŽ™˜¥­¹º´²Å×ÙÁ³ž”“’’²Ê¬¦¯±¹·°§š¢Œ}‡•Œ›˜™™—¦ª— Ÿ¦£§¬¤Œ‚ˆƒ‚…|~–‘“‡zŠ £™˜Ÿž”„››‰‰•…nm`g}˜£ ¬­šž‹Ÿ©Ÿ”‹„†¦¼¦’‹šš«Äº·¯µª­µ´¢ˆ‰ ƒ|Š¢¼º£¢š›£°½¾ Œ‹ž¥•Ž§±šŽ“„–“…‚’uo˜ŸŠtrš¡ª˜˜¯¾­‡—Œ’¦ ž£†{žŸ¬‘ƒŠ• ”‡›¥®Á·«²š³¿ –ƒu¢£š«¬¨¥¢„]a¤À­|os‡£’Œ‘œ«¨¥“‰Œ™š ¡”œ¯³ºÆûºÉÝéڽ¾½Ä¤™¢¡˜šŸ›“«¨¡§¢–‘š•–œŸ¢­±«¤¥…ŽŸ¥¨®£›—‘”šƒ’„‡op|~qnx‚€|†žš”› wliw”´²¤¦¬©¨’Š›©˜Š‰‹¤¬£Ž…~’³ÅÈ¿½³¬°šž¤¤‚‚£±€€›µËŤ˜§¯¹¹¢Žv‰›–”ž˜££ŒŽ†ŽŸž”~‰‘Šzju–¶žŒŸ«§™’£¥š–› ›©£¥›…•¬·£‹˜uvƒ¤•„‚•¡®²¯žŠ¬¢~p€‡¢œŠ—°¢bZˆŸ­¡‡u{‹žŠ“…¤ª–Œ}wƒ•ŸŸ©ª—”¡¬ª­­§›¨´¼ÀÄͶ§¤—˜‡€ˆ‹€nr}Š” –‡vŒ—–Ÿ®ª•£•yt‡‰“–“¥«£œš°”™£”}jdbkjScrzƒ‹•žŽzuv~pm}©µš˜“¢»©—‡|qb]pu—ž“„~wzˆ¶Çµ²»¯¨¬¦µ±–‰–ª£¤”ª¾±‹ ¸½ª ¤†‡ ¨ž¤›§¡Œ‰‚•˜—¨«œ–~¤µ˜ž›y€˜…‹Ž‹Šzš¢µ»›Ÿ¢†’¢¢³Áœ“p{Š‡—Ž˜£Ãµ°±‘ŽˆŒ‹Ž˜“„¢¡…€w¬¬š”‰Œœ²¬—œ‘—„qlirzw‹ŒŠ~•Œ•†wn““¨š©­›‡y{zv{io~Œrv|odvƒ‰zzx¤ˆ~}y|ˆž‹‚wƒ˜˜™Ž†~yvy~“ŽŒš•{rs|–œˆ’Ž¡¥œ”me”to…‹z|ƒ”¤¨——›—¯¬°œ§ª¨¬®²£†‡‹ž¤ƒ{…¨–~}¢º¬›™ —‘œ ¥™ˆ—ŸŠ™œŽ¤½¬œ•€y­­ —†qy”¡“~vy~€“º®³°˜²¥”°ª‘—•’‹wy‘ž Ÿ™³³³®”‘ Ž•‰w–¢€qŒ•«¸®¡ž’¬°¦§—œ„‘Žˆ}€‰›œrv~…qrƒ˜˜¦—‰” £›˜‘…~€zƒ”š‰q^`eqri`asƒ—‹‰“ˆ~|p…“Š…ˆ‚~txuzŒŽ‰yŠ‰‹€‚—˜Ÿ³¾·™pjx}†‡zskw€l\už©‡zŽŸœ‹“—˜–š‘€r€œ¡°£‹’œ²¸¡™¢£§¢•w}œ™ƒŸ¢‡‡‰”›Œmh„¡‘{Ž”Žœ«™Œˆ„„–¹ÓÇ«§ž”¡¯žŒ˜†‚ £–œ¥—£©£š™£¦˜–¢”}†¢³¸˜§¦¾² š°±”…„”œ£’›¦¬««©£œ—­¡±­™©œœ¤¨Éø¯£¤œ›¢›zƒ{~ˆ‰œ›˜“Œ–˜“}ˆrsutvŽŒ……†‡…|qadntnv|Œ˜‚…‘‘s€~hf‡€…‹yxvnej‡“¥º³¯ nltq…ˆ“p~¡ªž“ˆ––‡˜›ƒ”‰…‚fh‰§¶¹³¯§¨¶¸š‘ •‚‚†–‚”„‰†“{ft{{œ“…zpbz¢œŒš’­µ±§˜ªÃÌÕêíľ°ž¤ª¬¤ŸÇ¼¹Ã¹¬¨ž¡´¯§®³¸·¼¯–™“}…­¦‘¢“±´ž‹¨¼º±¦ ™”—¦“”¤™­™”˜ˆ ¡˜™}³ ›œž»²© œ›ˆ{wu…–†u‹’’Ž–yž£Ÿ¨­ª›—”ŒŒ…zƒ“•“ž¤˜”  ¡—…uy’„optz¨om‰ƒ‚ƒ|€~„ƒ~„{†›‡ŠŒ†~€wk{‰Š’…y|‡†…’Œš¨ªŸƒ`h—­ ‘…‰‰vzžž’’“¥›|Ž©¾º¿±©“’“ƒ… žw¢™ œˆ€Œ¤¢˜‹’–µ­•˜ºÅ»²¤®ÕîÛÇ´ÒâÛæþñêã³ÇÊÉÀÐàÔæëÑǸ±¹³±·¸ÂÈ´¡œ”˜˜‹Œ‰ƒ–£”ˆw–³‹ƒ›¤·½»·ŸŸ©Ž“”Š‚†‘»º•˜“ž‘›™ˆ}Œ–Œ‰‰‡‹z}€{ˆ—™–œƒ„ƒ€“–¤¨—™¤¡©œ˜•š‘™œ›°°ƒ˜¢¥ ªŸ–˜£‘ˆƒ~„_LbŒ—‚†ˆ–©µÃ¼«°©¨®“†‡pm€›¢ž—“—ƒŽ•gq¦º¬‘”‰†¥¨‹Ÿ¤¡¯§ˆš§­¦¦š’„ƒŠ¥Ã̼´¢¡¡Ÿ£u±½ºÅ¥¯¦ºÅØÍÐÕÍÚóù ïÛíÿ  -ñäéþóýëÞò íñúâÍеµ¾Âı«¸²”˜ª¦ª£“–‡“¢®¿¥¤«›‘’Ž‘¢²»·˜£•ˆkbypii~­ºÆ¸¥¥‘‘¡šž«¥™¦¥¢›š¢©¦°³¡—¥¬¦š™˜¢ž¡¦ª¥†~„Š‰’Ž‡’’’”–›ªµˆ‰Œ‡”—ž‰‰‚ux‚ˆŽ‘wv{¡»¥ŠŠž¬³¨ Œ™­–xwpx˜Šœ­­™~˜œ‰”˜—„ˆ¢°®• •™Š‡…ŽŒ–”¬¬–‡†›¦²ºÀ®¬­ÁÎéäÌËØÒÍÖÀ©š²ÂÁ¾Àµ½ëð öùèûôÝñ-"-(óéæåãêîú  ùÜÌÔ½ÔíK·ž€z‘®¡±¹±›£¬´ÌÌÉÄ°¢ªª¡¤ž¯£¦º­§«‘f_Ž„wq—ÖÕ¥´·‘†€†¨œª¸¾­¡¦ª¦š¥ÃÃÇþ³®­“¤¬¨ª½«’yu™¤¯µ¸·¾¾½É¸Áƪ£‚€ž£§¥–Š‹¡³»¾± š¥¾µ–ŽŒ—žšˆ~€}ƒŽ‡„‰™•—˜”„……‡’¡¹­“–†‰”{{‚†v}zyŠ•µ²”‚„™°®¸¾ÄÓÝÝàõ%+-'ÿõÚÚÔî  úþîâïìß×ËÃåüýæÚÐÌÈÊâìÛçîê üÝÎËÉÒá  Ñ®²¡†‹ š¦¸¿Á¢³·Ò϶¹Å³Œ ©–¡®—š¤©­§¤˜ƒ“”’ŒŠ¡º¢©°~v‚‹š‰†‡”—š¤¶˜ˆ³ÃÀÌÓν¾¶ª±¸À±®±Ëäæßèö -úðñáßãÙ¿µª¿ÎÈÈÊÅÅÐÑÕÖæÔ¸³ÀÃËÏÑÌÈÌÇÏϺ¢šš±¾± ž›‹r{”¥¯¶¾¶£—ŒŠ‚€˜ˆ’˜§‘‚„€†}{Œ€‚ˆ‚vqœ‘v}‹ž¬Ÿqt›¤²Îà )66GP@/5:>5<-þðííõüê÷ùþïâäÒÉÉÃÎõþðô  ûòõöíßñççþñáëòýóÝÏÉÏû,ÔÃÏȸ³½ª¥Ÿ¯¦µÂÄÁ²¬Â­˜™‘ «½«¤šˆŒŸ–“‰™‘Œ„†|›•«“z{€œ¬ž©¸¯¨­ÀÌÐÒÚÊÛéæàììõò /5$ úÖêüùëÙÞøöúññèâìü ëÜɱ¤¡£¦¡˜••Žo~Ÿ²¶©Ÿ‘˜’‰™žŠŽ˜•|sƒ’ƒ™—™Œsƒ˜Š’—¢½¹¾Æ³”˜ªÇãõñ%#-;F,!)) !ÿôìÝåêôþ úòõóêù ÷ -"3$#)  -9IWE ûåÓâ#ÿâßìçÂÌΣ™› ¼×̼°§§ª­£•‹ §±¿Ã–†‹†zuŽ‹y€†{‡Œwpp~“›À’Œ•¡°º¾ÅÉÁÃÄÏ×ØÑÆÍàÙêõü4úû ý ÷4=+èû).25(+(þíéãñ òÜÔ©•~m~™¢ž‘““|oqx{~™¡¦·¨¦¦›ª¦œ”™¢©•ˆŒ¡~xz‡ž©•‡±±³ÃÐÃÍÖÕƹÜÿ -ÿôâØê -<94$(. ÿ $>889 8D*$  1-$,@\=/2D?%BINm€qO3-39.   üúëûúÜÏÅÁ¢š¯Úտů˜•‘ŸŸŒ¥µ¢¥¶Ž…y†Šrmh^mˆŠu†‘ynvžœšª¶´­¸Ä¼ºÕôþéØÑÆÚæòÿ âæû '!!/;8FU@! üèÞï ,CA214  ýïëèîúæ÷õåѹƒ©§™†|„}y~§¦­«—’¡¨·©¤¡±»¯¥¡œ‡……v‘¥§‘‡Œš¡™œŽ¢¾ÎáúûüòÿïÕÃÙð "4-!$6  ',9:ONIPIaZVK87^ZI:EaztQHPVggs}€ž™{hTOBOZ71'"ÿþⵧ ‘Ž²ÏĻ̫‡ns‰ŠªÍ®£u{• –…€sv”›••¡žˆ»¬¥±‰¯ÃÎÜâáåæææô ùëãéþùùüÿþõúóïú )/605=FMG?üþùáÌÕä(;D( -ýô7;M=3&ùåË¥Œš«®‰ziswv‡‹œ¦¢€{l”›œ”ŽŒ‰“–™‚‚Š‚‹’{gbj}Œœœ¦¸ÙöèÑÏèñÛéãÌä .*!#DDH`iWdprc¯ìæ™Xp¢¨nz‘³¹¦|f`vvv…•™“wvUaj6;6$ .)÷â½½¾¹½Á´ÂÍ¡Šxmku·³˜Šma”º³´³}ƒ–©®¦¯¤°«¥²± Œ¨ÛÚáð $0 øýæßáêèý þúÿ!÷þÿ# /&*80'94üÛ¸‹¨ÈÌÛäè/-&âÏâÿ$ åÜÍÀ¢Œ¦Î»ˆ…‘£™ž–Ž‚y~}‰„…‚m`iu„€zy€}zlruŠ™ÈØÛåü'>-òÒÍÑиÊáâï+",1(>UT8O‚³Á½¿ÚÛä/‡Õ9^3ˆÐÑBª}50:3:O¥lehciˆ„}y€wfrN'0: #óßËÑÝêêØÙèÞ­‰›Œ}‚Ÿ¢© ‰‚Š“§®¨‘uu‹¦¡¦µª”Š‰” —’“Œ&6$ úø÷óèååèñ,21!ýøÿ '2.þ"'3'ùäϬ’•Ÿ¯¾ÆÎîìðÐÕïüüøëðîЊ´·Ÿ£šŸ—˜¨­‘£§Ž„yru‹˜–’tt„”™“{€‘¨©¤›Œ“¾°»ÍÒÉÒá÷ÚÙÓ»µ°ÆÅÍíéåù4CYZQC9x±h™kBW’Û -á kÖïОJ[$5X8æÆ—¤j]_ez~xhcjYSM("&/% êëÿûëðþ -íÕ£¤¦ˆ}”¦­”—‰tu™ †Œ}‚ ™•¨”€€u}…ƒ“Šðý -ò÷  -+HO;-ü (/6;-õÖãèéü ,$05#óØËÔ¶¿ÆÒÊÇ·¶ÙíÜÎÕÝåü%÷öèÐ¥rewkc}…‰‰¨©‘—›Ž…|v{‰‡ž¤Ÿ›¢˜Ž‹„Ž¥¨®¥‚¬·ÔÝàÛÓÜìôÑÏãɯ°³¸¾ËßßÉÅÝô"%-7%!W½ ’3m×5.•ö8ÆBTáR£Ó…±*ª7Î)¾ˆ†‹ƒx€`ZVFBA4$#(9JB-ûÿýùêí5$ðÖĤƒŽœ„”~rqvœšœŠ~ƒ—›Œ„y‚xv‚|€€ƒqÞì÷ìâó  ''..3DI?FS]]@5;=E^^QSO<-;LR2ãÄÆßßç%?McrJ ÷êßÏÅŸ›®íë×ÇÃçôçæðïêÁ¦­¤nrw}x}›¢«®ŸŸ˜”–“š¦˜’¢œ‹…ƒ‹šœ—¤¸á -$Ta"÷öðÛáÜ´²ÁÁ³¹ÁÎÛÓÕá((-9:@ždCÒr‹n®ƒŒ »¨[Uü_]Þ š×VÒByý¥‚Ž‚jdwmSJC@ILI@@DH7*284% ùëö## -ëáɳœ‘ˆœŒyz`„‹~y˜˜¤š˜Œgs‘‡•Ž‘‘rjˆÙåòäÞçúÿ -#/ )Sbwweam„²÷öÔÈÔĪŠdÝÈÖó÷êùøþ  S^D$"ÿïâß×Õ¬¹í÷æí¯¿ß+  ñãêȲªŽuu‰…Œ•¬´ª•š£¦•Ž“™±Ÿ¡¥£Ž„…“¯²× -O“âARÙ1áÊ®¯ ™¢¹¼Çøüÿ LeDIay&JÑ#Q‹®í!øè¡ÖyZ " jV ²T¶RÚ3¡pmP@*I\CC?LHGWRDCT:*]iMEîû áѼx‘”yqˆ¢““„®©„™Ÿ“‡}z–¥šˆ‘“u‡”‹ÿöúîù4H8-"".O‡£Ê_Å% -úëçÁˆM -©8öÏÓíöêãëòç×#&óÜ×ìââÁ»³´ØáÛ¡§·üNfYIH>>!îÍŸœŒ‚‡|‡˜‘†n‘§´ÅÆ«ŽyšŒ­µ§©¦®ãAÀ/’ä9H¹Ÿ÷¼®¥ “¬¦¥Ó  ûõõùCb]=@€@I¥ÊûÇ•UѾ)¦’-ÜŽÿ( ñ½“ ³. öŠyûwNQD$8G=RTJUUK/%76ñ1Va<÷óûû +øæíÆŸ’›”Šƒžœ–”„¡¹¬ƒ‡ƒƒ—°š‘ˆ€§¢…;øùù --FSFFRRC%.†!ŸVÿo{ö=Y{~c=/ -˜#‰ØÁ×ãÝËÓæÙÃÁêüùëâ¼ÉÓί¡ª¶å߸—‹‚†ÅNã()ë¢m`O>%ÛǺ¯¶´À®¢©§¦²³ÀÛμ­«­Âá $/Y{Äûl¡¼ÀÑí#ש«µ´ÈÆ·Ø (*4Kf_\Kmäü1‘€*ošˆ‰8}j=ŨÎï¶Ö$ •–^v&45)($69 ëäôöþÿÊÍè! -ñÝáÓ¾¢´Î¸—‡‡”Ÿ®¬©š‰‹•‡|‰”š ‚™£šŽŽ þùýö.((2,!Bù¿cëßôÚ×ÿ&ô“(°MÑÌÔÐļÑøãàðüÛ»»ÆæóÜ·’|q‹Ê×¹£‡ps§K4¦±´‘[ ýÎpb>óóùг°³»ÄÆó)!J‡Ô7Ub{hF'Gpö ¾›¡·ÆÍÉÓç!3>1/+9OVc`URL¥:«¸ˆ~Ði2ÄÌq5€j¾DБ¼"H#'º?¢!$"(+õéäàÎÑîûÜÂÄËÉʸÅÑÑÛŨ¬å øäúàµËÐŪ”ž¦¨®²Ì´“–z€–}z~‰“‹‹õòéçóý$#6›€y@Ê —±?,*Nf``AðµŒLðÏÓÑ̶½ëû ëÄÏì÷Å®˜Œt™®´˜‡‚”¶ Æ8KRO,5RVjLë­ˆL-4;&     +-'Bx¥Ðý1[a^pgJè·­¾Û(ŒÐ•ƒ‡£¼À¾®Çï '-"-GHMA09Qt‡|sÇZ7¨ñ:] [µ+Ì¢{ˆ¬Ç«•“£“†O&=U:$ òêðàÛäɶµÐ·›£œ©¿©Ž†‹¤™‰–‹¡ÇÝ÷õÿǺ¾É«¢œŸµ£¹Ø׳’˜Žlhˆhjs‚˜’‡œä õ ú&13,TÆ‘@ÀG%·ûnçóöá¼–}W9;+ õÒÏÓŽ´Ü!"+& ÝÆËÒçâÚÄ®›xdx‡“‘¢¿î\ÆÓ­š™—ªÉÚ*I;B;ÿááçäßË›˜·×àÓØ;o}N7Ý«ˆli`WGWx®”¡’‡ˆ§ÀÉáÝÒî"%!'ROOL?;4SM35guj~õT¬‡/Ã}d.!*?XE820+þîܺ¹×Õù»¬Žyvzvw›—znuƒ{z€‚}ŸÝèõ &#÷Ñ˼Ÿ¥¸¾Øèò᪛˜^Ml‚€‰”–ª²²ëÿ+ER6&/=D>,9‚u®½²šs?âÀ¥”JîÝêëßÍÒÏɪ«Úþ 默œœÁÔʵœ|mr‚¥´¦¤°¶ -v‡T.DEHctzŒ†›¼Óý7V<3VŒœ‚BA\aM-A6$ Ñ–q\0  ú1[‡Nü©Žš®ÑÈ»Øí"$?CKl{uiY?.NO/,HP?4_}QC:0,ôê÷ ìè+&þëâл¹«››½¶§™~em—‚a[{„yi_`kd[hx‘²×ú++(#ྷ® ÈÙå÷ÿõÞ´ª‘n`˜–” ²º¡%$ ÿ0DL502+487/(@€®Éʧ‡vsx…kRK@1üÐļÎêôÑ®«°ª¡€†ž¸Ò·Ÿ’{Œ¯ÏѲ„bde€’¬¶¨™¦ÌS)%  08;+!?Me‰ÆÞüCO;Þ½¸²º³©›€mPB7!øîî÷7²˜<í±•®ËÉ°°µî$)#(FIKTbniGAI>)6co1%:#ßÇÐîùíèéóüëÑËâÞËÏØÕźššpy›see\tš–}}ƒwmgkd[?.:]c¬ã ;'/49ýîîøýíõûéåÖ½¢‚oa™±©¯±Ç»“5>"øèððúH]^I=3$ #MV?ùôþüíéêòèÜ´•œ»¼²—ƒ“…™œŠ†™°ÁÀ¦¡ÃÈÌðÖŽha‰·ÄÓÛÁ«®Æõ.]^G:*0%7:+2DIBP¬¼ €W>LR9/'5Q[WQD3/ $ôù ;„ŠPøЬ„q†³É¶·«Ð#45*7)//B=:X€yZFþ`ººi13"õÐÔóëøöôßÙðéàÛ̽ÁÔµ’£¯¢ž§›”—•rlˆ ~€yˆ‰…{zˆˆdv{ZK0$2*&Ni”Ú"$)('ñϾÀØ÷㹎¿µ˜ ¬¬zf/$ø×ÉÛìåö1/%"' -ïéëåâö íßÝîð̲ÃÎÇËÈ •¼Â«Ž›¿îüÛÇÏ×Çͺ­Ãàó -ß©˜š¯ÌÛëÜÍÁ»Ü^ˆfD<+'%-=30PS4>PlX4%$H@**=:$ *..( ï#'b}f'˱¬¤ˆ”²À¾Ä¥½<5":1&9Iu‚_'ØÒ‡ØÒ‹7óüõÿûéÚÖïòؤ£ÈŬ•z ¶¥•¥§¤Ÿ—‹•¶²’¢Œ“¥™|pbh|zqrqQ0)'/& SÀú  -õÒ˜ÁùþùæÀ½Éª‰uˆž~Z_Ç›x…zrz„˜§Êëé×ÌÕÝËÆßçÌçúáÃÀħ¨°¥“­È»Ÿ“ÎH|HôÁáÿáÒµ«½Ý÷ñÐÓ¶xw…‹Œ‰¢‘š³åAŠzWgZ+-#4615-01   !ýð#01üÛø2Yu’fÍšªÃ¿¼ÄÊÑȹÔ2EG+(&ø;HWW>µÁúC• 7èÓôýúÁ¬½Ç¢Ÿ½ÖŸm£¨£Šp—Á¹«» Š‚‘«´½™z—˜sˆƒ{n^\iw~‡twjLA?>A&ÒºäR²åüûÿ   ᯥÁßòâòáÔ̶“‡zˆ‚hiψ`UJE]s{„™µÆÉÇÇâ1m” ©ÊðòíãâíéÜÌ×Õ¾¶®œ­ÆÌ««0ëŒýÎç÷Ô®¡¥ÞíäÌÕÓ¥•†{‘ ™ ¦œ“®é,t„xvcA5:5&01TWõõîì -"5*æY”–…Vö¸¤ŸÁÉÕàèâååí8S^C0ÞÇÒÿ$0)Ü­³£¸ìô¬¾ÜÛÇ·ž…ƒšˆ‡¬«€‹£§žŠp¼²¹±–v€Ž“«©‰†Œrz†…ƒm•š…””‹ŒŠ`^trTîà-oªÜ &',üèÔÒÇÈÇÊëùìÖ¾£‘x~“•‡`SE).JY^dj€Œ—¢·Ù jµÙí4Zp†¥¾¼ÌÏü -ùëÁÃÒƯ¾d+G¯íس £îÿîáÚÉËÌÒÖÎͽþ_©Â·xW@?@.ûìù#WS)éèÿ3!ëõ , S­ƒ:íÏÁÅÍÚ×Üççäßù'%!þÞÞÃÄÎëòòå³ ªŠjzª«·¹¯®¬´©‘•“ž±¦¥Ÿž¯´®«¤„‹²¸›˜“£–”ª§’‡wƒ†“†fp¨½Š”œ–so†|Z0%0#HdŸñ$ %íûýèÇ°¯¹ö -ÕÒѽ¦uq‰’™ªµ×Ú·¶ÃÏÖÍÃËå%3A=?aš»Í×êNm•Åò#Iq©ÛðüÚÁÄȧ®:Ùâ>ÇÉí ò¸œ Û éÛÞ×Ô¶ÈßÜÓ½´ß9‘¸À†A63( úíþóþ'$ÿíñ -</õ ûýßùèÛõC]ˆº€îÖÒàØÝÕÌÝéÙßæýþøÕçÙÍ¿«¦»ÑÕÞʤ¨²rv“­§—~…Œ›Ž‹†~Š…’š¡·±«¨©…ˆ«¦vn˜˜™ˆ‘˜”Š“–uŠ”xxŽ«¯…” –…k|Œ}cX_W27IaË -ï ûïàÊÌàȱ¼É̘f[u~‚ˆ™·Ä´¸ÀÏÊÉÊÖÛæúù @itv–Êô,xÝ.Œ¹ÁÃÂüî9«{‹ºÎíΞ‡š­Íæû ëͽÆÓ¯Öõ೬Ø&y¤ºŠC(0,"#ðéûúØâ  üÛÉàîüüòáÍÝÿ$M‡ÊÍhúÖ¹¬Ã±­¹ÀÓÝäëïóëØÐç߶²¼²ÂΫ §­® ˆ£¸§‹v…˜›…}xn‡ —Ž­·¢š†Žž–x{‡Žyˆ’ƒˆ––—–œ©™œž…‹¨¦€g{ysa\iaQHS`{‡¨æöêÙ¼º±´Á¬Škjuu¶ÁÛäÅÆØÜÖàóûâàõôÍÈÏî ååõ/wß[ò_¨ÂÝàïë±~˜²¼¬–†Š”¥­´¾ÞäêáõÌض¢¸Â® ³ýfª­—c6)07;# ßßõãï  ìø  #8*   ÿõ%Tm¥åÛf íП©±¤®åóü þçá'Ť‹s{“œŽˆœ¢”²¿¨»¨«µºŸ»Ö¿¬’ ®œšºÁ¦Žšwn…‹“¤£¶©™œ¨˜‘™–šœŽ“„…§Ž„{š—z—•}uT"ùgÍõ.*%$91êſ餬¤••u•œ×ç(øÍÏÛàî ÷åÜÚÀ¹ÂÒòþæçðÕÖï×ÈÅÖØÈÇõYéƒp²ÏÚЭ©¸©­¯“Žœ““™–›¨©¨¨¢ ž½»¥Š‰•œ± y—ŒkJB-'%;ïðçö)D\tjfw’¨«®°Ž‹}agqpY`–¶ø×kò×­±È½Þ(E! .4ããõè Ø·›Œ„{‹‹‡œ°›ž¹½®ÁÚÚµ°Æ¿µÛêØɱ³ÈƲÈÓ¼»Ã¸{‚”­¼¿Ä±©Œš¬³švŽ‡‘—ˆ~‚™‡…™‹Œ¤½¡€l/Á|LúI¢4Ü'/7-::ýøÕÅÍÀ•‰|—Ÿ®°àõG3ëÞÒáþéÑĶ¸°¬ž¸Õéæò çÆáãÖÝæëñæ¿Ì+¦;×C†¯Ë·Ž‰¦ª ±·®œŒ€”›œžœŸ¡•‹‹»¾­‘±¸·â<”™~dgq]]†¾Ò»…Zn¾&6ING`lreC/.óø@5 +¯DäÉ¢•·Êäû. -˾ØýûúîÒ´£œ’®­­ÁÈ·ÀÆÓàïÿäÿúùëËÒñì°¹ØäîäÈº»¿¹¢Ž…}—®¦™‹rt›Ž„yz}‚„{ƒ{€uC)¡üp èíýfÜ|ñ)!+ õýòíÌÙäÁŽˆ†”§¯¼¸õïö2I&ðò -îÀ§±¼«¤¤ž®Úùý! -Ý¿ÏÏÓ¿ÇâòÀ™°ýl¶<„¡³žs|¨¥¥®¸±ž ¥«ª¨°¹©¢’€—±º·¡›³µÅ€«±ÓëâÊÅÁñ.+! FsedgV7þýáãáÝèüëû).ÿØ‘óÕ³’œ˜Ÿ¡Å÷ëâñ4a]ÎÜÿ îæи¢µÂÇÙÑÍÎÓÊÀÐÐÛÇŸ¥ÁÓþþòâÔãÓ£š«È÷ÝÅÍÇ»ÒÒÅʼ…˜¤§‘‡~cz™‡sjmk{¡žoNú `D±™zqdx¸Õ÷{L² ü ôÑÀÉåܱ—£¡žµ¼»ÝÃÊòC]X8.-ɧ³ÖÍ¿»¾Äã - ÷âîøйÆÎƳ›¤ÉȾ¿ÓðeÂG’¦¨‚ay„”“®ÉÉÁÇÅÕÛ×ÒÇ·²¬Šv†š›šœ £Í.œÛ äà¶ÉÐËÜ×·°ª˜{†~dC3'$-GSXQMAQ_aL2" -í϶¢†mš¢¦½öñÖí3GM&ÞÖðýãÀ»ÃÄ˵±Á·ÂμÎξÁºµ¢Ž…¢ÉÓ××´©ÊÔ½Ê˶œ“«ÓIJȵ ©¯ÈÕƳ¤ÃÒÄ«™†€vlˆ˜“ˆmpz~ »¨^É ~V(õݯ{sgU`±™­$Í»•â  ìǵ¬ÊðÛÒǵ¿Â¨•Å¿ËÜ)hh_fc"Ü»ÃÜÚËÌǾÈÿÛÎÂÅË×íâ¾³§¬©­¸ÌÁö‚NÿP¥ª|gowuu‹ ­¾Ä¸¹§œ’˜¥†mpr‚‡„‘¡¦Ö)\‚“vjI)6PB=.çäïùù$ ñ"èÎÜ ÷ÑÊÍÎÒÍÑ»® ¦¼¾ÆÅËÚßʯÔñîáíéÖ¾¼¯¬º‡‘ §¥¸ÍǼƹ¥‚‚¢¡•ž €‰©¼«¥¼Åźż¡°·­ž¬°¹ÁÀÓÒæàÒïš…{’«£ š|t~•­Æ‡êLçÌŸ€•—‡gNNWv š|wÙˆi1©öùáȨ±ÛôóêôõÕ—tÕÑØäû,8J?íåÝåØË¿·¶®ÌèÿõÜÒâ÷ì¼±¾ºª¯ÁÇã!ÍÍX†¬ÂĪ›”fQcx}…Œ‘‰‚­Á–mq|‰y‡ª¥“›¥ºÛêÚËÙ¿Ó÷øúíÛÑÙüúÙ·¶ÒÛî Æ´ÛùêÙĹÒÏ­¶¦§ÐÏÎÏÁ±«­µÃ³”Žš³®žµàí½×ëêм°›Œ–ˆ}{‚‡š¥™—¥€x‰ŽŒtdpmyŒ–®³©«ÏþÛºÍ×ÀËÒò»ÈÓé輿º§‘›¨µ®žŒsƒ—Žª¬@Voå„–‹˜Žymqy•œ˜yy”½4ë±mõ$忪¼ú )౓àâÚÔåãí -èÔûÛÎÉÁÁÌß 4ãÒ÷!\LàÂÇØ;Õìý™iž°»°›œ˜|qz‚uq‡‡‰z¾³|g†ª›œ¨§—’Ÿ·¹ÆÓÎÆ¿¿àÚɦž«¶ÃÇÏÄÊȵæðØÕÖåáÌÃÉÌÉÞÌÀÒಶ¶§¡Ÿª¹ž“°ÅÀš›£šªÝÛÞ ”xt›œ|}œš~yx}yHP}‘ƒirv~¢©«ª°¹Ð .<ïïèÎÙÖŹ®»ò[cÆ»§±Á¸±šŽv¦¬ªµ«AЛ—Ë讬‹‘¸ÌÌÈ«ž…jyí}0 ¸ Ø;Üñ"ÔÇÎÛÚǺÃÂÅÑÏ»µË -&:&èÅÇÉÌÜ7!)aš©_úßż××ÇÍé ^T'Œ³®¡ˆ–’˜›’y}ƒrcw„‚{in¤¡‚Š ª“’¡•˜ ¾½ÍÓÌõÅÊ©‘Š˜·µÂÓÞÌ¿§ªÛÙȹ´³Ø¼¸¾²¨ÊÊ´¶Ð¹“™—ž°•Œ§ž¾â̲š‰Œ–‰˜ÃÔ¾—„Ž‡›¶Š•²±‘„‚pMQ} Ÿ‘Š•š§­²¬¶¬£Ñ)/úÖ»´»¶»¿Ä¾æjè˶¬»Ï·š™›ª²­£±µžîÊÃëóÙ½´¸ «ÅÏ -ý¿˜{}auÀ6ׯwûÿøìßõ úìÔÕι±¼ÅÈÀ¬ž Í -ý潯¿ÉÊ]l„â Á>êÝ¡œš– »ÒâÁU”•Œ“‡‚‚z€Ÿ¢Šƒ¡–„„‘†£–‰–œ–ƒ“·Ä¿¶«¸ÒÜÔÍÍÁºªœ‹€€²ØàÓ³¦·³µÑ×´ ž¨Àù©ª¥¥Œ–º¼¤Ž|“ª£š¬£±·œ‚•‡†Žœž˜•tm™–ˆ‹v‚¢¦¢ž’x‡Š‹‡“¿Ã˜€’­·°²Ã¥‘—ªËÜúÜ°¨¯µ®ÎØñH„>ÞÐÜËÑÌ£¥¼µ¼¾±°º²©›%ËåíóÄŸ¦¯¥‘™žÃ)@꣮›†m‹½ãt‚|òä  (+*ÇÒÙϳ­¿À̱¤»ÍÎ×Þͯ±Æú92ð„,ï̵¨’—“Ž…nc€³7#£–†‡¥©ª¡¬¿ÞôÆ™œ¦Ÿž¬«™œ¾·­ž™’·ÞÎÄÑ¿«·Ì³¶ËáåÚÙØк£¨ÖæعŸ¨°·Øáǽ¯ÄÀ«” ·ËƽÃÒÖÁ²«°¾«²¼¬‘}ƒqi|†‡’‡ƒŠ‡‘­š…pqˆ—Šš­˜€˜´ž†“²Ö«‹”¯±®º¤ž£ÃÊÓճȰžÀÜȹâܶÍðóທ¦ž½Ä¦‘Œž¨¸«UywæÒÉϧžœ¿¡‹—»m5ݾžxry|ºvhXÚîû$-!@:ÍÓͯ–‹“¤ª³¼¬š¤®³·¼¬¢´Âò¦kmŸ"Õ¶  ‘Žœ¦›‚pew”ˇ¥w©¯ ‹š±²ª±»êúÜ¥{–´’˜˜´ÕãÖ¼¶²½âÄž¬ÀÎÌÁÃÕ××æïîíôùæÚÚÙáÓôª¸ÅÀ´©±ÊÐÌÀ¬¸ÏñíâËÜìäÒ³¼ÛÄ¢«¾¦¤’n]~•‹Ÿ¤˜Š‰œµ¬­¶³Ç½´ÀÇ·¢»äÞÏäõøðÜƸÉŸ¸¸ÕØáàÞñîáÕ¾¨½µ±š’¾¹Èíú渕‹™´ †wo‚Ÿ²º–&?̳ª£™‘Œ– ~z’ö}vÓ¬gVw™´KM;Ê7%<yd5)’¨Àµ®’—ž«ËÝÇ«Ÿ©ØÇ© ³îŸ¥ÛRôÀ ˜”–„Œœ­––‰s‚“ áÍç—µ½˜}{ˆ±ÑÌØæÖ¼’•¿Ç«®º¾ËÙÚ±ª¯­¢šš¶áçéíÚñ¶ËÍÅéöñòÞàÖâãÑÒÝ˯¡¢ØçÖĪ•µÛåÛÝõ÷䟴ǧ„ˆ¼ÎƲ¡‡œ´—¨ —£«œ¬ÔÖòPl‡Œ–‡n_BUs‹„„…ž§Y)$ ,=A?5+% öéåź°¦¬¨¡ªÐßÞ»””´²€~“—›¨¾€­šÒ’ˆ¥ŒŽ¤—[Wx³,H쾜†umšž¢ÔhNEõ -P…p=žŸ®¾ÔÖÇÔãëú÷Ú½¬ÖÚ¹ã®ád_À¤§¥“†‚xˆ’™˜…z}’–cˆÓÁÅž’”§¶¿Æº¯¼°š½À¶½ºÈÀ²Úøæɯª¦­Ã¸¹âýðÜÅ®¤¼ËÆÒæéÿòê÷üëÙËÌÅÆæüøн«Ÿ ¶ÃçìæâÔǹÇÒÙæ„£×ÕÌÒÀ¶¥Ÿ®¯¦Ãê#Xpr§á /$ëÙÚäïõñ -A觗¨†®¨£ „F8B6" ÷ìéÛßÝ»¯º¿Ä¸›‹Ÿ¼«ˆx´ðÙ˜¡³»«ôum…—›¬†WV|ÛŒ’¶¦—‹’Ÿ±—ÄpiF×#Vò¶¯ÀÈÏîíñîòô×˽ÁÎ"èqÝ̦µv™ª˜‘‡†}‰u}™µ¹£»ò‚öã໯Ÿš¤°¤£¨®‘‹’}–°ª¨Ž§ÐÆÂÀ´ª¿ãáçìÔÂÃÏÒÃÀÎÌÐäÿùæõüþìÞåÓä ýÝÛÜÑÓÌèøѶÄÚêïóïÄ“’žŽ–¨¼¸Çù64>g™¹Õàì<,!8; -øèé4 5R<î×ËÁ¼¼¬Â³–ƒ‡zT0&242/) "$ ößÏÑĨœµ½¬¤Í÷Ý°¹¾¤™r“SŒTa‘¡ ŠzŽ{Ëe¢)Á˜‘ž”…¤¯™šÍV3YI›ïÝ ÷ßäåßÒÛòâľ¼°´Øÿ-@ÆÈ;ëiu˜¦·¾ªƒ~†‰Œ„y¤àÝ­Œ³²'õñÌ¢™§¯¢£§«¦¬¼°‹tƒ¢¡Ÿ˜my–›žšª«¸ÑÏÅÀ©£«¶·ÂÁÃÔáôèïïâÏÚûýêüíù 2@Y8%02ü æ³™¯Ñôäåâ» œ ·Éè -O©Ðå×Òåààêñéáù  õìîö ò×û üóæâÕ¶¦›€ƒ‡zVGS]GG:=:71EL@÷ØØÒŬ³³Â½«¹É뤤•õ -’~“š¥•„š¦ŽÓeAÉ ¦ ¥¸Â·®£8YmƒîR]pz"éìæÖ¾±ÂÙ˽ƼÀÖÈÑÙLt‚ŸµÁÉÀ§‡wo…’˜Ž…±ð߯£±7Y‘ï«›¤¢œ§®š›§½Ã³¢‘‹ ½£œ„ƒ“Žz†¦¦ÉؽÁ̹«§­´³µ¼ËíâÇÄÊíöèÐÐí!\ylR[`73\ŽY%-1Ó ³ÏÚÛÈÆÑзÆÖé --“çð×ÄÇÅÛèê ²Ú÷øñýëßÃÓíÚÍØéÈ»°•£‘{oZhgF-PxpG29BH0AYcS3# 㮨¸¬ š³ÈÅʵ§¢V…Ñ~ƒs{…y•ª¦¼ K+îÏÆÄÚËÁȱ”²Ykp.³#Jß–·*×ËÁ°¤¥±Èų¸¾·Ð5<d=ν|‡‹–‘°ÅÄÉ­šœ¦¦¢™®ÝâÙª¢ºpÓÆæÃœ“••–•Ž¨Ñμº˜‹•£•‰¥©µœŽ•³¶»ÑÜñöѵ³ÄÏ­°Áº°§¬°ŸÇáÿåç8P‡Ž’jk~wv’ ˆbm|w|IäÕäîïêÜõøE~ÈåëâõèË­¦®¾­•’¢Öÿ ÿãÖâûÕÁ´±ž€mJq„oWJ;8&Owb82K\TC=S]L<>87+ùºœ©”Ÿ°µÈÛÒ¥‰pò"¥mtƒ‡nj‹‘‰—ØJ¬eòÈÝáÅÃij•˜•»k‡JÔ%å¬Ï¾¯ž‰•±·¸¢›¥¢ÀHQâ?n[s}|x{“œ¥¤¬´¤™šŠy†©Æ»š‚¬]ª¢ÅÁ¸°§¡Ÿ–§¤®¾·œ™Ž„•’…¸ËÛèμº¹³¸ÐóìÛÏÐÄ»¨¨³¶ºª¯¸©Ëöïç;U‘ª{™“˜£«©­£zt‹‘Ž¦wÿýûê4ZY=MŠ»»Óçóü꺽ìÑ©”­¬¢ŸŒ´ÖóùÙ¿ÚÞÜßëõ×À¨…dMXmVN4-$*RI=(7VZ\H7:KVDCVI3îÚÍ´¾¸µÈáäÀ›–f²šº{€•ªœ}mƒŒ‹ÑQú·ØãÌž–œ¥”{€{Ø–ˆ®yú³½¦‹‹›«¢«±¶±¡—Áh=6nËpZbw~zz“ÙßÆ·¹¯š„ˆv€Ž‚`zø̱ÀÁ½¼½ª‚u—¨´¤€ˆ˜§·Ÿ”¡¿Ýîå½±¼© ©ºÉÉп£¸·˜š³½®¢Äé%hR;Ibw‚™‚jš’‘‘‘Œ‚ œ­²ƒ8ýýìóù n£Šm‹ÄÖÉÍéîóÚ¼Ðçŧ¼ÁȾ³âñ¿ ™¼Þë׬‡}hnu|‹„xsxmN7%AWM7DUL_R;E6?J98T_6"EP$ìغ¼ÆÕîãÕßäqB‰n†¥—tw”¼¿¡ÊYÿÖ%ÕÉÁÅʾ®Ÿƒ†‘´õ¡Ããžyt染 ÊЫ§¶Íؾ“º€·¦uQWcy“¥ã/*õÓ¿®¡‰ˆ‡}pmˆ±-騰­©´Â±›~sx‘´Ï¼ˆŠ§ÁÒ½–·ÒØØο¥’Žž¢µ¹¹­œ½ß¾®º×Ì¿µìD˜„„oSd{Ž¥¬„q„¬˜{“¤³ÉÝÊ™G ó÷ñó4‘¾Ã²ÀàÞ¶¯èîî þ½´»ÈÜúâ -'#öÁ³Œ¯ÎÜ£xh^QKHQjgpƒ“„tO47YsP<NQSN:1?E:D5(PV3@XN< üðÏÁàçî - -Åé­®fvyt¡ÆâË«¡úœœÍ°¸óôâÓ°›±ÂÛø.û<7Ú¢’¤ÉѪ¦¼ßÒ¢¸fÖ]Ë’h[{ŸÊëÿ#é;®¯±°£¥§Ì+É R±Äºµ²™–®ÁŲ¶§¹Üäò ¦±ÝØÄÖãÚááòÒ´š”ž°²³«©ÂòÎÓç.!Fa’„„‘kWv“£¦pd{¯Ê²¬½ÂÀÊ˲e '-L~³ÖðÛÍÁ¥©äÜÑø ÿêÕÚØÌôîõû×¢ˆŽy‘º¶¢cb\P;>XiXZl€jcVGWpvZW^\K..6AYH>/AgFGVBCI-!&K5þÈÎÜõõäªUl6‰lst¨½µ¯©“ÝLWä¥å,1 ïØØáÚócB[î㿱§ç&ïÁ°ž±Ò¼ÝW¡A½µÞõäÄ·ÇÞßåܾ¬œ´ÊÈÈìPÿ¡7—¹ÈÖĸµž‹žÂÖâäï¼ÄÒÛáи›žÄÉÛàæÔèñØʳ§®ÂͼÍîìÊàëý'Qg|g_|sclŠ¢~lw”‘{z·­—¢·¨š¾¤ŠW,Ow†”…§È¯¤’µÂÒÞÁÕñèÒº·ÐÛæäÒ³³‘m\XVu‹—’sIYdXKTomVZwsPIPi„aM^ghbDTuv}xkN_Z;FVBXhI<Vc^/þëÏÁÃÄ©—ëÄix¡ÙÐŽsy„«øB¯…ƒÂ!K.øéØóõdYËîöâ͹ªºàïÛÍü¯ºÉß,=’9È$¯©²’¬«°²²´ý™g;°Ñî·É÷©˜Ž¢Åâ&ñ›˜ž³¶¥°¹¨¤¤²³´ÀáÛÕØÓǵ½Óßÿõþ7OOVcc…xpvcjŸ§•Ž‰€o~ˆ‡”’‚{’¼ºËîáÎy"c†œ› —€®ºÍîãÁÉÞÕÚµ¦ÓäÚç鱄oaY^dj}ˆaMjqV`mhYv‰jTRWˆw>6[kyuƒ±áñàܨ}IPHQQUP\ps€\2!áÙÞ½µi®‚ºŽ°á¿‚gd•Éö+¸‘ªµè  -ÿèâëÞõg¢ÉûéÊ­œ˜¢·ÇÊʸ®²ÂS½©‚ÛNKC¦‡¡«™¸éóÛÃÖ@ûÁY¿Ð³©¨¯Â̼”—§°ÀÙïþ àvš˜¢Æȹ£—¤¤œ  ¤±Ýùíàåç%BORJ1Vrn|†nr†ypuuqruˆžvwŠ€wˆŒxŒ§®ºÙúÞ½*5cx•ÁßÙÄÅÇÃèõÐ×ÔÏÓ¼ªØЪ¼Ñɾ±—|h`jsyfJ7Rqbn”u`w}XP[fm`PMPr²ã -?sy€Œ€6â‘q`6;87Yp{{P:[OçÞϺ›La-‘´«‘„„©´ªÜ)ÏŸ¦Æ¬®ÌåèüõçÛÔßÛꦼìÚ½¤œ ±®ÇϾ±¶¶Ò5ñ$I–Ì¡ü¶™•¸Ù÷%øμ¾‰E¦§µÄ¨—§º¯¯«¥¾ÉÖÎÆǵ¨…†¡°ª®½ÒñÞÕÙàºË¿±Äô-Njƒ˜š~siV^z¡Ÿ†i`i“’†am„~€{kQwˆy…¤œš·ßР™ib‡žÃíô繺ÉÇÍÛ̵º®¥©´§…Œ©¤”¢Š…eCOw|fRFk{hf‚šˆcccUex‰jLEm‘“¦æ>‰¯¢¡Æíë°¾v5)!?gfc]Bav_.ðßÒËË›ûÅÒ„š©Á³®ü㽧°¥‘²½ÇÜðüø×ÑÏÎÞ¾ÂÎðÚ·µ¸ÎÒ×ÉÕ×êýûð ‰X3Ÿ0G觧±öRl Å¿EôÍjµÂ¦«Â½­˜œÄ®©°¿ÕÑÇÑÊ´ª ™¨ÆØäÝÓóñòêòãï÷æ&8Xkoreg~§¦€ ¥pG^kuhz‚hhš™‹iMLG^yrnVAozs{vx½¿¥ˆzz–œ ºàêïÖ½ lW|§®°¤›©žƒ‹tsi\FSZIMlŽ„ks…oi™‡rxŸµº¹Œio§¶¡ßO}¨Õ˹¦Æâà¿£k®f99QTOZSWo‚u2&õ÷óÏn„U¡ž»¼º¸¶Š¦Æªšƒ‚x©åÛÛ " ëÌÊÍ´›ÇÜáÓŲ²àÝÓȲ¾y}B9ŽCå/«oˆ••šêA†eçøx;ŠŸ¨º§ È˸§Šœª¸ÂËÞÙÀ¼¿°œ±°¼ÏÍÐÛòüðßÆÐÞÕõ>JSkª²²ÁÀ”dgocªÉ±x`c:5X€{ryt…†~cIVgm~jUTes‚Š°¾®‡kƒ˜¥°ÄÝãÑ«‘yXP^ˆ›´À³©¼¹‚z‡vaqv]]`qto|†‚zpbn]‹¼Íʺ¹ÕèÚ¶› È # -M˜¬ÆÅÓëƪÌ×Ò¨bAî‹iSR<32Bfhsd6-"  è±#(Ǽ»¦¡²§«¦’„ƒ¢Åïæäÿ"!üéÍȶ‹§©³Æµ­¯¿Å¾±œ¿)¤Ày7<kIë’tz‡ž£Ê+\Z ;ûËm²¹¢Ÿ“‰§ÄÅÂ¥ƒŽ­ÍÐý´®À¯¬ª¹ÚÖËÕÚÕÐÚæËÔÏÑÙç+z¤ÈÒÕ¼™¦»˜vƒ…rœÇÊ®‘{XVkuŒcTpˆ›•—™vytjqo{š¹½®ÀÏ¢‹“­¹²ÒØæÅ„jlX<A§®Ìëέª€_]fJRnc[jqy`z‹ˆ€{ƒ‚u­ CV=+òÔ§ªä@ma¬³«±¿áß·»ÑÞÆ¥€;Í®†O)*#>C5?7'&;7 íÆýÝħ¨¢¿»€’¡ÇÞéåå:(òÝÉȲ£·Ó»ºÃ¾¾¿Ä¿®´Ã×Tk.øÝÛÔ³¢~qœÍG2 -`a4“˜•œ¢—Ž”‰—·¹»¼œ„™ºÐÁª¢˜ª¶ÁÈÚéØÊÚéÓÀàóþüþãã*šàÒÏϹŒ^K`[q–_q ¹°ž…|‘š•Ÿ‘yusuŠ°ÈÀ|Xf‰œª–‡–šžÃÊ“€ˆ£§«·ÃØð·{shG&6e¡”¯ÏǨ|lPcX<>Xj‚pbxŒ‚›’Ÿª°l’£†wG⼿ÏÝEEeŽ±©²®µ×űÂÉÑÔ¸z+ó¬nfJ "<?=]AóÔуsT»¦˜³Ì­‰rw‹¾ÄÄÀÖåú7ýåÖÑ͹ÌÔǸ¸ÁÈÎÕÒ¶¼ÕÓàåÒ¾À¼®¬ ›‘€Š¡ñ-+ñbiC¥£“’˜Ÿ’Ÿ™¨³£Ÿ§¤ÆÝØ®Ž|y—½ÄØßÞä¿°ÈÊÒéàæþ?MPŠãïÈÁÒɪ{dkatŽgQr›§‘ˆˆ…‘‘š—uw†‹‰¡Õžp“´Âº£‡’¯¿¢pt¡¦¸¼ºÕñÕ“‡|UQ`u—ºÉÑ»”ylqpa_bGY‡‹l^g~…‰†¯y°¥ †oIîêñø'8\‰¨²¶¾¸»ÙÛÎÈÒËëÞЋXC5ÓžFõû'\ekfV*õÞå£ööÈÜûøʘŒ„ÍÔœ¤ÌîèíÎÒÍÎÄÑÃÍ¿µÎÏÖÀ°¨·”œœž²ËÁ²™™›ÖñìåÐksNžš¸¾¬±°—›Ÿ‘‹ž›ƒˆ³îܬ °¡˜¥¢¢©ÍáÑ¥«¹Ùýçõ OŠ§À˿ȸ}zˆš}†mbW8Hgƒsƒ‘Ÿ|hq„~v€ŽŽz‰€—©±¬¦—”±¼¤d†«±ÅÖÇÞË„u‰Ž‹Œ‚®Ä´žp[ryvmaXbhcdgSr‹‘Ž ÜeºÞ©z|u…tG,BW’™™ˆ”¦·»µ¯µÐÇÁÌÏÈÐØñÅpZqYé}.Ehl{[C5#úÔ†ÅÉßûì¿ ¨ -)符ÊçÚéöåãÞÔÀ½ÐÖÌÐÌÖßÅ­›—£¦£š”‰ÅÍϾ®µ½èéÅÅTlM¬³£©Ä¼²¨ž|‡”™˜ˆœœ‘® -3ñ¶µÄºš§ª˜§ÑâïÒÔϾìõü%I‡ºÓÀ¢ ´©wqxŠ™’{dUR^^c„”†cj…‡¥­¤•©·ƒ`bby†š¹¦…ŸÃ±yYg‚Š­ÓÉÝä§MA^}s„—¼´…vjaVWjciUMeYhŒ ¤¾ýX„š­¦dq¢²ÓïÝƪ±Âdz”ƒŸ»½µ»·»¨©¸ÍƬÕñÁ—Ž„_2ð˜Z?JNQWSD>>;çͼ_kXÕÂäîЭ½ TÐÂÒòñ÷ûþöòíåËÃÈÃÉßáàØŲ™ ¡¦£•‹•³ÂÍǸÁåÕÁÃQ_V¡ª·²«¨¢¢ªÀ­š—µ½¥¡¯»G紭ȸ¦ÏìéÎÏÔéïòÜÃÂâ#@~ÔìÙ±˜·Ñ¾—t‡—orp\fskqx~pp~Œ¢—²Ãª¬±£~pt‘·¯‹ ¾šc_f˜±µ±ÃÀ¯¡mKWj‚Ž˜¤ÎÚË–bg—¤{Xb…‹z|]v‚€‹u‚§è>„‰{^<P ÇÒÝéþ麴‘–ˆ¾ÜÔ¿·À¹»«ÁÌ¿¨ÑÝƺ´Q$ÏpAKGKOJM_L72ùÚÕ±Ü ½ÁШ¥Ò 5 áéìëçÞìîãÓÅÏÊ׸ÕáÝÝÓÀ­“½Ç©‹ˆ™‰•¦–Ÿ ¸ÏÙæD4A«ªµ­£®§š”²ØÓ»“šÆÍƵìKk–Ž¨¼›´ðãÓÊÕÞäǶ°µÇàýqÍÞû®ÆϹœonvF+PrbXo`rq[crµ¬¦’º¼«£˜‘ƒ‘…’ž—³¢‘˜¯œaY\“ÒÛɸ¥ztmo|§ÜÍÅÔ¸hF]„š{| ª´xwšÁÄ£„‘¸ú[±˜cFT‘ÄÉܪÍáÏfŽÍ°«×ÕÁÃÏ»·Þá¼Çξ×ÞÑââ€EU¡YK@5E\fshjf2ñèÎj]>»ª©¨ÅÏäôûøêàðàååÞïéáÎÇëÑÔÞʶ·´Ÿ£¤ÐÔ¯Œ”¢§ƒu„®åÞÄÜI**·¶’–š”´½¦Ž¦¼­‘‰Ÿ¬¸ºðJ3Ü£ŠŽÁÖ°ÐæØÌÓÕÖ¹¹ÏÓÙäñ =Š¦§°Ÿ¤¥§§™z‡m5\n]€ª™tzi]_h°À³ ªÏØκŸƒ{ƒtjyu}Ž¤º½ [:N{Ëǃ~“k``{~y’§ÊË®‹k[M_ƒ„mg“«¡€€Å õË¢¡ÇzÄÄÇ¿º×ËÆ˪—©Áܾ‘Çÿà½ÃŹ±¡œµÚݳÓÙÖü÷ü÷Ô½°€b.å¥m?DEKSXt€}Wñ£Æ‚Ö”©ÏĸÏý ïÛÝä ý ùæíèÚ¹°§¥¶ºÅéá±”œ®¯£‘Æ&ùÔþ雫©š‡„ˆ‘­Çªto…–”ž°¨ É(>ך¢¢š«ÐÓ¶Âʹ´¦’ª©ÄÍÕû  -.W¬¨©¯­‰s‹Œ‹¥žk–¶Ã™€Žmsn‹Š˜’µÏ¼ Œlhnx`TJiŠ¤¦•zO;Jw¯®uffilƒ•¦ÔíÍÎÉvDZPo¨´“…OY¢Ëºœ˜ô̪µr¡¶ÉáàñõΨ˜µË¶¯²µËå̹²¹Ç¿•«¢œ·íûõþש¤È¯i@õÒ”QQI;&BumbZ7ê½ Ö»ÊÅÂá*õØÞñ/;0.-îï.ÜÍѵªÀÖéóÚ³—„›´½¹ÜZ„ÒÔ£ÏÀº¼®«–†Š‡˜¡…jˆ¥±ÎÙ½R6ÅŠš¸˜»ó亥“Œ•‘œ®ÀÆÙëìHt‰Œ’©ºžfgrŠ}|°ÓÔ¦’•˜–šŸ°—†u{–‹žlWk‡•dP†®¡–³‘bd`x“†|fK[ƒ£¯¨œÙâÏË•qswƒ¢¶”Šox¢ª² ¯åõó#q§¤©¼Å¯åòõ¯³´Á¤£¤¯ÐÚâÉéæÇŵ§ox¼èïëã×ÒÀ¯©Õ¿T#ê×µt?87(>VYcsY Û¾UQ8¦š©ÎÔÝdj çý,;LK4ûÜòBV@òôݪ­Õîôê¶}¸ÌêdêÌeb<˜«°¦¢¢”|~w¢°–•´¿¸Éº°ì㮧­­«¥¼ÐÆ»­§¿Ê­–£ÂÌ×ðëì 6W|xx{‚mft~‘yl€¥¡¨¢—¬œµµ«¥Ä“iwŽ˜¦Â¥¦¶º™—¤¦›—©„L[`€›ƒe\SI`Œ­£ ìá´ƒZv ¥ŸƒwOiŽ¤œu~s‰ÎÿñXy­³´¼××ÜÓ´Õà»°¦²Ë»¦¹ÑÏÈîÞ¿¹¿¤ˆ•¾Ãº½¸°»ÇÚÍÀÉj%íߨd[dJ58FRgdÝÁ”Å€±¡Äã#\¾×] "Ety,ôè_cFëÖ¤©çüú¶uy’ËöSý%¸>J0quu’‡‰¢’s³¼£¤»º´±£ÁäÞÛ·¢­§ªª®¿ÕÓ»²ÈÚÛžÚâþøøâ×å -<\dz‘ž¨˜ŒkAGf…¥¡ˆžÄ¹Ÿ¥»¬¦´Òܱ†”ÉÐÐÆ®¢¥¡—®±RTVPvd_rNJ|¬¾°ª¼È{ih‚›£|^Xkk—µÌ¸‡SU–ëF®ÂÎÆËÑàîÕ¹–³ñîÝÑÈïØ·§±Ô¸»ÔÇŸµ¹¿Æ¥¥ÅÓÃÌÎêëØÑܶf+) ¼kG=GN?UV×®œ¹ïË2h–fæJ#*8£ÿîqT†S+#÷ÆÝ%"öЦt€§È&ç,¼OQ ;¤š…n†¡z[{’n€¦ÁÕÇËÞÕÀÃÖæÙ«‹ˆš¤¬ÆÏÍõîÅÁ¾ÆáÞÝéåîïèäü_¬·¾áÅœyGQVtŒ|¬ÊÁ²Â¾¥¯¯¾Ì²œyl¡«Ã´—…|“ ¹ÌÄ¢|vpoo‚†_w´²±Ùû× nlŒ’š¤ zu˜Ÿ¥Ñ¥ºòC°ÒÖåèåéå×¹¶˜žÝêéÛéàéÁ¥£ºáÆ®¯¬§ËìǼ̱»Ôæ üñêÚËÊæÃW:S@ ˜9)*DUAOO ݪ¢©à¿Ý7Kl¿Sƒ7@72¶§ yn—¸) 1÷áò&èʪƒž­ø£NÙAö™Ï…¥­«‘~•‰Wj}•¯¦žÄû"Э±ÌÓÒÚØÆu‘²ÇÏÐÊ×ÞÖÏÇ»ÆÔÌÌ´ÃÔïÏÛï2z†‹Âж”onyX[i¦¶¹ÆáÙÈm|Ž‘’{dblo‚«•†€|›¹ÇÀ’“‰ˆ†jKdrZa–³Äç÷Ó‘p„}s“¼Ñ·š­°Ü4Ù¨­È*¬ÔÐÆÈéÛ¼—’³¸ÓÉÌÎáÏé¡™ÁéÅš°ÆãäËÇÛÊÄÍßëöôöøåÌÈðî”da\u1=CZ]k9Ú¼–Âàµä ðòÏ¡Ë_4¦¸ƒßœ‘Ý//ùÁµÈúûäбž£Úk@>hù15J©«¼¹¥–˜ ’™¾Ð¹§Ì'L¾€…Àй³«»£†Ž“¯Å·˜«½Æ·ÄÈ¿ÀÑÓµ¸ÂæìóóÞæû9t‘µ¹’ƒ§’ƒq[w“Š‘²ÕÕÍÜ®p€Ž¤¤¦¦Œsm|£–ˆœ¾Ã­¡‘xv€|`teKC`ªäöàƘ†gG`¡»Â¨‰œÌ OPÍžókÞ åÆ‘–°¯°›šÁ®¬·ÓÑ·§¹À®½Ð®œ¦Üá̵¯Ý÷ßÌÒÞÜÚÖëìÜÛØÖе’gøy-2LMJkutBëÀµ=Ëر³ÇânzÇ]çÙU\ÙsçŒN1Öû*1ûÀ¦Ãô÷Ö¯’‡¬#‚Ü%&;®¤°ÀÂÐß×ÓÍÚÕ¿¤œËúÚ§xl”¦Ÿ„‡’­ª¬ÁÐÀÃͳ»ÏÅÃÇØÇÃǸ²Ô÷ìàoŒ‰’‚š¼Ë®À±››¡•…¬Ê­³È¬†žÂÓ±—¥qWh‡­™_FŠ²¨¥š†‚”}ZŒxgŽ±ÌÆÁˆr«¬‰eACt¡­ƒg†Ð ]d( ƒš¸ÒËð঎›±¶¸ÕÚºª¶ÐÜ«œÇÜß™œÉé÷Ϭ±ÒÚº­ÊÇÀ·¯­ÃËÛìÎË·¥oâo^E7NbI<&ýË·ngRçÁ®®±ÁC<+Ï¿Í£$ ŽL%òôÿþîØ* Ò£ƒ•Æu,P.³ÐÉظ«¨·×ç ïÚÉÂvŒ¤¨”Šv`{¦À±¬˜•±ÊÖÌÕÝôôèÐÆäúðÍÖÍÈȪ«¾ßïøéê:``„¹¹ÄÕË×ØÄ»®´¿ÊÁ©¡À¡yŒ¼Ýªnyy’aQ©Ã¤ns‡ˆvu„Œ‘Že~‚•²’x_Dl‰rt|}mn\Xq˜j€YQ¨¸vx ÇäÊ–ºÈíÊàÔÑ×àÌ•x‡¤·ÞãÔ³ÅáÙÈØÆÏÕ¿³º Ÿ¯¤£™°É÷â˧™¦FÕšm+;U]G)Ͳ—Áèδ¼ÜO…=Až’«¼õLpE1ùàìÝÒÞÜà -Þ¶ž‰éi·?]‡ÒÐË¢—’“·å)èÒÕÁ¤‡¡¹À¶©©†òO9ÝÀÀÛöçÇÕõ -ìëèãáÃÎäÑÛÇÃÆÕÝÙ¾¹Åü.@]–³¬ÁÃü¢Åä×¼ ³àÔ–’•­®”œ„‹‰£µ¼–viXTUe€db€‡lW~¢ª—ztt`S]ˆ›…x‡’‚“Õ5_¤»À–~‡¡µ¾œµ×Ê· ­ÝûþíåЫŽ¡®¡ÅÏÃÒñûÚÌñòâÄ´¯«˜Ÿ¯´º·¾ÍðøÕ»®ž|,Ñ_0):Neqh8þÕÏÔ.åþÊ°Äõhs2ö¢•˜©·ß í­¼¸ÁƸ¢±¬¥£¡±x*Z·ü¦«ÑÙÀ¬›“¶ÓÛ÷ÿÀÍÖ´šŸ²½¶ª²´®Õˆ,°X231óÛ¾ÍÜßÓ¾ÑïÚÄìø ôä¿‹Ãô&IŽªÂ¾ºèåÌÅÍÑš—©ÕÙ¤up¤Ì¿©›†x—ªš€€yXK?Nkz~”\=+:OatÐá­ ˜‡{o^Zp…Œž¦‹ÙZÝ᣷̸ºÂ¯—Ð×ǽ´Óäøò×ÌÙÅÅ¿¿Àº¨¼ËëÜØñíÖ˵±¨ž³³ÎÌÁ¿¹Éѹ«·†<Ì{KCNrtpiS.ùÑÅõ}0¯Ã¶ÀøI'Z/Á¸¶¼½Éäâ¾ÍÙºÁÏßñÜžÁÉ°+)xýEh‚¬›´ÑÆÀÍâôôâæ渹º—ŵ¡§¦­´½õ´†å¾|S+D'ǦºÑÛçõèµÁÛõêåÏÆŸ ¯Üûîa¢¸¸ÌÎîíǾ­Ž}g`‚mh~¼ÓƧ’¢¢§™†oreX\swŽƒ„rVVYL^j{¢«‘Žƒjpqz‹Ÿœ~lzŽ“rz©ó ʾÖÙæûêºÌÝ̸ÏßêàØÆ­´ÈÑÏÛЯ”±ÊÕÐÙðη¸»¿¢–½ÎÂÉÔ¿¨®¹Â®¥˜fqMú¨eWcjwkVH&Þµ´Ë•“WµÀÏåî*éù¯zÕÃʼÆü­´Îîóþ)#ï­¢¶ÔÞ Ù ˨àæ¨ÃÑö?FK@ãÜÁ¡«£ ·Òâ»É×Êç}Søa“ÊÓÎ/)íÏÔìêÜçôê·»ÖêäæÙØãÌ®³Êí)‚ÀØÝÇÉÞÚàÕÃœmYXly¬ÃÍͤ”™ÇéÉ’y}€qs€”²µšŽzVap_[e|R<‡»¥˜—rg£Ž•šœ„ŽŽ„ÐwéæÞÚǸÆÑØâÐÄÅ×È©²¹ÕßÙ¸¦Ÿ´íÝÕËŸ‹»ÍÀÝåÎĵÂÉÕ¯ÃÁª« ž²½¶¡Ž^8M^¿tiGWcS=>!䪦´©ÔÖË þ"×þ°óÀÔáÜĹÇØÙâôD,ìÇÏÓÚbHz´CYwË··ÕýF‡t‚_, í¸¢ˆ×úÝÎãÜ·Ä.ð¯WëFr‡~bgW; 0+ùñôúêâÖǦ¢Èù !_ªÉö²ÊÈÝéÇ“x­•œÀ¾Ø᧌™ÐèÖ†§Ž|Š¯”§¿«ˆVV{Ž{cjQ@_”¦ª‹iipnf¾éŸ–ªßAµÊ¸°ÁÇÄï¼ÀÉ£·Å•Ÿ²ÇíÞµµ¦¶øú×¼ µíÓ¥ÌϽµ¬ÎÖ¦”¦µ³–”•¼É¸²¬„C3bg5ÝWVS]C.DQ µ¥ª·‚uMü'0J7BðÚÛÖ̽¾á÷çÕÔ  =;üÙØÝ%Þc×4)÷6Ȭ²º¸×]‚ˆ‹oO8Ó‰ê(öæÒÉô–;Ç@ÖøofèзŠ‰¡˜‰Œ„[WBêßâÙÐÖͯ¯çþSƒy‘¯ºÒ¾×᳊ ž©¾®©ˆ¹Ñ Š½à¹š›‹‚Š‘‹‚nwcGXyljb\c|˜‘WEj…—Œ‹•œ©´¤µd„¾ãÍÀÍé깬²Íͦ¬½±ÄÔÂÖÓ×ƪš¹ÓãËÀÈîî·²µº£ƒ¿ñÞÊȸ¢¥ªµðíÊĽy'n]ÿ†XjM6>W_a/Û¹¿¼­ç©,9OßQ"1ØÑÏÇÌèïÕîýõíýóñšqZ p©¿ÞÊÁÊÒê4`{„ƒŒ~nZ%èÇB<K6 -ßÈÞSËö*Ùs„h9Â{m> ûæêἉa2îÓãÔÇÁÓàäñùú÷õ%N`ŸÙÛíÚÉß±¯·š’½Ù¾·Ç›ÄÆ„i¨ fat„‚€gkxWUdjŠrOlœˆhY\žœ’²¢q\p©­¿ôîþ¼ÏÔ²¤¬ÏÀÍÌÆêþÛÁ¢©±¤«ÃÁ¾µÃåù¾³µ¢¦¦‚~¯âçÜóᢤ¼ÖøýÙÍ´0÷+kƒfæwXX:DZg`P4ñ¯©¨¾P(4 * ‹¢IO?ÑÍ×ï<`@îýÞÞßÜéü  (Üš%cDùAàõ3=Kbxš—‚†bM,û÷äÎÌã8ÀÂÀþhÒûîÕÌ罂‹m>ýÀ’XùôêãÕÎâþùýïîÔà#W¥ÝùÛ°·Î¶Ã¨’• ØÅ‹š¶‡—¹µŽt¶•z”ššŽ‡ˆmhs}w‰…ƒ‚}uzˆŒnQŠ©š‚€‹~pˆŽþ«¼Áò槙›³ÐÏÀÄÞ×ǹ¾¼ÙäÞÅ´šºÇÅÇ¿ÙêÕ²ª¬³²ÌçÖ±ÚúÕÄéïÁ®ÄÝùðÞ¶Jð'NX:ÖxP>HQYM<D'à˜‹™¶Œ¶˜!øà?]2~PÀ´ß -+_i:àÇßøùíñ÷R.’ãNˆ—žô(" *Eefw|n‚¢“…“•I 뤯½¼ÂÈì7az‰‘§Ï)]»Áš–ˆBÁ’`=#Ú×ãö ð×ï,|¤ÈÀ»ÀÁÓÅ©˜¥›¹»†ˆ°¨²ÚȪ^ŠÂ¼¦±¯•t…uv›™Šb€§¤¡‚hq€no›®”ˆŒyk¡ÅÏ.¦ÄÐÔŽZ†ª»×éÏÌ׸©ÃÒÁ­Óÿ Ó|”ÉÓ»·ÍêçÝÍÒä™ÄÙÙÉ÷ÝÇĽ®¥ÍïãÔÅ…æúþ(<4êHDXI4>Ya-äž–§«±÷øòëNe-“\ÕÒå<RJ+# ñÚäþëÞè¥q=…7æ)Ú#0FH;Oˆ¦¦ocŸ£’›=çѦ™¥¢¨¥¸÷6NS1:Ry«ý1,%éÿ&)?1 ö¯Ÿ_%âÆÚëøçÔâÖÐ+m‰®ØØ£±² ¦”®Á­¸ÊÀ»Žƒ‘”ËÉ©ÅÌŸ†«±£‚…†jjŽ…`p‡svn›—‹~|‡—ÆX“ÅäðË„¾ÎÌ×àÇÕÕ¼ª­Ö»˜¬ÒÖ¼žÈðͽ¯ÚäàïÛÊÚ–­·¬ÙÙ½º¢‡¶Ýåö¤‹J ßÇò$é‹FHY[ag‹i)í¼¨¤±M%)ÎÚþTI,¶ŠØÜ÷ H`G# ÿýÞÜå)ëe¹e†«3B\vrjv¤»¬”™‹jš’ˆh(ùøüõÆ®¹­ŸÚ*þéûû<}˜©²Ìç×àáùôÞäüØȱr#õÖÕ÷àÌÇ»ØÕÂá N~gez™Žsdj†§ºÌ»žŽ‚ž’²½ªÀÝÔ©¬³z[YaS]„uX_s—¬¥©žƒw]`|p‡ôLz¨¸Ñ×ÕÉáàþæÇ¿Öîé°¹¼«¹Í·ÁÜèãÁÊÆÑÕÑØͧ–´´µ’˜¼ÞÓƭˬ«ØÕÀÃÙÕ³r$Þ¨²óüÍoPLZsŠy]*î¾|™­qzjðîJ+åºøíô`f; @ZÂÃØFXƒ Ä;3mrpmgli`kˆ„vruy…„wz< è¼½½³™¨­¯ÌÖÁÃÄþÁÑñ97:i”“†Ž†„¯çþà»y(ñáûìòïìà¿Á×ëC[oel€Y`y~‚•­Ñɺ–›¥®—¯››•‰yq^GM^_a^gc{ˆ›ŸÊ̳‹ks{|~·= ”¢ˆƒ”­èç¾Á÷ñºÆÊ˾œ­½ÀÕÒ¿ÅÄ×±¼àÍÈåàÄÌ¢ƒ¯Ï½™–¢¬Å¤ËÚÚç˨ÄÌÔÂ{3ì¡«ÎÌ©kYWYu‚feIúÀ§•°¯ƒÖÅB.=Y  ñ'ôö)j‘r;þJ‡Uç·Ô]@„(pg¾¤‡zmaWP^szwƒ‡‘xO9Lm_G8%þêÆ´§™§¿Æº¶ÁÏÜÛãáÛÇÌãÔÔä.G@0+XÂ1!ýµZø+ûïñßϬ¥Àèô >msG]ƒ‰”˜wy•Êèß·“¢›ª±¯‘|kˆbvkUjmViijq†ˆ`h‘wjo•ºÃ—̦©µ…Ž·¢ÜĪØ⬇¡ÆÙââÄ­¶Á¾¸Íìίʲ”¯Ä¨¿½—ž§¡¦×¸—ÎôÿâÖ¥°ÇÖØ‹7Ý«¼Ð»—vunklSUb9竤µ²®™Œ…|nìÔ*4ëló ½k4_5 @´ (ï5–}¦ÁòžÇÈ»˜npsx•˜ŠŽ}rgmhrzrdKJ'ðܼºÊÅÕÞÝÈÔÙÞäëò÷ üõÅ¿»¼Òäóü÷a¸ù(òÄp ñâÒ»ÆðþÙÎÑßìü0Q)%Yt¡–½ÓõûÉŒ—Ž€‰†fT@IdZ_x`j[_‘šgy‚x[eœÐŸwœ½2ºº•®Óä­°Ìß¼ÃÄ‘ ÄÕ®™t‹×ìÖ­²´½®›Áé辸§ž“–¨¸È¬š§Ç´ªÓìÛÖÄÇ£¹ÊæºJê²ÈÝàѹœhPLIgWÃœ²Ì¿²°[f¼˜¼hê_pø&±ÎqÚp^ƹ€˜ûà\5Ó³´Áfs_©²ÀßodjztŠ¨¨Œnae{¥œ…lq{d0ÞÇàóñ×ËÄÏ̾ÅÈ­ËæÕÀÊű™¬»·¡°–ÂÜ4+êcç·¡¹ô* -ýöúñý -(-?k‘›¯½¶ËÞРªª„qs–‹h;;Ql†£¦°¦uUf‘™£§¥«²•–¢Æwœÿ†ÛµÞïãÛÐȪ¯¼¯’´ÓÉ¿ñÒÍÍÑÓÆÈÅį‡ŸÇѱ¬¨¹Á¢œ¾áÏÇÞòâÇÁÐÜñÄ’£²¼¿°µÈºY Ôî ý뢅|RCLlkC°«ÂË®·àoj³t„–¤ŒÀ<[1.-zÓkI•äé%?ŽNꎙŒ¤ð’˜À¿ž‚vzfo–®œ‹Œ“†qn”šƒ…Ÿˆ|k8åÚîÝÀÄ×ʺ—™»¼¡ˆŠ³íÒÌÁ»¥ƒ€…€‚£=c÷Vws&†2ãßë$\]<IIf`ThsbWQWw–’–‹‚|ªµ±Œs€|zaGt“¥Ñ½ÐÉ°‹{–Ž’­¨¼Å§¾Â²Ž‰ñtÌÕ°·¾´Ä±·åѺ·´¢²¿»Ìõ÷´­ÑÛõÌƧ§¡¢¸¬ÁãÕÈÃäßÈâñ¶ÅÜÇœ¢ÇÏãÇ«©œ‘díùôÙŸ`R@CDOmXEÈÀμ¼Õ×XIaO[Z°QŠíʼ¨syÀ@*“¼–:é…µÎ@³±®¾³ŸunssZQyª£‚ƒŠ˜ƒ@\†yS[ncy|x3òÝÍÂÏĹ®šœ²ÐÀ¨¥ÕóȤ•œºÂ¯€½œ•Tå_„ŒxÇ dC:Cb¬ºØ)7#$ãʈN!6]OksP@ÁȲ •r~di}€¡¬¢´ °šžƒly€›§—™”‹…ª¨ÜÆž³¯¯–…¿äǹÆļ£§·ÊÎÉ°ÄàÐÃÍÚ˯º²¸À¼ÅÁ£­ÐÝÈ٠йÕؽªÍèöñÊ–VUum Ûĵ®yC (OM\geD Á¿½³¸¾Õri›8 (ií6ô½ >åYA†!ã;DÓiû9[¥ÇóTgÆÕ½’‡oaE=UM9Uxisœ¤kVdb1+Nct”µ—O òëÙƸ° ”˜£²Æ`¥‹Œ{}ÄíΛ•©¸ðD äfžÁ¢WK Ü̵žÏNžË²››”])' -¯,>A96!P„—¨wrz‹”|TVlduŒˆt[‡¹º¬§Š‹o}£ˆsbj´lÄÎÈÆÈÄÇ¿˜€œÙ˯ÉóÒ¬•­Ò¯²»åⶹÓõ¾ÌÅÞÜÁ›}m‘Âñå˶ÆÛÚ¬¯×í×ÄÎûí»a Q^×±¨g64Q_ogdsE¸´®°¯½Ã€Šœïàí)—ìðÞ„‹ÁúŽ'ÿÐôž‡aÜjÖ¼§o®s´É¦x_]T6,M\^Qkƒ†ƒŒzYMHJ:6QeXi~}=ûßÕÓ˳—‡‹¥ñ’É/Ÿt†—¤­×Ô›u‡Œ¥‡ÝlÔáÔ‡zm†–ri‰ªÌêûôßÕÆĦˆU§<0)úéþ !:-H‚”m?Rg\e„Šhfkˆ¢¡Ã©zzee[‡À(ÀܳÄØÔÄÈÒÉÍÂÕ½°Ëôá³£™ÄÅãõí¾ŸÀç­—ÏÔ·ÖΚ~w‹´É¾¯½¦¨½½•ÃäÒ¸¸ÑéþØV3/EK,þàÀ˜h`VUm…{nf0 Û·¶µ»Æ¨c“ÕÃÓKŸüDÕYvådæ¹ò#èÆ«W¦sû_€Ÿ°sa>*:h|}rvpy{|s]__JTkhnnt\=EpwL øóâÔ»»(̺ĄŠ»â·§š¬ŸŽˆ· ‡‘ÉÛõâ¹ÐðÚÑÕË­œ³ÛíìÛÑøí×Ï“"ˆ#꿸ëè3Þ^zkam‡‚v ·œxcKV…™¯²”–‰^Aiœ´0äÒ§®ÒÎÄÑÔÏøÍ«—¦ÉǸœ‹¯ÙþçȬ¤Âʤ¤°·­È¾‰t“Ðßм¿×;ٟšÁÇ•u’ÉÚìÅ‹VRIQQ<% åžz{kZaksyL0öØÒ¼§Ÿ…YœŸÒÉÑð3©2¢äåhÆböÞâq:ño'¿<‰šiBmf…¬§ŒoQIUq…ƒ‚h\cwjSBJPc‰srrOE9\q: ÝÎÕâæÝäwIÛ®¨ª½Ä°‚{¬Ìѽ¸ù³M½¾íìèô챸À½Â¿ËËѼÖÉÉÀúö’Ç\Öï$ .Uqqe—³±•q‘§•ž¡“Ÿ¡”¬±Šƒ}\_ˆÜlÇÐÅʼ³»ÑÓ­×Ë›Ÿ§¸Æ¡°ÄÇÂèß±“ž¬°Ž˜›k€¯¾Ï«“¼åáóÚéöõ㸎¦±›ºßòÖ½žGIYt|YK輂`nkcc{cKY)ã¿¥…Šœ}¿Í.ÕºÁæ7¦-VÊMùóúO³#šò.¾ÇÖOy¯®Qur‘‡rx†qw…txkNO^rv^LFY‹¦Œwb`WIO^hJ$̯°¾ÔæõúÖ´³º«›ª±Æ®¹ï0×™ÁÐéßʺÈâÔ¦­Âõýê˧–ªÄðÆÕIJ:Óvý )9K_p‰†‘±«Š„‹­«¶Ã¾ÁƵ~nt’dŽÝâÑݼ§ÃÏı¾«¢Ñø½„œÖÊÜäÔ§–¬·´º°¨ËdzåôÎáÁ¾ïúÝÝЪ|—¬°°«ÂêåÕÍÈ”GE†ŽnmX6¼dDK[cqgWgr)Ë¢€…Š¦¼¬ò2ãÍÂï(Žú5ÑW÷ý' ØÖð¼M­ -‘ŸÚÐm”™‹Žš}s~‘¢—¦‘qƒwx—­{f`l’aVuxnq`GIX4ðÎǶÊòïäÿ&É¢«ÙÕÏÆËÄÂÿd#üðöÖ³¢šÎØǹÃé΢Ÿ§¨°Ê¬™œ¡¯ŠEòeBXQRU@_|wx ÁŸˆ®ÀÃɺ¦Š‡¼¦ÂÐyXYiŒŒow£b¿Ëº¥­¥§ª¼¬¦È¢¶Ù⺷ÔѾßâÏÁ¥Ä»Ð Ùá ÝàóÝÚÓãçÜÓ·–ãÞÒÉÇÛÜ׺ÅÁžq€²kBkfI ™P1Hbutr…~!¾•Œ‘–³º»' OãÚóe´ÅˆIúþ &¡ÔrùЊßvÐÙ2{˜ ³°¦~uŠš‘’¥—xkryxƒ…wtev„}s†“Œ~}€nLYZ9êæ»úîÍÌË¿¶²¸¿Æ©ŠŸÍïúLöŸ2öÿɺ¯ÏÙïùì̹ÁÒ̵¹¬³°«¦™‘q œ ewjž‡’­©wŠµ¹½ªƒ€xzˆˆ‰QNX‰¡µ²³™›”’µ—–¡¢•„¨¤³ÕÖËÉÕµðåܨÈÉœ£çâ³ÊâÊõÙÑÕãýÖ¹½ÄÈàõå¾ÔåàʯŸ­ÕÛ®¸Çz3MF÷µP?]‘™oU„‡aµ™ƒš·Æ¾±5VÄIõâèBplP2 -óêîàHºÿ·q àŠã’;‹™š‘†‘†qnrpgh†Z=JinxŠ„…{t‰Žy~y}ƒ‰T,+(絧¿É³§­¦«»ÕЯ‘…®ó/_ÍŒ -L.ôôðôæã¿­¼Ã¸ÆÊÛÛÛ¾ª©··†¥w[n•…peWXh†hand{ucW_hWESˆŠÙ-œÕËÁÅÓǸÁ½¢”‰‘”™¹½ÆÝ÷èȯÚÞ¯—²¢‰“¹°”ªÁÊݱ¹´ÎÜÔ¼ÄËÝÔŸ¹åèË°ËåäÙ´ÇÒÄ]=ÆgbqŒŸM`€†4Û™•©³µ£ 9xíb -ó÷÷>LE ñèÞÕÕh2»ï _âm훽T–•’‰}lowq]\wvS?Nf`I:Uq€}xor^O\€vvswwfog1"0Þ®rs…„t“›¦¯´µ¶ÉÆP„ñcÉ-2÷õ äÁ²¾ÌÚÞͪ®½ÈºÃéïåøüäƹɆ -ž|²à´g0+LJmƒndŽrbcfcgOPfYYn‹‚ÈAŠ·ÕÖ×íæËàÞ»¨–†Ÿ•¤»ÝÛ°®ÃÙ¸ Š}ºéÙ¸²²ÊßÓ™©ª·ÅÁÌ»ÂËé̸¹·ÂêèÅ×Ѫ°Ùÿï®UºsT`†ŒsMU{x`8Ú–‚˜˜¯Âª§TŒÎ4ÿôäØààãíîñâÉŒÈg¨m9¦7Ö›'Ót§švhueSIYpdOc_HKf™‚vg\abcvqYA_fdoik[`vdG< Þʵ¶Çºpz¥³¬‘­ÃØï<ˆË[ÁâüôïùýÛÁ¥Š¡½ëôãÜðô̽ºÄ»ÕèìíÏÔùÇI÷Ôû ÷Ì’kqvsuxryeiqs~£}}dLW|™ }‘°¯¡¨ÜÈ°ÅÓ®Ÿ¾§Œ–¹Â”˜»±«ÃØÙ°ï%ü¿½¼Ç»¤šÉÌÒß´º´º·¬¤´©´ÉÑÚÝÓÞûѧ¯× ÿ²^Ío›‹VKcuk]8à ˆ—Ÿ®¶¿ÔˆžœèÖÎ×âèúíÞÕÓêùñXcÕ -)­uSeã]~ximuh^XfvbDQpwq‚“ ¤–‚`[ijpn_PFu‡lx‹Š‰†^+ îßજĺœŽ‘¦¹ÿ<³>›ðäÒàýûäÎÖÔ³¢³ÖáêßÏ»ÄÔÀ¤¬ÈÕÒÓÀ­½Ô¤/ïþ>]ns€?¶~››vdjjr™©|}[P[…êoÆÀÃÍÎáк¸¹´¢–¼®˜“¯Æž…–¡ÌÜÄ·±ÒÁÈÜïõÛƾ»Äº›¢ÏÁÒôäž¹¾™žÅÆ»Õçêïæ÷ûß³§§ãè’i@Ђœ˜qqUJa\H;)òÀ¦µ·«§Éì¡œ|îâØÜÝèêÖÐáâÓÑâüÄ!tÓ7‘Ÿ; -RXjqˆ„tqym{qo{Š‰‚‡{˜–ŠwplahibWVShov—†y„‡~T,Ô¹½½ÁÈÈ°œ˜£Ý>“"¥ÌÃêíÜÆÛûéÛÍÖ¿¿ÏÐâðÇ°±ÏÞÁ£ÅÒâêÃÀ®¦±u -ä6 ²ÕÖ¬dÿÌ°†~aX]m|“zafr‰ƒ°ã>«ÖÍÌ¿âù¾µÄ¶£µÁÄÌоÕП‹ž·Éºµ«ã% ïßÉŸ”¸ÅÈÄɾ¶¹¬¹ßþÏ¡¯Â³ÃÑÎÍßõóÞàÞçø㪋°ÂšhB»iŒ<<XXTH<>íļ¹ª¥œ±Ü”tRÑÄìýîÕÉÄÈÙäÍÆ×#%}ö©O×ìJ…{ipzŒ‹Š…rjsu€‚lrmp—‰uohcao[KZQBZ…€€ƒ}ˆRöË«—Ÿ’x…¾¿çD—ÿˆêýÌÅóüÓÜãéßÝÕäæðĵÆîÇÐÐ×Ä´¼ÎçÙÓÕÒ¦] -wÆÖÓ»˜x«¢u²™‚o`Wbcc~ŸºàìJž¼ÊÅ­ºÆØÒÉéêϨÈÉÌÌÔà韩£Î½©¢É÷ôìÞåâ¿ ÒïϼÅÆ»­ªÒðݵªÎâåçÕÏá þÁÀÛÒ­Ê·qn«ÃÕ§u1ÁhDB2B[R=LYSØ£Š€“—¤Çl^RËÄìêåÝÜÖÝÚàÜã 2K¾í‡Œª^l‰lh½½—w`drw{–qhd{ƒsc{z]ir^UHJVh^J_plgv“’“ˆŠ•‚-òäßÇ›œ£~r«Ð]ƒÝJ«ÖêôÞâÒÞÞßøçÒÐÐÜàÜÅ ±Ä¦®Ã¸Îµ­¸ÇÏàêáÕ„Bÿ%·ôÑ ®ÒÞ¨Gñϳ˜™£¤²Ëó"ZrœÐïéΫ½áöÆŸ¶àÓºâÕ¸ ©Ä´žÜÔ¶·ñ¤ºÍÝãÃÄäÒÖؼÂâõõÔ ­ÉçúêîîÓÜüÛŸ´ðÄ®uÔñÛ“a%¹nACKA32;wxEî¹”ˆ…™»Ì¶OQ…íñ -ûíùïéëúïñþ¡ª¡F\ÏQÌj^YeÎǵ…c]^Zj”|u~}„„lx…lOd‚vN@=;MNf†›•iq‚‚em›¡O þðÔ­¥¼¶™°ÃözØ)`‘®ÊéÙÇ´­ÑÚÞì×Ä•|¶Ç¿ÁÔÀÎȱ œ‘¡­¿ÃÓ¹vJR·Õåÿçè÷ᬓ€y^$-715d—µ¢™Àö÷Ûȼ۳´ÐÌØôõå½Ûبrr¦ÒÖøÔ™œº«¹È³£ÚéÀ—ËÛ¸ÁÖßÝäÎáÔ¿Ä»·¹àâμ½º¶Ýéí´mo/²sNE4'%<l…`äÁ½³¡”¦¸¼¯_o¨<ý    - õîøã…ù?ͤ5ƒPNc­¤¦ ’‡qns^yra›«•Œwy”~|~zhVL/8E[x˜ŽcHbzqZkgn=5üϲ™­Î̶Ì-ÅPzŸÁÆÝÝãåÛìëá×ÊÝ˦š°¸ÁÚêëöí¼Åå̹ÕÞÜÈ”k0$v¶É´ºãðß²–š³½¿Ì|Urš­‰v˜¨§Ž“©ÊÚì绊˜¾âį·ÏëèÇÀ qvÂ뤥÷ -ÞÁª¨¢Âþ¸ÖêÊ’“Û ¼ÈÚ˸Á¼²¸˜¤ÖÐÓÑÑËÑØÚ×ßøþßšŽ…(°oS76<Uƒƒj>Þ¿¨•–¶¸¥¨o‡”ëäèò*:8 ùèEkÔf6¶ábN[¡­¤¥¯¦Žo^Ymkhwš˜‰ˆ{coamonbhgXlj^lƒ{]Q†¤ wgP8QB×É´«ÃÏÜ[ÙwÑÒãÚÄáòæêðäïúÔÈêÝäѸ·¿ÉìÜÖôöñÏÝ ô¯?ê$’ÚÚ¨«¾Âµàøìͱɩ‡“¦¥šŽ¶Í®œŸ²ž²ÍÓœq¥ÓÖDz°¶ÂÎÁœ§­éº¡ÜÚ®¯Œ•¤À¯ÇíÜ¢©¯ÇðÑÐÑÏĻŷµ²£ËÚíå÷ÌÜÏÜæçùì¾€_QbQczwª›HóË«Œ‡ž¸Â¾ÃÕŒ“òßï9jqGïÝÖ^ãînîž±¾ff”kxºÃ±›©«‹qeXcxi\DTYtr]\]vxmq…•‘cLG_ocV‰¨¨…^UOK20"ýັÄÐû3ü–þýþÞÙØàíìÏÜôÙÒæÓÛôéøü ßæíèÖÄÉÝ×Ìßê‰úK¡àÉ®ÃÐïþӵĿÄÀ©¡£˜««½²É›cd‰ É¦x¸°¡—¼Ú—}w{©ËäþùÎÔèìË¥‚„£¬«ÃÂÚý¾µÞÔàÐÈÜÜåæÊÄ­µ­ÓèåÑÁ©— ÀÎìïÜÝ»?->ó˜me{…‹¤ª‡MôïÄšŠ˜¼ÖÑÜÛ¢{þëíÿbk*ìäÜç'`°½9ÑÂNëºVg°¸£Š‡—›‘}WIQ_JB<Xdquhfq‹ŽˆŽ˜lfKFBQz—ƒxtˆ‹iWs^)áÇÔº¶úû:®(‘õäë -òÆÍÝåÕëÿôáïãÐßû÷éðþå¹”®Òäâäжɠ>ö+Ž¸µ¿ØçÙËÞÚ¸¾ùÿäÙßþÔ­»Ê®o‡ÂÉ¡ks¯»´´«‚†¡¢™¦åþÈuTÃð彘’Öãณ¥º«†‰Á¼­ºÙë  óÞÑÑÖìÔ¾•©ÒðÍ­¯­ ©²Îæݼ§xH4\1±zy{”¤Žyp?øàåÓ®³ÖʹÁÉŸ´fÜçýÿF·‘9 ùæÞìEU—¨ÈZǼƒ“¸±Ÿ“™†whT^nQIW_erŽ„pekˆzj@02Qt|†šfc‡zeTLB="å½¼ÌÙúý9Æ3‚ÊÛè çâÿèÿøú -éá÷Þ¬Î÷Ø—‹˜ÝàÌÉË ˆ;â •âä×ÄÍÖ¸´ÐÒ¾ÉñõÿöàÏÉÔÆ©ÃÖ§w‘ÓÞöȱ¼´¾¾»¼æâäÆ«¢¸Ñóß³˜¥çòÇÇ´Ÿ«·­§ËôÒ®ÓüØêධ£ž¢»òêÚ̬³ËÇÂʸÉÑÊÓàÚЯ vV{1¨}xkgs—¡wv5ʹèÙι—žËÞÀÂZ¸Ò N¤äŒ ïöêä÷nóö‹’ñ520½T šÈ¿œŸ£ŽuhVaqy|‹†pqzƒ}hkshP12.. ;cnj{~q€„]_sX::FÌÁÉÚò+WÓUªôòãñõ(%ÿêÐÝéîüõÍÃåè½ÇÆ¿¼Ý¸·µ¬“†_ÍãA¨»¼çúÛ´¹ÞîØÁ¼ÙÚçÞâÊÛäõ»’ ÏåÀ¿¸ºÌí÷È›¢‘š“ÃöÜÙѾŸ®ÉÃÇ´ÄÆ°«Öé ãÄÓÎÏᩈ˜’—¬°¦•Óʳ¼¹·°ÌèðóøÜР“ru¯Ÿ*|uogy‹‚z…#‹²ÞéÚ¿›©Ãד–WÑãWÂåÌ^ÿõðòêá¥d§/Œ©·WX·lÈx£›‘Ÿ±»™Š€noŠš£š|rglw\LMKLFKMMPEafrwskT96dpqS$ ãÙúõíýsñ`§æÿíÙÎõ õâÀžš¯¶¶¦¨©ÂÌÛªËâÙèíÓ®’’rCò§ÏYŒ]}«ìüëë¹Ëèå×½×Ý·®¨µ¾ÆÍÐçÙ»¶ÐÓÁ¡‡™ºíç篞»—x‡’¸ÉÔÏ™›¯µ°³«¿å·ª²îèåÞÛíÊÃË´»ÇÑ¿«‡yˆ»çâ¼Å­·ºÀËÇîâß¹Žo‡¸wä~vtSIS_ci€sŸvw§àáÚïÁ¸cpVÒò|ïØ0óÖéíäXBEe‰{”ds%Jÿ"f†—›šÌð½—Š€lns…}qe_iI59YjSumjeoxu‹{OKcnR7ludH'$âçåÒù9q¼éåú긳ҿÁ¹¥­³ÇÁ´¯®É¿ÒÅ•²Óüܼ“bO<ÕÈ–Ö¢‘±¬ÓÚÚßÞ¿»Õèй²•rŠ•›ËÛÅÑæ×®¾½µµ…±åüßö²¼£Ÿœ¯¬~ ªŽ“”«Íì¨ÛíßÈÜæ;ÚÒÜ绲Ù΢”¦ÏÒ¿ÙÔÂÆëóæŵÁ×ÌÃŽšpŠ@ÂodYXhYQhcX-à©™·*õÇÃÃmfi‡Ë™NØÛìçë0b\k„o;l&qKU‡”—“”Æ´„~zO:<SU@/%*9GNWaMOGEW_ZdnbCEdŽ‚K;%+ -ýãÓë'…ÓaÍûúõìÔÝÑÊÛî ÛáäóÚë΢¼×¯ÀîøÁ‰N31ù²Êîaį«ÑŒ˜åßÑÙÓÕæÞɳ¹Œp}¤ÐâÐÕ评’Ÿ»Ù½‹±âº—“ ·Á²ÄÅȤ­¤µÐßëÜ¿¬¹áÇ×È̽›¬ÐÏØÍ¿±¹ï øͶÛ×ÝȘžÂÉãéàü¦‚“¹Ë§|‚®©8­aD_}…bdiVS)ÜÀ³¹ö]€Bçáßh[V'3KM6"éÞßØÁ,˜M“¸Ú¼Z4ù"l¦~Œz_Owf[|ƒeA0+)!EF=8@7<I[b^ZhmCZbYuz†vPD*õþÿÞáÛ{ßeÂýüóõÜÈÖ 'ëÍÓåñåÖ¾”ÀåääØöÖgý¹ƒ™°âl—¤ÄåÉßéÊÈÓ»ÐèãÛÖ±“̼¤¶¾Ù±«ä´ho¬Òס¸· ”°âɶ½ÇÐØèáÒÒ÷ýÙ˼È­½ÍË·´¿¹¦³© ¯ÈÝËš¸ëóѲ¨àÑ´ä  ëåš^o¤Ë}Oq¥¯+™a\~•bSqeN9éÎȵûŠ®NñÒàÌ15þ øòìβ¼K“Kݯ$4ê*'ù/yw§ˆutP0Odq|zZ@$$=0#><073;E?B`lo…‹zftlJGZqynq[?(úÝÎÒÝ!nÒ>¦òÿêáÚÙ¾¸æÉŒ ¶ÉÙËÉéÂÑÆÇÙmÁ~gk^Š!´äöÙáßÎÌÆììÓÝëÔ̱ÝýÓÎ×ȘHxÑ»~‰³À¤™»Ì²®§¡§Ë²Ÿœ©¦¯ÃçßÓÌÌ×ØÃÌÇÉèÚÔÑåÛµʾ¨ÃÆÔÄ®¤éúñÜÄã à½ÕÛñóåëÜ—^Gkk(S‡ˆrhtjQej]<>ß±›ŠÙVdéÖʣб%è õÕµÙÇ_óÃבçMÀuÞ.7^–|ˆwfgPLU\KUOVhSFI?6EM5@;/2PDM?EThq…lTS\x‚n_``SLïùð@TzÓ*qŸÅÊÉÉÎùǨ®Â·¼«­ÙÐÞóßßñöàãâÁI …:V„|»eÖúúÓÜ̶ÀÕâÕ²¼çÓ­­ºÔ®«ÈÒWƒŠŸ—‹ÄÛÖ̸©¨¬¹¹µ¸«­Ÿžž…ŠÐàޱĽÉÊîºÔØÔãܺ£ÕíÌÐ íäçʾ×ÜÐÌçÝÒÒÐÊÅ“ - i•uÓpfg^[n}dVPO ­ˆŒ¿7 뤓rCWLJ3?+ßÛ-¯Îo¤¶ÀmÞ’3>§ƒ¢“}ilwvf>8.EnsQB37OWKHOTR]zy\BK^Kfg^s”€YSCJ4(1"7c²aŸÖìîÛòØ°ÑþôÞÐÌÒÎÂÕÏÌÁÑÕ΋ðÂz_z™¬þ`¸¿­ÌàãÆçô«‘|œ­¶´ãÌ ‡”Òöðߪ„–ªÉÛîçΣ—¡¶äíàdzIJ¦¥—^BŒ¾Å°°ÕºÀ¼ûçÏÎàâæÖ°´ÞèÈÖãðòп½«™°»ÉâÔǵ¶Äʨ*Èíý>¢7‚O[kvƒ”•xivK§w›Î :Q) «tYp}b]D ãá90Nþk‹ÔßÜ$K -73ÇÉo––{}‡~…‹~^H/0TgO;7CKNDRbZg‚‹{phP/8\_z»KPSL2!E,õãëø >›ä.“óäßØÆÖø íßĻ˭¦»ê뵩ÝΗ…C̱ÃÖŦ™ëTª« »¿éî眇©§¨ÏÕæûܽ±ÕÞäï΢˜µÖÙÍËÒÚÁ«¹ÇßéÂæÕÈÀ¹‚oŠ ÍѳÅÁ²ÎÚÖÈÈíîʬ¶Öç×̺ŸŽ—º»®¨ªÃ½ÔÓµ ÁçèænÞÄã";‡ãomƒxx—iWum ẹå14åò›kË­Œi8KŒ‡Só kå^°áù€ç:ô^ÝõÀÖO¨’ª¥¡{O@I9$)G]VKK:-5KRc_gbb}ˆyU;Ts–€SHZ_E*ïÚÒßèpÆb»ÔÓÚͽÍæñ ðü¼ÕÏæõ²‡‘¬ŠsJÅãþüá¬æL°ÖƱ§Êè²±ÞÌÍëÚÝÚ»ª©ÒÃõ£¹ÇÑÐÇÃÀ½¾ìÓ™ Àع »ßÐÅÜÞººµ©›• ¯‹•æí̽Ðôì°š¿åßÕÅœŽ‹›áÞ½ÂçðÙß×ÌÝõôZÇÌÚî)Vw4Ö‰ŽnezgAc~Løξ ªÏÞññõæáÜT\ñÉv9-WhF# #Hi‰­¸ºtP=¿þ°÷ù¼äHdŽ£ ±ª›‘lH4=DKCAEHZ^SJLZurROjz}’jO\[LHMTnJùùõÿèê\©ñB{¿ÎÔÖÔæÐÃññÔêÐÇáèÔÌÜÇÞéËRúïéïèü‚ëýöïüÝÖÚÞßÝîèÞÑÅЯ‘„˜’­§ÒþïÓ¨”®®¡°¦€{®èÁ˜Ÿ²µÂÎв˶Ÿ…’œ¡ŸÐ"ÓÇØÛʦ©Îâöð¼–²ÃÝê×ÑííÝÝÜãÙ$éœû·Ôßî -$]IøÈ—oLJT[M^yl;¾¬«½ÀÀÀÅØøõ¹ö(ðÊl2)0  &(0Ÿ!Ëà  è Þ/iKo¢§’‘€nWGE@BN]VOMVookfzlRMUi_S`u\HOdee`fWI -+J,LŒÀhÃåâÜ×Ò¹·Ûé×ȵ²¥®ÌøýííÀ=Öù@+'˜ÔááÜéÏí  ÷ÒÌÏñ¬‘•gpÀÌÆöÔ•…°Ñ¿ªˆm‡±·yr‘k†ÀÏÙ¢Œ†¹ÁýÕèÖ¯¢§ÅÒÃÎâÝæÁ¦»ÞÙÙ·™»ì˳Òéοâ ë®ÆÑÎ&H¿›~fJw€snpl^E˲¿¾ª¡ºËØèÚ€°) ¡e€eæúüÿòðð - _ÈåÆ®¦ŒÐýï…°dg~†‚˜¦›ˆorl`KJSB91?KSXMC11]^P=E@BVm…¢š}nŒ†cNQZ1"7K5ÿC^šmàúØ¿²­¹àúͲÚèÛçÿþ -ö¼xG>,[–dCF8$4tŸ¡½ØÁ¸ÑêóлÜîÛ´ÛË¢œÊØÌÁ›„•²ÇÐÚµ³’»ºyet~~JUóÍŒ‰†‡ÇöìðÚ“rl›´¨Ìîã«~“àûóµ¬âæÅ­×åÏÝãäèsʇ³äÓÂýÛŒih`¨‘uvtjiUͯ›¦®²¬¯¼ÏÇM‹>JÊÀÂwäóåáÕÕê!ô2ƒÇÔÄ~SÀæ’Úxp{ƒwŒ‘tlvq^_K7=6/(/1D>GEclkMLUiQKj£Ï¾‘‡‰~zkM$ùÂÂè_°œíʱÍã ÞÑÔêóê üé52]Z_zTP6E˜½Õ»ŸÓÚ¡‰­Ïѱ·ÕãíÃÁΣ«ïñÁ»¹ž¥»ÈŶ¢¬çÛÄ~-7mŸ‹K{ÑéªxŒ¯¯Óèä¬eju§§„Û๨£¯âåÚ›™äþóáµÇ¼ßâë®#·ºäæáãÍ’dbnqŠŠ\Slt^L%ß½Œ¢½Ã»©²——vÒûó~%øÕÔÝèü79ó-O®ññ…®æÚˆðnoƒž—„ucmkf^aKOa;(P> $DZkocieRUcsˆ}rjw™É²†‘†Y:('þÚÎãèÀå8„Ç)ŠÄØÙì õìûæ¿ÆÆç -ÿÞ£N$2Ce\UV9ˆÁµÞÛ°¬ŸŸ¦Ÿ—Öéз¾æÞ¥ƒúÿóÆ«³°¾À¯Æ£fMIŠ²´µ°§²¬¡„‚¯Ëó æ褜£¸É¡©ÑîèηÐèóê¾µ¶ÐöåÍÛ¿ÔåÞèâúŒíÀå'=æÁŽqz…„}|mcnsbO%è²°šŠ›«»§¤¥Šî­ÏŽöã)ãbëÉá(MT7ô$ mü£¤ÓÅʉj|v€ˆœ”z{V:,08WcMA>8*,4C?=\usXRS[~—Ÿf]sƒ€—“lUCD -$"ÜÉQtÂ(›äÒÓïéöùÖÕÒÏÎÄ°«†\S1+5#HV"`¾¶‘ÁÿÒ¯ÉàÞ‡‚¬ÝßóÒóá°¡òýúße;X…›µ§™‚sTOq£þõÒ²¨ £©£xs¤îû˨¬¸ÓÌÖȤ²ÒÕÐãÓèüç­£½Óì×ÔÙ¯Æ÷ÙçÿÚ3·½×àÝêòظˆ©–zyx‰ƒ…f.×´¬Ÿ•–¢©©§°½‘Þ°ó³]iH–ìçãè1Na:èÜñ÷ݼ „‚]¢‚¢‚»Ê«ª¦ŽY Øç &*A0 /HINGCP0[o]]g8aŠwq€y]{“‘€ˆ—x[Pò)çÇÆá7r«ôQ‹ÐûãÏóÓ½µ¥™£zhb;*8GVx^PmŸÌ²êÿÄÅáÍÆܸ™±ÇÅšŠ“¢£Ëíᾄ~Aòá$_hRDwzmh‚·çÖ—…\En’¡¢ ¢Èܵ±™ºÊÛÑÈ­¾ùÏž¶ÝâØãÛ¤ÀîåÞ¿›Ëåì†ç»ªªºÐð䱯Á®›ykeh|~ƒ‹\5½«·¯¬¡¶¾ÆáÞÅ-oÂXtYÿ/NáØçìþ&Vo_ÿäéÑò%\ïZG7sY -‚ÕÊ´©“Jõ²°Í';=DAM`qX^]Vqsk|rNE^bQh{kn‘†ja‰‹cA4%  ýñäéýþ F†ÆdÀýöÖÍÝêßÃäêϨoZdUZkhB;‘LW¢¸ÞýúƦ³Ûù¶¯àóÔž™Žl¢àÔ…*ûÞõK‘†P9C@i}k“²nb7Bfˆ£®µ«–±¹ª¸Ñ²Â¯§«Îøü¨p“ÃÆÜب³ßðíçȺºêýÆ»¶·½ÃÓã¹–›¡rKckag…`aU1礜¸³­­¿ÐÚãå…’æ[ûû)ÎÓåðUŽŽLýì×Äå1oš“?nî¹\;Ñ{oˆÊïÌÎÒ”ãËÇÌê/YpbVI[u]Tbnjhw„}debdfrs{€l_j‚„s{h4õóçîÏ×+Zz•ï-_”¹Îì迯ÈΕQ~Ÿ–jTQ|ŠJ1/*I½È¸Ñ϶‡—î"ý¨ž¿©›š}b54O'íÔMlaqžÇɵ…sfˆƒ_d›œ”kCfŽ™¯¿©£²¨žÐÙ»˜¸¸Äïé»”§Ö×åõÖµåþîÁ¸´Æè# -Ã!³¤³ãþðÞ¶q]`v[Mtohi†•o;#憜§˜®ÐìôèÅ 6&Xq‘øÿÒ ÍÎë+n—†9 ẫ³øY¬ê¶#E7E5Éb3=|¬ÏÐÁAÕÃÈåò $0V\J92Ponrlq„¥ˆtwpozvn‘Š‰ov˜ª¦¥eèÝ῱³ËÌÜèóòcÕY¨ÆÎÐÑ·©¦oK°ÄC(`ˆMK¯®‰zŠ¢¦¢¡`=æÍñ$òô,"bž£ª¯ÅÕøØœ”ª§°Ä•r|·À~Ip©¤¥¦±ÃÈ­¢µäʹ‚½øïÜΧÃðèÐåäØòóÄÂ×û î ùäP´’ªòA:ö³‡uKPkg`cbUi’«‘Mú·€‡©»ÁÈÄÔô÷œÇ;Úù™{üßÀ×ÐÎô8vvK#þඨ­ –áæÍZ(î¼Ûø˜,/ƒÂÓ·€ ÖÈáõ,@%=aR:K\q”•„u™¿˜…ŒdFHj‚qzˆ‡k`uœ¡€GæÕÔÀü¥·Æ»Ÿ£Çú+\± >m‘z“®‘uew†stSB*!9?U)!^uO( öØ«uƒ¨¬ªëNGGS|–µÜήª¨¶ÖÙ›§«ƒ|¯ÀŒ\…¹šd`~wl}ƒ©ÈÛÖÖÑË°§¥æ Ö·­¸ÙçÔÒß»ºêèÞñûýûàòæ³ðªÓùAm/Ä€\n{jwsX\Yj‹´¸°\÷¼¬£µ¸ÖüáÀÝþx±·²“Í™×–‹+ çÕì<$ úÛØÇð_Ðýöö$9h¼}øÆRšº§jñëî0@NH?GXYS`l®°–„z~y{f>AY|sUjga‘ªž•¢h;5òÞÕØͦ¨æÜc”²Ñö(&& +73#!ýÊ®ÊýÑ’vWj’Žx|~nh-[Ñ:^eTi‡ÊüÉØÈ®©¥±¨­Ô¶Š–‘‚qžƒ]3.:?a”’í¶°ÇÔÆ“¥°ÔáßêÓ½¿ÈÍÕ˳äáÉÝðòîãÙ฀)±ÃX-Ô¤ƒbt‹{Š“€[R€¡““uÀ¨¯¥‰žÉæͼæöaàiZèöl?é1òßîøóÝÝÊÄoâ+ äê´Kƒ×çf|†3q›t!ðÈå>OfnZK;XmgpŒŒj^heSfy€‚ndVbkŽ„j|™®½œ‹~]GUE[a+ýØÝéÒÄÖþèä$Ofx‚¬Â®fl¢¯¿²½ò ýÞÃ5_o 19p}„t›ËÁÚG¢ìà£n™Å®¥ÌúóÂÁ¹Šuu‚“´³Œ¡ž]A&"mµ›´Ñ¯”­ýøÝÉÁÛÎß䱿ÄÉÉØ»–¸Ó´­½í÷îÙÄ­’NÏ¥ã?tlú¨”‘{yzƒ€†zXZŠ{ZßÓ¾®‘’ÔÑÀ×éÔJ/àŽñÒÉs{& ôàýàáÊÀôöãì“Íoºƒœ~ªxC×%ßQ[ÆÙ+2ùé*=A<7:svKQmKAAZWk}Ši^ynw…†‰ˆ}aW}…I91@AðÔæöÆÃìüÞí  )F‚a8OfVEP›ßÁhE5 ÉÓéæÞ3I.Sr»àú&<Gx®®¿Í—¢¾ºª“±àôҰ̸‡„™ “´ô㻥{a>2R‹¯æ̧Õàúï¼ÑìåãÊËãîóýزäÚ×춡ͿÈÏÃàúó̱u0Ímüd|Nꯒ††x…mttgˆl`&îÏǹ¢›·ÔáÝãóæÚ#cŒ·SôÂ(åäæ0&*ûõÕÄ÷ý×g>Àc5Q]©Ë6Ÿ.‹k÷o»Øñøìï %  -%*8JP}žoEBJI,ItŒ›—”•ƒ¢~r€•†’‹¼Ï”S$çíôÖøòýùñõËÁÇ»Õé2d^6.I†;ïéÅ´›«ÀÏ -?>'>…üEMlfh¡Ÿœª¬°ÍàؽÎõãÁ²ÆÒÜÂÍį³ÒÉŸ¯»–”‹‘Á×'ßÆæãÿ÷áîѽ¼± ±îåÞÈËêÕÜ߯ÅÆ·Ôââêñä»7Îxcž€oAÈ¡‹uhzpOahmptm]ãÁ££°ÐãñõÖŸ<þj{e¿¨³#ÛÛúûòû$)ùöðèñ˶YWšX¸Þ.¬,(߸/ÃÖÏÆÕç71+%--(Tpwy„šy;<PMO_€“‹Ÿ©´©œš›‚uŽ¢Ûèœ,' ,"àÓ#*0  ÔØκ·¼²¸á4@'"  $õÔËØóôÍã<}eK¿"uŠwš—¹¯ »º¯ÏóÓÁ«õ1ú£¥ßôîäÐË¿Á²¯¨ËÎÃÒçãÍÓØÉÊßéżž˜£÷óÚ¥¢µÀÐÖÁÔçÞíÓÜýñÿÛ‘!ί ©ãJZÿÉš“rQYmhtomp‚¦tøÂÁ²®¼ÓÎÓõðÞ­EóO¤Ä±K²õêÔÇà8U]Y\is‚H&•¤Å -?ÀÉ¡Ó3½úÁÿ¢´ž½÷!6>=XA)BXa|lbhq‚Ž^?TJA:FLOR}¢”¥¶¼º²‰{£¶ €I4'(, õô+>!úþù &  +ëGCü8TF1'5ŽÈè&„†Š‘‹«Ý¬¾ÒÉØѼÃàÒ°¦èÔ§ÒÿɻԶ¡¬•Ÿ £¤¸»ÚëÅÔíéÁ½Ìµ¤™¢éÓ­¨’žÁØí¶tŽ°ãð;¿à÷ßÚöÕô­¾³×ñ >BõÊ°{eyŠ~pf{†™…~™™5Ã¥·ÛËÕõÜÔóðÝ×uꮲÃĽ½³–;³0æÃÇÔìb‚¾"50¢LÅÊr€ûŸ–Ì>¸±„Ó»¦Ù RO5CW[JL>4Xmbuxi‹zNOgŠqp[^‰¨Ž’µ®žŸ¬™€d4úÛýÿ<@#6A0IP`qfP;=]{K"Lo]TZHCd’rft—¶ß"pžž›±ÑÃúóÆÜÜÏîݸÓÒÖÍÖÓ²ÃòÉ”›³º£¦®·ºÏÇÏãÞÚßÕÞÈŸ¥Þܸ›…ÈòåÚµ©«¼% ¿°Àï!Á¿Í̹ ¢žÑ0A(ðÆ´“pNfƒ…€kb{‚x„„†l ·­§§ÌõçÝõåÛ³B¼s<þÕäK%›ÞÑÝíKnŽÜMxŒ|CÞ2¢®$¦^»z¢„»‹ˆ;ÈÊÃH??SoˆvV?ADboj]Pe|iglˆ™œ¥¢•š¢†pwsŒ|›ˆr[\Nñ÷û *1:GZ?53W]ªÂÛðÑàúÛ«›™š¥¨·Ã¸­­ÈÜö 2r©µˆÍäûýÓ¶«ÃŶ˜®ÂÚãìûàåó¾¿Æ„ltÍóçãÜÏ×ÒÉÆÔ)ÝÚ×ÊÊÓØ´³¶«¿›«ïêØëñðçÉߌ©ÞûìËÄ¿Àœ.ŸÐ=GBÓˆ`WLj“œ‰uhiqnsx{=ã©–Ÿ’¥ËâÞâæîêºXÄ$±ztpnšýøjëÙí*3\¬ëùôÁr >Zó»g‡7æ‚ß:pb.§ɲí+?VXUw†jbZW`O^`U‹‹rgib{­¥–…xvn‚lhhDC3'7 þ¾ÊBB]¢¥»ê× wÉìÙâÔž‰‹vNBP\PNb1EXH„Ì库°ËÙîÿ¶e‹Ëʲ¢ºÇÖÑÑ&1Й‘ˆŒk½àõ è·ÎÚéØÛÑÔÒÁ×ÕŸ²ØŶ›fT}Ôà·ñ -íÊÇÒÖ¦¶÷îÒÂϾŠ%ÌŸÉ!+AG:û¹”vMRv§‘„|]Ok‰hEñ —¢¿ÅÛÎÖËßðäèê—™¥>3>4#= ªJ -Þàúý)J\m[E3ßÊŠ˜c¹ÇÛ¯€Ô¦É îq‰ßÂÛ4K:9SylhngMYi~‹{woPDRPYsžu…“Œ…}bfT@!÷öÙÁðLyË 84V~‹×ü$áóõôºÅ³›¡´©•Áή¯ËÍÕìðÇ¿ÕÐվÿ˼Øøë½ÌàÿÌ‘‹±•¢¼ÛÏÐÓħ¶èÙѾ“Š˜ÄԡƼ~ƒC -?ºÁÑî â©ÃÏÕͲ®ËðçÙЪn­§·ø*0÷º‘{]›¢‘xzq[az"嵫®¿ÕÜÃÊÔÎæçÜO‘ 6 û:cQ(&"úú '."·iàÏÀ¨;Q2%RųÛñãÕ1"ßòè .AK8LFCK`\^^kˆ–•†uQL^YDKlu`i“¢‰^C08- õþ Jo˜Õ9m¥€Œ¶ÙêþøÓêóÙÉôçÌÄáÛÖÔÆ´©ÛòÒÌ¿ÈêåíïÅ«®µ®èôßêö뻣¸ßüëêલ¾Â«±ØÝÌÂÒµÁæÇ›²¾¿¸Áª=×Äð2j£ÉßÖçÓî ñÕ«¥»ÒÖº³$ÏÏõÚÚí÷á¡|`ek~z{Ufh]sŽ‚EÎǹÃÆÀº¶ÐíéÝä5³¨D£æáò÷ôáÞ^f*%%ø+ -éðùçá#¤bCöd‡Ï9èC˧ñ+'ãô«‡÷ò ,OM41,Ci‰~š™ ©¢Ž ƒ?2?bJWr…€c?÷0k£î=ŽÄØÂν£±·¸Ô!ô·Ò÷¬¨¡ÊØÓæìëÇ£––¨·Ï¹±¨ÉôìÞßåDz°®¾íÚ¿ÈÏʪ¤¬®½ãôãè߸®¶ÂÏåÓºÏÑ¿¯ÕøÕÊÌÉ™Ž¦¦¬‡Ï<v¹ÑÚÉÐâ.&ß´z—»¸”d>þϯ‰[€Ñæͨ ±Ë«}[cyfjpV<m}}ˆ~q0úÌÈѶ¯¶°µÍó?Ç<˜¹SãÙæñôðëýG]+÷û(ÒÄÅÄÊÜ횢:esñ…õô@ëÇáF££Hðc9ºç(-1613<L‚”‰Œ‡ˆ‡’˜Š“—‰^dSGGOeO6;=)þ÷óð -/{Ã{Âççظ«“†¾Ã«ÀêíÒÑÉϪ¶ÚÝÌÊòøÖÎΟ”¤Îá‘®¹ñäÞúÙªœžÁâ,ëȺɵ¢ª´ÛâÝÚÍÛóèÎÑÄËÞÝš©ìâÕ -òæ÷Ȫ‡Š«¾÷€Z¶<¡ëõïÙÍÎùÛº¢¯®ŽsAíЛtwÏÑ·‘†ƒ‡pUdWi~sKPt|ƒ‚fR Å®¸¼Ã°´«³¸Íö3„P84üèèäÝñ?P:èçîöÛÃÍ×ØÅÉFªQT#"¸ªÿ?v°ŸpK$¬Ò%$+*=9L[€Œ‚‚“Š„vˆ›…QRf‹u^9âç  ãÛtÉ.™ãâãèÔÎÛäÖÄÉÊ×ÉÕØò⣼ôüÜÔçÒÏÃÅÚÉ»ÔËñÒý- Ü¥v—äñéÙÁß̺¹¹íéÎÕÁÀË» ÎÕÁܽ¸½ÓÈÆí ÙÜÈ¢ÑÒéØUµuIÈN¬ÏÝéÔ½·ÈÉÆÃïà—€g,þÃ}’Ò2)Í¡ŽsW\c`WckphRo†ŠŠgK»žœ•§«¨¶­ÁĶÔ=–½˜xù7úéÓÎèLhi;#î èàçåßñ×ÌÒÈ {f[ê†Ù¾µë©& ð!½çåãñþ "T]g`[t…|fo~‡luƒ€e5ïâÙàûÿú÷õÐÑ€Üõ!`‚­ÌÛË×ûìÕÊÉ¿µ— ¶¸ÚÇÉçùàÉÖåæçîÑ¿ËåÕ½êíâÿöÍŽÑîÉĹÅÎñ׫«ºÿÓ¾½ºµ–’¶´ž·­ÌÚ¶‘žãçäà¦ÇûéíÀ;¿X_úiš¿×̾ÎÀµ®»æ䦄k ÿòyÅÿã´¦‘xO>YpolF[”£ŽsJÙ¯¤ªª½Â¨®¶¾À¶Ü*FÂùƒ,4Q^swU?64=/þÖÕçôùóéýù8 úü‡Ly€s½ò›o€ÓϤÙÐÊÃÜÝã÷'A=Udoƒ™Žmtqm}vcUI-ýùíòùßÞ-Ë8z—¦µ¨Ç×ÏïþýáØëÖ¶½µ¢·ÝÆÐØÍñÿܳÂùñÕäûÚ·¼Ô÷æÌ䬑ÁÎÉæõæ×»š±Ó×ÍÒãìñÁž¤²‘x¬ŽŽ­ÕßÕ¬˜ÇÒôìÑÈÉÎÀ×–Oõ‰†ôD€¯Á‘ËüÖ½ÒÙÕb*c@ßû3Á³â Ý•¥ˆzo`b\`{–‡P-MŒ{jE6ëÔÁ®ËàäÕ´¹ÓäÏÒðÓ¨X0çRÓ}[iouXHRmsS>41'ááÞâëï!%%X.ô£þÕÕ³àÚʇ96ltÙÔÐÏÂÏä÷\––qiig_FCcN9$øøþöþ ý+¡äºÜøçßÈ¿ÐéÔã ùçöààâÅÂĪ°Æ²ˆÂø׺ÐÊûÚ %ÜŽž½ãäÇ¿¯¦ÌëòÏÀ¾Éß׺Á¹Ñ嚦–{”~Š–y¸ìª°êíûü¯Í°½Æ¦®ÃÚ•¤É!Db‹ÏûÙÞô²:Ý @4<2 "*§•…Žq^Rdx†ƒDGe„‚oU0ÞÙŲ¶áïÔµÂÕÚãí˜Iü­¿]Ý¥£“r=èõ&I2#ñÍÇÙæõíú‚™žLÕC\aQõ7¹fIq@WÊ×Í»ª¤¸ÉÄÒîäð&=<2(.54íèûòÝèø-& E¾ReŠ—åü âºÂÎÖÛÙàâöúçØ®¥ÅÐ×É°¾Õ¦­þüëçûîÛ¶·ËÞíÓºÌæÖ㦖ÈüùÊ–ª¶±¹¥œÈš„‰ž´ˆ‚ÀîñÅÃÐ2äè±°º¤áßÂÆñîd¬ÎÀœãkÕýÚܧ¸Ø@D.]WAZjWCû¢“©º”f_fjh]dda€„pfsd/úñ毚§¼ÝçĹÄÚôÂMå]ÍóÎtf€”h ÎÍà)ñõèÜéóüííëû2BWJm« EIA4ãobr /¹ÑÕƱ¹ µº¿ÕÝÕÊß!÷ ôãÞãÜ "aø‰›°ÑʶËîîåÅÂË«ƒ‘°ËÆÈðþðûùêÀª½È²Èïæ¿u ÊáæàŶ¯¤ê ,úˇÍÅÓܯo‰ÁÐÓ·¨«ˆmŽÖïÆÉîñõùÛØñ$ö¿¡«Ë±ß"êÊê ¼ÞyŽj)…2Õá¡ŒÏæ*‚’–L:E5Ó¤€¯¸}Lq˜–ƒj^dmƒ“hKH/ìñ貸éúÿÙÏËåÅio¸3%F,ú(TBï×ï* íìíáåñÛØàãà)9@LkŠ¡–{ubPP_fÑæ‹Òí⼨•£ÌßêûÕÕôüâÔíý,ðåðÚÓî Pš<µÞ´¯ÜÝäãÍÚê×µ¦¤µÓå®Åïñ  üË¡Ž‚žµÚû¿¬€lœ¸áùα¥­Ò÷ß¾™Œ»ôÓÌѾ’ÊÐÊŸœ‰–‰­æÙËçäîäÍæí×ȼèÕ¯ø"ûÔÏÿ ý¾¡~lb–#ªµqD ,qÈíåŸ1!"Þ¿®°Œn‚“pgŒŽz~}eat~yWðâó ëÕø91ñàƨZr½JùÞÍÌÛõü þêðïéêãí õÎá-ö -?O@NVA#1p€_C•»ÖòÞ¹¥©¤œ½ÚíÜÑõúúýþ÷æöøÖÍêþ0nâ^µÜëÜÉá -êôò½Ÿ¬·³ ¯ÉÑåöëتž¬Êò᮪¢²ÊÇËìÎÄÛÒ´ÄÓª²Æ¼ÔÑÒÈ°·ÉçÜðþääëɶ»ØÊu–£ÂÕÝéº÷ÎÙûñßÕÌÐñø´¿ëþá÷úÝ·SØ~z|šöTRH -U¢ÙðÎgìÔËž¡ppo}xssY‘ŽtddaYbb½§â0VA"j¥["üÏ~–ñCùýòþ -ùש­ï,0.ýôõ  ÷ï@@&ÎÈå %3UDK¨à·MqzvÍåÝÈÃÃÃÀÈëöðßÿñììðóØÎìòÎÙ8[jÆS¿ÑÈÀ¿ÓÚäØáêéậÁÏÚêÊ­¿ÞÔ¦«¦¦­ž¦Æ )Õ¥ººÏÞîƪѴ~¯ÛÀɲ«Í×éîùùêòÛèÛÝÇÁ°yˆ—©çïß᫼çËÅÆ̶ÂÒÕÖÉô*ÌÍÙÒâÙ{ùš€q”ËÍÚáÜóg»©¤xÔƒ€ƒ„‡}s—†p‡†XK‚¦‹qˆŒW8'õµ¥áAzm‚¤E/þ½@Ë [ϾÒ÷ -%ÿÒÉö*#  -33 ýóBA=áßô þ -/Vf\f±õÔhG9eÙäíÖßÉ´¸ÒáôõêàÞëÜÚúðÐÇËë&<N€ØX½Ïµ¢¬Ä×ÖÖäðëê㸮ÍÏù êѵ´Ä»¾¯ÂÁ…‘ÃôڶĽÈÖä˾ÙÒ§ÍÓ¹»Ç‰¿ØÓßëߥ¸éãÊƵ²ªŒŒ“¤Ìè·»ïæîïÓ×ÞÍÇÐÄÔÏÕ­ƒé#©ÃãÏèÓŠ!šYT‘ª«ÂÏÞÜþ[™šbåugja`}“¢°›€‹“Zp¤€tž—²–HýìʳÄÝ,{œìG"’C1÷‰ c’觶ÒPT4 ûò +>HA2'ü÷ôéê$, -.æäþþVfQYÀò¥n](kÞòôéǾϾÏìø羿µÇÝáÛââáÖËÜ!P€ ®ÎÔèкÚç¿ÂÞð×´¸Ùîí×åþíÝ̬—ºÎ½Éæò³¥¬½ÉÕñÓÙÍÄÖòÚ̳¦–¶Î¼ª£¢²ÊѼªÐµ”’‰•¡›¡ÎßíÝÇË÷ ìÌÛðí×ñ¶¾Ã¥{¨ïîþ´p¯ìðìÞ·œ@w&D‰˜§¾Éßà"QsMܦŽwhWmmhgw”h]dz •[ZŒ›–OôÉ¥Ÿ·ºå3}ÚA(µfZR©3ÛÆÏñ(J;éßñ&VTQ;ñÝÚëßÛó!ÿ îàòù0R*ZÑð«u„$uàûìÿÜÓÊ·¬¨¼ÁƹÀÎÛйÅáý1›•ÎǾèÞÔÔ¿®¢®ï鼇Ò,þË¡¦¸±–™ÁÃæú̽Î×ÑäëËåü·‘™ÐÕ¼°ÏíøÛ¡†´áà“n‚ºàéݸŸ£ ¥¹ÆÒ°¯ÃÏÙåÖÆÖçø½ÍÎ×ƳÄÍƤ¹æÓÍ·¦¿Þ ﲨ¿2tObŒ‡‡†ºÙt„9¼†—“w|mkUISh‡yXBh©§wQKrF伖·±Ù[Ø!)×in §côãÒà÷&&ñìêôðÿ5^X5õÒÏÞèÜÉÔïéý   ä+Ÿ8ýááäñåùRÄéÉ–•&KÝåþôöè´œ˜Ÿ¼ÎßàÞÇ·ßáñ 4N„¤«ÀÓÕéìðáǵ¾Òß·ŸÔþÚÜ­{r”µ£•œ””ÄÙǬÇì ñË·¯«§¶²Á¾ÌÈëéÀ«êìâד‡‡°ìÀ‰™¸¸ÄÙÆô¾ÙÁÏÛŹ¾Ë¸ ÆÏØÌÝëÙÌÛÈõ÷”¨ÝÎêíº¸®ƒ{mi~œª»&h*Ö„l~„˜Ÿˆvsfz„–˜•…–³ž‘ohb0×¹¹Äæɱàt  í†XˆÃLJÞߨåÄÕí÷ûäÏÖöýË°®¿ÆÞóð÷ü ! íæå-|žæé óÝÝð4ŒÀ´•ŽMWÈô&ïÕòóèÛÄ”±ËÄÊßàÍÏù;V”"‘«ËìíÏÂâúÐÃêØ´Äú在Óî¹µ«¦ÌÇÃ×âèåý5#çåÛ¦œ¥‚¨ÀÁ´ÊÏǽÁå@(å½ÆÁœ’“t_|­ÎÛØÍæöãÅ¡Îãæн߽”Á±­÷2æÃÕèë 옯ÎÁÆÙódz£ôyƒƒ†š‹¥ýŸ‹nv”ž¯œ†‡‡‰‰’ŒŸ­š‹‰qJñ¼± ¡Èü/i½Õ®PM‰ªó:ÙÈÕÍÒßÛÇÕÿï¾µÏÔ¶°·¼Ý,ø7ÚÅÚâ_soøÛó õöü÷u’aSŽ‘žôüé×ÍÖèïÕÎÑÕÈ«²ÈÔÛú+Ek£~·ÍÕúççÙÙÚàÒÓõë̺ÒëΪŸ°ÉÜâÀÍðòèàçÙ©­¾¹¹ž•×ë×ÆØÛ·ÅæÒÒèîЬV`­·ˆ¢ËÝÍÍÙùØ¥ ÙæìÎìüØÌØÉò1E1óªÀê ѺÂØéóîôÕ­”Ês‹}— ŸŸ› É§os”–ž~‰„‚ŠtM]ZXkvqkaŒƒHöÜ¿š…Õ)1>Mr{jPSfƒ7]7ñÛÉ¿ÂÏíüíõôÜÝ® ¶ÑÕÀ»Æð1B;ëü04öÚϱ KïÌÜ êÞä-qQ0ŸÓËCæèéèð%úÔÁ®¡™¦Í .•†ÉáéäÎÍ×åÚ¹¦­ÂÚåÑÓÄ­¥«ÃÐÀÔüéÍÏë  âÆÔÅ£„Æß͵ÌäDzÅÊÒåÉÈÇÞиØüþä´hj½ÛéüöÛ¹™´ÑÉÂÚüÿ øß÷ öÔë"ß©´ÜÛòíËïþ餤ø€´[@bžŠƒ£„ˆ–£›£¢—}Ze€‡†O@>KH_lh[U5 -óãîë×­§Þÿ<Qb`a]Z-ŠeNéñéÛÓÝî ö÷ìÙ¾½ÕÛÚßèÖÓÞó"8- í8; îÑ=ÐXž».Ñ®ÌåüýâÎÚZhTÐAiWñÎßü@)ëÉ~ Àì$3€‚¹êôèüúÒÞøòȨ•¾þòáĪÐÙÙúÝÍƲÒãç×ÓãìãÃıÂÊ«œ´ÓØéͽ×ßßïØÅÐÕ¯˜©ÝðâÓË€‰ÑÍâý%º ¸îêáåßÔùóèûõäÆ®Äüèñÿôîʼ½Í Çí,c*~‰^q‡y‰©²²É¶œ}Tnx~‡†i{c[x‘]&øæçÿgz?ØÓÚó %GbgVCe^kááõñð 3!÷Ü×ËÂËÙéëïýñüø -,5)!&EDìÚÜ—ôé/è¼±»ÒÛðù;{~ƒ(\>¬ÓÉ¥dõìÛæ!íÔ Èï%tÒEŒ²ÀÙêξè÷éØȽ¨¯µÁ¡›ÏòëèèÚ¿°½ÀÇËź½ÃÓ°©Ê¿âûìÅ›¹ÚïâÄÒïîåÐÉêè©€‚ÃÉÂÏÆâÆ‘²èóÊâã¾¹ØݬšÞþûó½Á½Ãþ ôúýâË¿­ÒЮÆúZSrzcmq‰’¨¦ˆrp~„wwy…«½¤^ÿĪ×{'9È6ûùô÷,6"ð½)Uðßë &8GAêÌÁ¸»ÑêÞÑîöë 13,#95 ÜÖPRLÛHøé÷û÷ 2…¢¨UŽz4„oAÉS$"1(þûü3rº¸­¢¦¹Á¬Ù⟬¯¦¨›‚‡’¬ÑÁ¾Ê¨•§¯ºÅÀ¸©²ÂçèÄÌèÞý ùÂÂÌÄ̳œ´Ä²¡´ÝüÅžŽu¥À¥}ÄàÛÆ·¨´±ÊÓðÑ¢­Ú¾™ÇéåÙıÑïëÆ¿°î -éÖû Ì¥¯Ëáøå·½x bGg¬´‰^M\af{‰jPZ’vi…†|Œuh”ž†[îÙ …äµ€¯1TïðûP„>¸Ð"Þåòô(D7'#ß²©º¯¤ÍäÍØõóÑÞ2;A (6 Þ϶ÐñÔJ£;1LTVHqâ$¶ËŠÌ܈¹ŠnG ëâÅ•qW=DQQVg³"\{œ—•‰®³²´Å˼¼¶˜¡µªÖκ™¸ßÛßêÊ­ÓÙÆÌÂÀèíËáèÐÉÞÇÌõÛˆ˜º¶¨©‘¾ßáùØŽ¡²«¨»ãÇ¿ÞѸ³ÙßΰÈêɹ¸¼ñ÷»ˆ—­ÐÊÔýäæïΧ™›´ÏË̽|>ï\™‚}a=;Sl`irjPf”|†‘¢‹ejaTLùýë´§îx -faìÜÿ'BMš‘+î‡ ëíô(GF. íãØÔ¿Á¹¦¶ÛÖÖ )ôèìæû&M[T5 3K* Phž¬cüƒ/*<g¦ç…\¯I½¯7#$ºÑ¼¡®§gäËÌÔʽÖ9^w¢ž¯§Ÿ£ØàË°ÄÖÞâÙæèç+꺻ÊÜÿ í´ÏÝØÙËÔëÐçåŸy“ÔãÛž‰¡×ǼÄÜðËÝÇËÞÌÁ·¯Å×Í©£µçþ̯ÒåêôãÖ' -ÿÅ+ Öºó çòú -À™¯¡‘ÀÒÏå÷ÏzÑ'å×L<ifYcj_Zm‹“c^…`mŒ¬uWB<,ðëÅÓý&Š”)Ú÷2Rmåqn% -';-äÜãðîÎʺ¿¿ÎÍÑ:äîò÷!?MR9"<[L2%þü/a;îžY+6†î -ÿNÅF*TÛgžºÒëçíòçÁŒi]ROIKM[Ÿ ÁÊÌÚÞÔïôðçäÜäìüõÕíëÉÊÊÕÜÒÏÕÝÙ¶®Ïݼ³·Áëñ­¶ñ×wÚᶷïíßÅŽ¤ÌɳÉþßÞɤ¯ðè÷¿¬´¬ËüÿF,ξÆÅáî$îÐ×˾ýúæáâï쟵¬ÓìùuŸðß!2^PO_Tbw~zxpy†]DLeŽ{]:&úÑÅ÷à¸Íʯñ *v…ÅnåÔø%:XKíÓË×éïèÚÜÑÚåÜÐÚ -ìëÞÝî -!#+.@FJ?$º™°ÓÒ–oV7XÍ•¥ÂÆ \OcÈïïíÞ×ÝìɆsqŠ–¥­ ³·ÙõæäÞÛëäÎÒÿꮳÖçÝÇÊ­‰­ý -ìÄ“‡}´¼Ñõî­{‹²Íº¦ÂðòàÌ–·&â¹Ýܺ©¯Šq§Ë³ÇôìÝìÉ®Óñ¹¤âñɼÈ÷ùõ ×¥§Àêùýî¼ÕúîòÄÇÅȵ½ÅÌéÿôÞ&4)ùìí>?7=?K„‚hFBX…M:,&&îõÊ—Ÿ»¾±­Ì¶˜Ì1„ŒðÓŸüåø/&#óúàÎäÞÑÅÎÑßèëìôæâ öïóçç+EJ4‘XEUNISU6Pêá …¹ÂÁŒqˆ˜¤ÄÞÛÎÕ·«ÈÝ›pmn“¨ËÈÒç¹Ää鶴µ«·¸ÕÞ³„“²ÆÁÏÇ—Ï ñ»µ™©¸™²ÖääÒ­ž§²²¾ÜÓ¼ÇÅß ÝÁÚÑ®¨Åæ´¤ÜçÊÑâä¸ÛÖÌí×›™ÂááðäôôÐÍᶶº¿ÚâåëØþö ÜȺ¾©Å -ýÚâøèÎåö§™-êÃÍ@/'Ihƒ[M>EJch6)Ú‘Š´ÕæÒ©‘‡“­Ë·¦å,Bi>l‚¯'ý5+éÏËíâõýÓÌÁÊÓçòúòáé"6îÙé ï÷ú - %HCùŸ<ýIZEjóçE7š§ ­® °ÁÁ²¯¬¸Á­Œ‹¶¸–€š¼ÖÎØïöÛ´£ÁÎÊäÛ·¢¡¡— ®¶ÝóëÝàÚÚèúÜÊÅÒ»£ÊÍÄÅÅÎÏÉ¢–çðÉÀÎÝîÚ¿°±¡€‘²Ù®³²­¢µ¶Äöܬ¸°µÚùØÍÄĪ‘«ÃÛÃÑÙÕâßÙøúüøȶÕÊÈÝá $êÏüãËƤkâ] -õ¾Ùöú?NL8+$EcO&Гv Á¥¨¹Æ³¹® ¤¶ËÈâ6Ph,>2{3.1-8AëÇËÿýçùôõßØÎÎÚðòìë<5áÐÏõ!  4J6 -“5 47^½Œß9ËиÂÉÅÀ¼ºÄÅÁ¸¡ŽˆŸ­®¯©¼×¿©œ¯ºÐó×Ê×ø ݶ”oŸÒÙïýéÎÚÖíìÛɹ±Ôë -ßØÅ‹ ÆÈ·®¯ñ×Åàë짱Ȼ¤·×çÛµœÖÜ»ÉìêÆæüâôϦ¹Ï²––´´ÉÏÖêÓÇõí×÷òò÷ÔºÔÙ½àñçµäûãáÓ¶|¸6çîÛÆÑîßÎÀÝ$òí,'ñÅ«£Íä´Ž¢¤°Ë×ßç亹Û+GX2kV¢lADBE5ø̾ÏõäðüççòÖÐÖÙÔÓÇÑñ)N.öÎÄã84+-!&+&†N62%  v9c½±ðÝÁÉâÛÕ×ÐþÀ¥Žƒ¡½»±¨ªœv…“¯àìçááèöÛ¬£±Ð ùàéÓ¥¶ßôÞÀÔËÉÖèòúë“€ ¦Ÿ‘—¾äßééÜàãÄz˜­£µ¸Ñú ÅŸ×ôÚàûØßÿüþõô¸’¬ÖÅ°ÀîêÙöÁ¾ÍÜìÆÒ÷çÊÚÒÊæËÈÅ©¡ÓàÜÛÌàÀ¡”:£MíÛÇ»ÃÙǹ¹×ÕëíÚÛßá먱¾â¸~¥Ä¤§Õï óÉÜ)W;êSe§QRW)Ô±Ñæà×ÇÓÜôûßäíؼ¼ÆæáÀ½Ãè=ßÓç ';@>:;42øþˆpP9õñôÿ k#+ÕøâåüþûÛ˾»¬‹Ÿ¶¿Áµ¤ššœ¡˜ˆ›ÒóìÔÂÍÒÁÛúÄËè»ÐÛÅÉêÌÍÉîöèÇÌï ßÎȸ­˜ºº«±ÓìçÔ°Èß·¨´¯»ËêðÃÚ÷ÕÄÙÁÔ Ùø2ȹ·º¶ÃÊË°¸èþíÿ Ò³¿ºÅ³Óæ˸¶ÇîæÈÚÖÃÑ÷Ñ­­·Â«“hð‘cÔÕÐÀ¸³ÅûùôîûâË»ÛÑ¿²»ÇìܤŠÇÑÅí üþûøô2S3Û@›O32,óâÊ«°ÏöéÚÝÛÌéüòóïÕǽÄÌÇÍÍËÙüíÙî8?WhQVB!  -—wS4* &iã§b*´ò ùñàéìз§¼®‘Œœ•¥¯ºÑº¬šž•½áõìƽØéáæçÛÙÞäÉÇÖâʹáûßÎÈ¿áþͯ§˜³áçÉÎìÓ§³Ä½ÝÔ©»»¥ž°±¯¿ÔÛ¾²ÛïäåÉÕ Øà Á¡™™·Çý -èºÌÈÔàâëíÚÚÛÝØãêÄÇбÄÚéÖÐÉ«ÅÚ®±»–<¿SÁÀÖÄç̨ÇéêãתÂáÕô¶ûõàäàå/WA' ôDqSõY‡ÃqX'ç¿ÈÜñöÿéÐÞûùóñ#úÛ¾±´ÇÊÈ×ÒÂÌÚÝÞþ&<?‹”]JB.*BRSS,¯ˆZEOD$þ'ÅÁc¬!Ê[±ËØÎÈÒÐÌÁ󪫞w…°ÄÍÕÏλÂÙíáËâêáñéáíú øèÛÒîʶñز”³ÙùØŒŒ¡›ªèÜÖãÉ¿¿°©†–Ͷµª ·ÜŸ´ääÔÅèòæòç¯ÌÔ¬´ÊÄÉÍÆÎ$ò×ÁÆÍêáæò×äÖÐ °ŸÃýÙ¤Úݯ· -ÑĘ́rÜÅÞ½ÇìÕÂÐÈÆÉîá³Î÷×ÏÑÞéõE:B‹Ë¶q@& Be -zäA¨aCó×Çßî#ïßò;;>'ïÒÊËçç×Ä´°ÑëèÕðP§­WOZ\{Œ„lF#¢vfY^L#óÚÛc|+*9³j‡»ÄÌÏÕÔо´µÌÞľ½¤¬ªÒÚáÛÙÊÀÊÒæöøòòöÙØØíûɱÞÞ´­´ÇÕݵ¶ËÈÂçú²¨µ´±µ¤º£mƒœÐëñɵê&À°Äçý òĶ§ºÌ¬Ÿ¼ÙÝêò¿Ó* ߨºÕü çȼÄñò·Ž¢ËÖ´×àÁÊÞãã÷ê•Í;ýéì׫ÔػþØÉ¿ÈýëÈÎþ 0>3üK´*D¾Y!'8ƒ|ü‹"¬u2øðõ ñú 2SZTaD÷ÛÙáíõçÀªÁéðé×ã6T‰q@K^ariRIônv}€`Th;÷äüq\ç¾’¥CÖ`«ÛèƱ¥©ÌÚß×ÚÓÓ¹œ‚¢¬¢Å×ËáåÝßö  ôÎÂÏéÅ¿º³ÐÕ³²ÑáöÑŽ¥³³ÅÞÔʬ“’©ÇÀµÐÖê ú¬£·âÝÀ¹ÀÒÅ ¤ÈèÙÖηä& òĽÐù÷ÓÛîúßéæé·…—§¨ÀÖ岌¸éïÓÙéÝW‰+÷ö -òÁŸŒžÆñæÔàùØ»ÆëR_Q5R¬úJ„Š(!;dn2ýz®>(÷ñ  çÏÏìþåæ ":S? -ð×ÊÓÚÌž¾ÁÙáĸÞ59891&-78$ -ïë:Z^ZPSM-+QºJ¯žN-ËlÁ^«¹©³¾Ìã×ÕȼƲ™  Ÿž³ÍåñæÜÎÈÌðóØÄÇ×ÒÌÚÛÏâÑÄÐÎèé¿ÅÍéûåÀ¢—»Àíô¾ÛìØÛײ§µòòãöÛÏÑàì èʵµðûñþÓÅdz±ÇÆ¿¾¯Ñéìðú À˜ºÞý÷õº“¹Èò®ëìï½ÜâÃáò&]%@l‰6É‚¬ÚÛÄÅÛæÜøââçãñGÒó—D,7RDê…/ð² Fîæ !êÆ­¹º¼ÚæáûëòêÕÔѳ­±³ÃÔÊ«Á,9"'"ñóüÿ -ÿê>TQGS\oÇõGš‰Áº$y©\Süe–µÒ×üýø俳¿»ËÊÁÚÝÇËÔËÔáнÊȳ­ÃêÿçÇ›ªøøÉÛð¯ÁÛÏУ´”ˆ¼·›°ÃÁ¼ÁÙÿ ùßÔåùïÕÄÖÒÐíК¹æÛÞÅÑüë'ïÏáßÒâæν¯·ÜòÖŠÀ -íÇÞ§ÊÙ×ÕßâÖé$ û°›Úš´'eŽ¶Ñ©IÑÝÇ·ÁÔÚ 1þÔÇÊ«™»Ô$hdM?) 7/úŸZF¶-”# ýï÷ÌÀÀ«ºÔåõúçôóèéîÕ´’²ÑéÚÆÕ 3PFG1ðçø‚ÏÊ>Pi¦ÀÀÙô4•Ê‡ÝXG¥õùW9qÕ3 ðÌÔÒÕĸÛîåãμÏÐÂÔÀÊòåàýâËÑìïÓñÜ”•ÁЦa‹°–“Ä·¥Ä¼Ž”ÁÜÓÃ÷âÔÔï﬚ÁÛëżլ³ØáÿðýíßóææûüõãÈñî¦Ô8±²ðÀ·ÚîàÅ(Ûãüðùé¡š_ïí3»Åʾ¯w.åÒÏÌÎÞÙÓº¸³’²æø  #@Aú‚-$=H -ŽÿyõíýéÔÙ -ëÝÍÐÏÄÒ÷ÓÛ  ôÆ­®ÅßîÖÎø1TsgL0òý)s#·¹Ì1Œá}û˜ÀîoϾ¹@z ÇIw³ë ùÏÓÔ»ÊÞ öîóíÒÁÁÓÜçöúÒÂÏñÃÕðòæäÚ×Ù˨™Ã̶°³Ê·ÌÍÅÖÔµ˜–ÓîäÅ´ý/ -Ì¥ºÖ²©áðÆÚàõôÕÒÒÖÏÃÎÚß×éÏãìŵ°þ´·ëê¹°ÙéïËÏùþøóòÍáíÓÛÅÃf¶&ÌÓA¿»´°º‰QýÜáôèðôãÌÀ±´¶yŒ½Ãå)=Wù<ÂÖ"FªIö…)çìûþòÚÙèØßëÜÒÛä÷)åÒç(.ÿïäÊÍÞéßØó@b‹€N0#&øî _ÎÁÑÄʉþIF=?y÷Ççs Žsµ?¤ßs*Ž®á@‰œ¯ÂÇ©±×ôôñöìÖÛÚÑÔÈÆÁµÞñþäÅßïòíÞãíÔÑß×âõÛ¶”£ÚüéßÕÐÒÓÔôé×ô辴ò¸äõÉÕÜËóÚ­·äýý·¥ÄÝÔÅØ϶òûç׺½íàʽÖËÈæØÏÙÁÜüäøûùñí"ñ¸¾Í“rÿ®ÆY›¢Æ ˜ŸDýóýëͼĻÆô’œ‘ÃFI@I¬¤a±Q*ý£, èÆ®»ò'ýüûéùóêú@X6äààéôôó3XŠfA$&.%&oí^ÒÍÐÍýeÛJtwhh­æÅ XAdpLD€áü'´JÄTô=bngÀáÑä -ìæååÓÅÌäØÌÅÊêßËÌÒÙÖò -äÄÅìûìâäÝ×ÐéûìÓÂÇØóýàñÔ”›£¬ÏÚèþШ¿Î··¤®æý()ã·ºåáÆæýðàâ¼ÈÒÏÌȾÂíãļÍÓéÿ÷óÕÎ4$å°Ž$”AÍŽÍ_“ž­¡¶Ä›S. Ô×ͪ¥©¾ÅÁÀ¶¬ŽŒÛ'jZ’ûžëT\ñSùöÕ^"#Ѷ·ÉK{^:'* óøôâÀß&qhðòüðêù)6R“sN-72!<€å%ÙÙßÌé+±A‘¨{Z‰ª²iÅcUK3"RŸµ‹w·(º5³TŒ»ÿ,Sƒ¿ÃÄ÷$ùÞæýÀ¦©ÐîäØåÒ˺´¨ªÃïìØÎÓåçùßá×ØåØÊÎÃÌêë¼Å½Ç̽½ô"í¼µ²Áå æÅÌ 'ýÛÖæØøñôúÖÒÍËÔöøÕÞôÄ¡§ÏàÒàç·¥ÅÜþ ôáµ7•=íš‚ÅC¦½—ÕÛ¸j;߫Ǹ—¥®°ÁÍÈ·­žÍGbK×<¥mÎ -šî5ú€*"û棩½ÎŽ÷õŸgKöýÔ¿Á§Çc"üûøþ'=KX…Ä¥n& #1*+t²Ûë°µÇÍò+¤C¦ÌŒ:;r°ÍqÙs< -)Zn_[‹È@ð„ì2[’ºÁÑŒÃñêËç"øå -ëèêȱ¿ÎÆËÅØÔ«{ŒžÅêßÕÕÝßÛÖÛàóåâøüÄÇèðþÿðâ¹±Êá±›«¤ÜÈÀÊå 42ïê -ñÀµúòÌãüÿ  ñÌ»´»ÙØßùן¬Ý Ĥ¿‚â: Þ’‡¾_¯“†­½§O瘮ĭ ­ˆ”º¿®ŸËí+s`M -e“ꃿ¤0ýTVüu. òÒš¢¸Ü˜6Aå{)æ½Øε¯ÄÕ*µE)MWSk®Â†G"Pls»$Ý”¬Õ -fÓA¦æ @(LŸëëN†.ç×Éì%E:;?€Ín¿¾Æû4SxãZª°»×ר©ÅË×ÿ÷ÇÎÉÈÊÌÂØÔ¥¡¸óÙÁíùåÎÆÊûäì4øçëÕëþêÄáýÔÁ×߶Çå÷ÝØõÂÄâ4 ßÕÛÄÊéñã±£ÓíàÖÝ —ÔëäÏØçôâÕíñ®Žpóm'ä‹¥Îôø=Œ~gCøÁ¯Ä½ÊÙÁ’§Ã©ÇÞ$Rh<ëbƒ¾xÓKuN þ@‘iúy6öòÍ¿¾ÊâüOÊõ¿Xݤ®ÆɵÌQúWÖJ1BWv†’¦‘SGXcp¿%q“ľfë·ØÆÍíWÍ =™È|næ(ÆÌ þàËÏåÿ2P®[ ]…œ¼âýX¯RÁúóèÝΙŸÐÝÓÝíìÝÞôüòøÐÚøÓÏ îÜâåíõÿüïíÞÜÜßàѽªÕß®ÇØïþñÚÕ鿤ÏèëÉÉÉÎÊÄ‚oq^Obr}ž×âÀ¤“· íã¿ÄÐèêÓæÊu»iÕÕ¸Ÿ¶É¨Ë öÏ»¾±²­ÇÓÈÏ̸¹í7tFÊEò‘ò•”ñFQ66x|%½]òòîéïÛÛ×ØHum ѯ˿¯Á Ruƒ C(Re\„›™€lJDsœÆ5Å¿z%îÜôeÓ^¸±På×ì8¤*ºª»á 'èÎêjÿ‹¨»´³ê2&L¿6«ÈÉÈæúñëæÓåìîéäßøÛ¼ØÍÒæøúö÷åê×Òð ôÑÏÓÍÒæ᯦§¹Òɱ¼Òòù/òþ& ÛÔÛ«–žÈ»`Ú¼ÒÝè  -&zˆŸôõ¼¼ÖÜ¥—Žl`³‰J1쬭“…™©‹yžÌ·±²”’£¡™“®ÖùæÔò 9ù=‡þùNb¡¯ýUrl68gUãŠ?åðñóÔÉë#ûêß̪Åb­O±ýG)TˆvwnW^€zd„ÆEqj[2ÁF6N Üûc»ð»GÞÉÝ÷;Ö-l¥¨»Òóþᨤü¼Ê·­“œÄäÖÂÆK®ò éÖþ õèØ×ìçÁ½ç÷ãËÃÃÜóîäÆââÔßÿëÖãîìáÚɬºÇ¹¢½ÙØãïóø÷ÛòöÉ}rà„Xh`>>xmgH9MNTü8 .ƒŽ8øÒ²’>óáô×Ï£f„ž’„’µ˜ ¼¥‰tžžŒ¯ÃÜÜ´¿¸ÄÀ!´›ª‡@²êH– nô CCÕyHù-ééóíìîðâÙÔËâ$™)οØHX“Æ®’S5l½ðÊ“xqh'ôï,ýö$|¸²ÍYúÀ·æŽBÍú˼­´ÚöÞ»ª›£9fxÂϺ½Ã´©·Òó!Y±ÝÈëÿäÔÎÀØðÛ¼¹ÃÎ×èñáëÚ·ºÊÓ»»ÚÛÆñ6EÊÖ¬°××¥ØýøÇÎéêÓ²Ùë¿œK -¬D487çê@@Òú)+ -+<>^j”•s’™•s>4!ò»¨¯ÁÏÃuz¦«~‹½ª˜ºtz£µšŸÃùõ{霠ÅãäÊÅÅa×£Îr¯³Q øÏl63/'(;ïâßí#<HbpZn¿EçWÉÈxšÆ¿ e8?ik\p@ýÿ  *;]½[ÚýÇy%¹xh´RCnv -Ú«Ž¤¾Ç«º´±4r}ÁÐÔØÝåô#0&7WŽÑfúýÞýÿâíÚÔÌÍÄÇÞÙèöú÷äèäÐÃÓÍÃÔνëéç+â°ÏêåÇŒšåþåã÷ÓÉÙ÷䣋_Ò~G -7]F½ÐçàñååñæÕÓüûñ+ 9&ìÎÁÁ§ŠÄÁ¦§˜®ÏÈ©³»ª»À¬ÄÒ¼ÍæŽÎ ¡•õR-ðöüt„aÚê&P¼ŽO/øÖÀ¥^/ 9*Heîÿ7™ë8š™µz¾µãÎÛÉ«iXXScRM.1R=øð-06d¤ W£ìóÌŽTßvkÑWè묋’œ¤¥£¯ñÍö¶ÈÓß0wŒ†‚OQ@'T¼WÎìãÜÑȾÛãß÷ùçÝÌÚëõèô÷C,×–¬¤²¬[4Tƒ ‹‘”ž•‰ŽŒ\5Ñœp")öÑæÔÈÁÁÜÜÏ¿ÇÒè誠Îêã×Ý»¬À½„mœÕ¿ˆ‰•œÅÆÇ»Ôâ¸ÏàêëìèÛæ íR¾t’þ:¨¤‡¨Y;. A‰f*àÛd1±V4+-0“÷x?t«&‚Ïé2TX5¸ÂãÎËÌî ã»fC,0/<    -ü&*1PÃ(âýâ˼–2¾–×w*DQ4ȸ¬ªÀ®²­Ý‡ŒtôùhÇ(%!ï–ul:$Rìw«Ê̼¼¯Ó/êø&êØö çõéî% ôõúð¤õ îâòàÙÐ×ݽµ¶ÏÜƼÏÙÔ¶¦€::>  ùôîëÖ×ÂÀÃÀ«¯°Êûâħ›¼ÕÙ®¾×؃®Ôºˆ„†»Ñ¸ºÑɾÔãêéðúò×ÖÖ•½}õÉøRvœž)dM2P0 'Gab=ýÝ×#ÍQ1IŠJ9<Oª"âåp7Í4x–½È¾µ:gm÷3Q¤1yS´…)4D1&êî&3Ei±4±àÔàµo¬Ž ù£/îÚȵ»ËµÇõu\;Ó%3~æ=ekŒ€PßœSÔÃÌJjƒ¡»ð-8ûõôÛ˾õ#ëϽˆfI¡ka_CEnxY`mŒ–h4IF2$4:-3* ÿûñ$5vzF," ÿðÚÛÁºÆÌÔüÌ¿ª°ÇËšž¿ÃÓ»´ÞÖÈÌ·ª¬ÆÞÔ¹²Òû -íÝãñÒœ}WèÙ„KT¦¹Øí+b9 ?kfT7çû7ÝŽk[™XOKf“¾â4Ë„&zªÍÝéÊ®’-‡¼EUÆ RÐ’ô‘”d”'Z]Hýñô>þ9>]ÂPÝ É·±{B1÷¬”ËYuP»Z%öû˜‰`Ô60kÔ3€š’¨¦bŽÐ´³Äék¤â1]M^–¨¶×ÚÄ×ÑÙ-:É‹LË—Q, ÿëö$ *8;òý÷÷÷þ*×î'Wer~cOC=,7JBä  ñãùѨÉÌÛðÄ™ª·ÂÀÊäêÔÔÜÖ¹¿ËÄ£œ™Æ/6üËÚ¹GõP[E*ø¨¢öÂFÊÄâã 8\; X”sX?ïëRíúI§dE9L½6ÈC´m««§Uþª1¸ˆÁ-~»,26ÙÓfbqc<ÿòò6><) -p¢æXö0"Éšfê÷ì7æŒû›9ÎC¶…Í“w -HB?XËIj…¡¿ÉÛâÆ„Fôoщ¤ÍàÍ×GWcYu Íï3Vffr‰›Nü£xT%ØËþ:@ ì!=+ %"ýÓͽÜÿÑÍɶ¾ò%DÖã<_yx_6EYR:2LeSLOHMC+2&赉¦áô -ýÁŽ¤°½·ÈäõÙµËÄÍÀá¿¢™¡¦Éÿ-Q#ÃTÀ|K½Ì¸WóLcíÇÇí;n^4AR‰­†UÞÛÕÇÒX¶G½c3"j³îè0¶òèÖѱwßÇÂæTÅô$„i]üVžè{Bô!þöô&/)#&æþôú=­*õ³`Õ­û:“»:ƒ›„LðkÃŒìf„lrÆiÈÉÒöûÝÙܺ5¿ËÑòðçíýöíô"ExtJ&7FRLOC5ïãÏÓ<]HDQ02<6 ðßïíÐáéÂâù +00/(3OYT\CY~T67ajf^B*4§Ó ,ï̸ÁÉÄÁ¶ÆÐÓ«ÄâÏÎÕ¿»ÂÖÑù )ÿUa¾ŒÊMKICÓdUV† Õõ#škcŽ­ÝÞª7Ûº¾º­»^8½p@s<ØÊiËlNû òû0U¾ÁÁÚ 6FLMJD7òšëùm"í/!!73>N78M£ø5\À‡Šè‹Kò`¸Ûßâا:Ú”ÒEtsYq¯(Å#(%üÖÒ¸·ÅÀw –=!þäÜê "0ýú÷ðè÷ôÉè(ìÁ×ôéï -4MJU?*izgLE=@ þàôEABEH' MC9Kf†(ViMGvŽhCMY9÷æ00ÚéþâÜú Ö¾½ÂÙãÖÔßØáä#;I!³U¥—Ô¡£xÙÏVÌyS,ÉW 0o´°š¸ãÔGöæ¹±ÀÝô±xSUO´uéÑ¿C|CDg›Á×åùçÀ—_éÁ¡ªÏÿC¯7²ä°ÞÛ&—IK@ÿü:J8Ü>¤“L3‹ë8ö<À˜¦ âŸ$‘ÓØÊÅÚÔsù.i2rí}Lé087²½¸ÄæÜrèi7 ôìäî $>#éïïÝêþ( ý ÷ 3F^ff`ln~¢žˆi)9b?<D&#2lVEHO4*M%DiOñZRý1ilV:\OI>1×Æ?÷¿Ö$K-ôäóõëÛùðÝÊÊW{n CΤºÛJ,EþWZóV£Y[1æ¶ÃÕÏÈÞ AB[#ÝÏÊ®“¨Æļ£•ž¨ü¤"M«õJç %ÏiãYç•E÷±tw—ÍK ø¸/ q˜ÕAÚb2;Ž ÇþV†t:lô?Û:̽ðt'Á8¬ž¥¶Ä¡8åÞM„ä5éŽ è"ÝÇÊÀÈÀ½»ÀÚóR •Ž·ÚÐÓæ(üÿòðàñ[•…R/'!Cmp˜®‹š¼ÑÓ·lebbƒ‹hx|N65Vg[VZPSTE2üä 0C05M'øø#-"=ds^\b8óÈÿD1ö$dT3.óîìëíîYm{9 :óќƊ­Òu›“dâ%™\j˜S ãì*ew„†Q×)ÆÚÄrTe¤æ ãñþR¬ŒäT¬îÙ:Ä D˜ý’rS>"%:oúßù¹  ‘žv¼’¡j^|Ûd¬€6d -M³0úë ¶}TpyŒ©³¥YøÞ&z2QEJþÀ÷ÛËãõÞ·©¾ÖÒ­Y½4èÐúJ~˜µÅò08ÍŠ³ýmn/Å’i_m{b‚ྉ©ï 㸗m‡„Œ’Z;^eji\aPpƒ_KÖÛ#'IQ?$HgtXY`VH:Br]:DmX?8ISTD.è24!*H«™Œ÷¼‡ìÖ+cÎÇ{Dá‘ʼZ ðïB—¼Ê¾šyA¿Bô¾r;F‡QPw¶ -wžûT­ïýÀWµïe¹V  O•èf%.Àê›ÝÔáÁ±~†ô33#ö(›ö½^„ UÖÕÖ!è·2_gvžÇŶ¬9XÁ „„sÞààèòË«Ä×âéà´‰0W(ø'f¯öý'v…GSuÁÿô ¤h„~`Ñ»¸ÙßÍš˜—‘›ª­•lƒ‘ƒKMZ\f„ƒrPøè,1HddC$þ 6wœmH76^Š›odXPZ8)_rJEVA.6Vpm>G±Ú:35»Á?PlÖÕ©±¼‚£Ï”X ÔÆäM®Øéظœ³ú6°h=b½” cÀ>ÐM›°ÅÒÑIAóo‡ªê[øèéQ¡ê.ƒöŸ •ÈI7k¡Éãî2+ؼÔ/®ªX˜ ºì‘†É+Ë%Mcu”ºËг‹c_ˆºƒj›ØùûíÕÄÊðùã¾ÈÓ’æËšÓ§ b^Žå<=[§áøÝÿ…@æ•9vDµ«¡Ï´iu¤ÒúýãçüÆ¢› ¥§­Æܹ¡£gTXXHb…`ÿ*N[CN@<6) èüAxv[WA9kgO4C:O0 DaoUDSIU`Z|“\þ)xÆÚ¬@Ûû³ÔÝäñÖ:4M´syµËÉô]ÊôΤ ºÁF€ÊfVÖ·•9ÌA®÷áÚé%ER1 ¨Y2€ÍÓãúù „âDcf™ÝÂ#­¤–·z—ˆ‡wjgE­ž¶ò¡ìd¦^oÒ~Mæ)A]kk_l™ªšˆ—¥‡9j–Ï¿«þçïÛ²»ÇÅÈÑ艘 ú”uls‰£Î$š+=D¶Z¼EÙ%!ÑVóÔéúÉ}i‰ÊàïõÎÖƶɻ¶¬¡¡¾Ë½Ê´‘rTDSKN-"/@I0$EZ;5BGbJ 0ABG Yp_BE72XU<($>@UvU/.EaCCtŸQöí;¤Å3$„P‹¨ Û -ñåØ}×Ûðwx¬£˜ÓBà&í—Q14ŽåŒÂí9Æ7¤é,!ïÜäö*%!¶uìØçìü÷ -:–õ.;ô«§ÑÌnPLFJÈË»Œms‡¯™“¥¶ÎÌÿXK³E©;ah^L6-Ayƒst_4Ø¡žîˆyóþää˪šÀÃÌèÔVvš«$À³²ÀÃÑö\¨ºØ8‘ã<aB öÓŸ¨Öྡ•ž«œ¨­¬ ¯¾³ÃÏ·»ÁÏÖÕœ†·´qR`B&.F<üç'@7F`?1BHFNFe>,&#Oj]afgfc{tVC8I="Dw‰5á½ÈøLŽ9Lzø½)XöççÉÉÒk›œÌ€|šÒaü^6¨q@a0¸¼~Þ…Äÿÿ×Ôñõþ÷ìw#ÃøløõæéäÿPÛ Øk>HYRXB %CSAùE<ÉϤžç‹ ” CÝ¥YÐ'PdcU9)+Sª°Q1>( ÷æèK3ÀØϹ¶¿Á½ÉâÙ«7pÓ’PØ…P7+5lÚ~ßA³ ä°¥®·§•«ËÒÕÖÌ¥©¯£™—¤’Ž|¤ÂÐÎÃÃÕµ‰³´‘mK9+;B0ë¼ÌÌó$=>5BSN//=\jL31D+"6‹„zšÃݯÔÖ¡lbO:40Ra+îºÆâ W6.~O±ÝŸÏí̼ÁÝÊ"¬žÙ0gì°=9/¦Ÿ¡ù ‰¨ìë÷ÛËß  ïÿâ: ²Ú›p*ò×¹ÁÙö,AZŒ£g4',?DC.õø3\4  öù½­!ÿ<pw23¬ƒrFK%#þ‡<0h"Ty]%í²½G¦ÏãÐÅÏdzÅÖР1‘ú¢6Ò;q‚Î,˜ï/eç'Þµ¤•–£’~¢¼ÖõÛ³¨¡²º®ŽfH[|’”—‘››{Ž¿º€r­”hJ^b5ö·—˜Ü22%)!,)=#!{Å¿Ç)i†qRli;é¥u;0a_)ðßü9 -ýd!W7ýƒîäÖ¾ÁÒÞ• |:CƒŸØyh^Î}»‡´ ÕßëæÏÐÿõÞøƈ+ ­™Jcc1ýàèëð989P?.1 .2.ö÷÷2CA6( ìf7Õµ) 9y38³‚~4–Dl5IH^èÇþi@… ‰SÙyŒ´ÉßîéÕѾ¨°­pú1O²\gÒ@F·‡É?§ÙßèGÏý½£·¤{cŒ”‚“ž«¬ªž’uœ‰bJ84Fhyw|˜“‹ ¬œš¨Ž_\x~8éœt}›ÓýëëýßÓïà¿ÎŸ¤û@QIiÅýqÉÛëÚÓÇÈ¢^І>,XjOBC"îÏáÕGU–AYŽ$ÑïæÏÁàþÊ#õñX³ð÷ß%nÕÜ#ÈÈÖŸéã¥j^WLIIjm4Ö¸<,SZ>(9A-'FXT?,50A6 -ôý /@=W}h÷ ß"ç2ŽnÞ\>€#ÜUéU•‡c…ŸÛd§²ô‡•pF3A·ûG‰¤°ÍÛÕǶÚÿâ‹þbGZ‘/IJ2V­ÜËß#u¦‘u‚•y]mœ§{cqiv’‘d^hgVC924N{sIy¢˜Šz•Ã¡|fnšx&麔‘¶¹ËÄ»ÐÊÃij¥©·½õ/&Ggª&IU‘áÜØîäüе»¹\ -¥“Z8GiSßÏæâ½TpàéSláîáâóñCø¯íÁ™ëÒºÕ‚5íçO ˆNÇBüć½&Ö‰\:S`]V[c^>)9ISM'?N7û -)$7FYŸ\ ú†¬Š`HÆv^«5ÉNÐ?¬w¼=)_ÅTÓbp‚–G+GœèN„Ÿª³¿Î¸•¨Öýå}¢¡·LZ€Ît!\·¶ÉÊÔô;^z‡xaaƒptx;FyŠƒxkxaDjlQ>BH-CuV -,{–ˆ–¯œ„¡¢xK#ܶ¤›“—ºØÍ˸­»½³Û8ci‘Ô\§xœáÕ·¼©Öô¹¸ùü×½sÙ™YHGc`üP( ·Da‡ xÿÑøüþßí½ýø5ôÒÙÀÖïé̵›«ÐKöÉK.„á<ÿ36’fægïZ=F`gfeaU5:OJ=#,9GC8)&A?CHe{†l+÷òð -J}y_†uå4šë?a\à1 - -#T¿Ü‚†‹T!mÑ(r¤°´­­¬©:æ¯Ç ÛøQ1X‹ÈAé[Nžƒ¾Z€Žƒujs’ŒqO/U¢Ÿ|i]c_3B^bUF>=77:&my_xŠ‘so—–¦„iT#îà“žÎÍÇßÓÉÑÓ¶Ón ‚¦’Ǽ¸ ¬Äñ¿¹âïêÛÅ›<ÒqM`dD*2/j0{e%\¡xÙ.â¿ €'®B -éŠH8† h”œƒ……€w–÷ŽëâeèÒ¯½B=’x%§C =UtˆvSHdkV20PRQN82).FXS[m‰föù¡¦ÏúÙµùЩ*ftix\<_ɼo,)J›Ê€‚sûÄž!‚“±¢ŽŠp{ÓQD]ÿƒ:Ls|}¿dú©pvˆ¥èf¡•„‹Œœ©Œdcv†€L:XYU6#7A0.06 '(!K¡CT‡rU…¢Šš“‰nR!Û±µÒ´»ÍÓµÞèò*`êžÊ§¸»¨•°¾Æ÷Ûƽ¿×ßÙðæ¨+¢jo\?LM&Ý¿Å\ ,æfÌÓÔÒ¾ªŸg"Ú{†Kž€pVJx¢’l9,X–ÅÓøùÜÙ*¨Yqe_î.!3Mƒ­¬ {d_< /#+RC#&&B`TMwjSC)"õ P™ÀÕD¥ÖâÍ¥yMèî[ã ¨¾Òá'çÀ7å/ÔªAnoQ:°é‚€±›ziQU]rzn`kêXe[~„edÄ8tfGi–Œlls{z(æ]F%6571+1@5/=:92Otx]\lqt”„ojdv€ˆ}8ãÀÀ¦¬äÍš¿Ù 6[ЅܾÃÀ ¶ÇÎØÌÈ´ÆÁ¾ÈÆÝ÷﵊¦p@2R\. :ñáx>7^V£ràæõ€W›ô1¬qI9KÎŽ3?N_ðL¦Õ<`LÊ+T&6FNo‰µé·E÷V50=$!'<L`aq‚Y %/úЭÍ-¡¶^{;ÍîùöÓ˜Q6VµÌª–­"ïš;PôÇŠï9 ¬ÐK#:”¿l 1d„o.ÇÒ;U¾:e,YYJg—sEs†~|]0%(;-9?UL.a‚[1)2TT[n‰ˆ…˜‘xˆ{n{’…aE%ð¼‡ß⪠±à']²T±««µ¬±õôÖÈ­¬«§¢•—·­ÀåàÄÁˆøz43XZ7E.(#‚/&0ìI•gâúèÞÚº)}uhцW.6ˆ±™C"G]ƒÊü'ìسý@w7Ûn…3.;VUmÑ7Kƒ6,N[<=[H5BMo€cq‡^óî)àÝÞ÷hàäéÍø¶óüüþùìµD6ÿÒd¿¾}OÊyâ‚ÍWô^Æ'hO°ôq)ûæfìû<[JÚI?Jb•¬Ür!XShs„bY[mqxb?:9-"#+)FJVKE‹™mZF=9F3K}zƒ©µ¤‘”³Ò³žm=7õŒ{Ã俦°øE‰üwš•ºÈÌöÑ´½ØÖŸŽŒ–§®ÅäÜÁÈÌb¶B7Sd3.2s\š9T/†´yà üÔÖÒÒ§ÓúœR#+m¯¨qPbmn’ì^¦õö˜hñL{Oyq/+!4FˆÿWhDÙLMV=+DYaK@U^juZôç÷4\!ì÷BV¦(`wj~(ýÜâÛ¹V;¹>wrpÌ—Î$©fR}Ð;‘×Z‚VÐL槻ÐÔÁ×=´a¾K$O†àJ›Ãî˜8LGb{zmeS\w}zzv\/"" -)HUih€˜‡aWbd?>9IYb‹ÁËÅËÒãݘ‚BÑ–±ËÒ¸°°¾Ü#]£4“´ºæáåèØƧ²ÓåÇ£«¼º—¸ÑÏÑÕ©q4·ZV],;'‹°ånÿcÜåû’½ÊÉÌäôþŠJäšK "бlqq}–Ú[îî‚Í8cj]p& +^ LW'¿NHM'$:%/6Dk`4úçð2v] MZxâEÕÙ3 λÉÚ°S,ê‘·,`¯,Å~|‰Œ¸ô0JÄý¯¢¸ÉÍÓÏè’œìì< -#OˆÍ2k¾ÎISZy˜wop˜|pzQ$ìÎç)Uu‡¢–„uf_WH=f„nVjºØåýöþÍ•™©Š+غ§©ÇÏÜþ -oæL›ÉÓÝÔÄ®ªµÀÏßа›¦¹±¨™©ÏÔÛij {âve?þ%¶Øî‚_NaÞ{Bó‚á)ŠËíëAÒ§jUŽÐà­b<DyÕ@»ýÏrߘû?qD›/'&XŸödyB&ûæåñïÿ8p|Q!ÿú#ˆ´BêôgÓ¼/"ôàÓËÙÓ„¡¤×èÈÖ~|¯`Nk‹¡à×Æßë H]ù¨¬¹ÈæåËëÆ!ˆ ñ;a¤r´¸W“®µ®¬“€€£¨“‹Šy_8áÝõH]d}š—‚t{pbYEk•nEL¬Þò4C/÷Ö™V-þÚºÀèù$Š{É׸›Ÿ‘‡žÑåÌÓÍÌÚÒϤ £ž»ØÞøä½vÓkF%%lò£Ð#ì -¾€÷Uœ'½Ô½P}vŒÜÅæ6TÀ[.E“à^¼¾p>þÑÙ?™-y€ñ¼0ý9iÆhŸHÇJñüòáú)e{6#}Ý ìW)µÉé\vôÑÐÞÓ™Sá¨Âô ,4ªŸŠ 8So‘ÑæÑÚà×ò%󩜤£¬º·Ñ\h¾ùšüéþ 5qì>cÊ£R©¨¯¯‘”ŽyjŠu0÷ß -M…WCNƒ•uFHo}‰yegG>\¡Ý P…–{ ½W!úÝÓÝÍº× (f½ áðΰ¯„šÒ -óÌÍ¿Âöóí“‚©ù à¢~˜O4& aªHIÍÚÁop(gˆePThtdvTáH˜ÿí7‡×ÓQºPZ–äu¿Á¤gÑÈXác  »;%þÿ=W´uùN~(%þ!4Wi7&|Í4ÇlEòMMæàúðβ»³‘2çÐòü)T†|;Öó¾.Pg€œ¸®ËÝÙÍâî¹zt”™€›ô;Ãàé<bœ×«¬=Wk–»«ª£ˆ‹tqypT(ýH‡Œf2:p‡qXFK]l—Á‹X]~‰›Ý+fš½‡áÆ€`CÔÇÀ»Àæ Q–¿.œÔüùÒ»Èóܼ±±¬›ºÕݤ–©ìÛºÏijWÅbCC*XŸº_Ò<ã¦y%„l>K7²0Þ£aO1åæxe–«º¿N…Ó‹¡ £ÊÁ»—M÷ÐùS°+Ç0(&)2’u‡ÅßàA"*84PdP:JZ;&EÍÜßÊ£vF3%.Y-³»÷æÄ©œ¦ŒÏÞ4lµÐÔ‡ A1^ú 3)#;g“¤ª¼Ñã¿‹glvwveQ8&ûëìäã=|µß ï'L–àóÙ≑“{Z941X^M\^N0=‚´†[dfcr•¢Œxjyž¯m…¥ÀÈu?!û¨cÔ¢ªßðÊÕkŽ±îðôãÈÒòÞ£’š£´¥µÆ±˜­Áûà­™ÇÛÊ„õ~iiOzÙ á#É—§\ôÛ%c³äƒ< , G&ÉÝÏ¿±ÞÊ!J»Å:¦À±®ŽOöèÖâÈ­Jeò ùøj’XXN!4W¼¯„cP]b^br‚—†zwiA4B6&9îSŽÛÜЬ’x1´m‘!s˜ÀèäÉvãδÿ!Bgƒ¹Ù !ÁxYc†»Æ SϽ¼ÉÔ9¯#h¦ö±.ˆÜóõîÖœ¦¨‡U@FL°Ÿ^D>M†É¿sfy~s‘bNh„ŒŸ®øW“¤¸ßéº}ZNÐe(ï¹Ðöà³âA‚GåÖªÊÕÕÐ˧­¼ÊÌÍÝÛßÏØËØÒ½®²ßÚ©Ž‰ƒ’p¡ÐÕ)1½­³ò‹Èûë_¼<¹~BþÝë}úä—:C¢ÁM˜]–šzuM3+òÎ*:ÓÂæäúáæÿp¾<«¡.PMŸÑĬ›’ƒtUK96</8[D ˜Ñ¥Ùß½<´ìåÆV¡¸ÉÈÍÄht-o7 0IJO]s“¾î2ªŸ}€¶ 4±V"ùßëcÂA Æÿ%Í\–ËñëÏÆƳ½º‘f|œ¨µŽhVx±Ô«bDPDWytO^©«£Ã As†·î­ƒóv$÷÷øìr µ¥Óæ㶜ª¹¶ÉáÑÎñø¬“«ªš¢ÎØïÞ»R¢rV<K6i…Bh“÷€?ãOAæµ+Îîõ|S±ö½p„ÆÉjÞS7Z|^A*÷èãÚÄÖ‰ÕÈŠd@þþèËÖS€ø½÷PL $U¼ÓèïÆ…s^8Üê$5,ýR$.žy2³ÝÏv4ªÒ×ÆÅѲú»å®ˆ\dpz‹‘wšWC6cÏ‘˜¹øLcæ^H\U=]·9Œ§®â%ÎT–ÁïÞÕèúÓáÏ©‰©×¾{Zƒ”zYw ¬w8/(Mv‡v“Édz»&|‡¼÷%M=Ü›†!!ð•h÷ò¾¾´ÐÙ³›œ±¼ÙéǪÏæÄ­µ¨žš¿äõ#ú9ƒN"^/´Õô Yf‘ëu¦NèÌ¡shüI'ž G  üóÍ|ïB34Õ¾‘zœ¤šöDÓ)Ñ ÜÇÄïA9½íRx[ü+g¬S-ǘ‚p_-ýóé  Üù ûáïwPºÊ‘ÈÐ#ø‚ųØæèÂÀ¸OJ€\.½†Š“’j2D+yec™}€›Ô*_ïVTuvl|ŠÞ'3^Ÿñ‘,“å öáØØË­˜žŸ‰Y_l[S™\\z^Sjqo‹µ¯½ÎìY™ž¿äþº^e …3æÎþ*Jð^­>²ÕÛÏ¡±Ã¨¥ÏðÚ²¥­¬´ÑÁŠÑÚãöÉf? ÷äàòîǵDF{}„èy¦ÂÓåþä£> åÒ…BCG-ýÄá-ÚàùîÙ» riTKt4 ãÔ°MeðÛÕöAš½ -h`-Z ;¯sÎÒË°uô÷ôõËßðñÝ×:ÇC‰ÁË‘õ[/5{l¹§ãæãÎÉӪܹ¦°œ†pI©—´ÙHCQc¬#¼Z\nr}v_~°ì9}Ên+¤ SMF8G ÙâÕ£‚Ÿ}]QOVu¢†y~zš¡ŽƒY\˜Æ¶Çsqi¦Õýþå¿Ž\<ÊwKâÝ"=; ÿ;€³t¯Î¹¨°¼¶Ãû)íÇÁÓ¹™”ÍýÝ¿ÂïâàØÞáßr;!6ÿù[†lÊC<”-™37A•Óà¶o4‘ü¼5y€d=$ë“éQëÇÖ˳ų—wC·£<§?â5)Ñ:i(b:?1DbÔ|û”$ôµ7úóø°³Îàäø%rÎîéѬv9<gpØ;ÅÐÖßа“àê{OªŠp=ü m½Ï\8<0R—ňkddrmLTlžùU¾zC³ TŽž¨ŽEõÔo¢¿špkpcu“žzwd„¢¢vo¦ÂÖÔÝ)_Wa¨ö+)öÏ®[ú‡n>ÿÿßd Þ6žÈ¾¶ÆÔÉÜ秲æᶙ­ööäßòåÝÒâãiÆi::PóIsØvºQ×<o}CǬ^M+17ÈR‡ ŠÐÛ¶r2Ë%vóÎÍÁ»¼½°J)")€˜.E-rø ü±Èæ5>V“è_ôL p(ü§Hùôù¥¿ÀÅÍÝ-´‡T5  $'<itóÞ¯”wæ¸äÊ©wZ]\TA5;N]7 Te57_ —mUt{b1=W XW±r3¥ía¾ã -Þt¬¬ÒÉšŠ˜—€‚­ª­¤–¤§³½®{ŒÃÝìü.LCDã Íg.Çx,þñ$ÈÎ$n¼ŸÐÔÆÓåäÿñÒÍòëͲ°ÑÑÉÎÊâÖïÒ¼©b®O2G:ÖåÒöåú¦ÐnE¥±‡è £ÜBTiÅÔ{­TÄæþÖ».‰«ý¯¢¸ÃÅÆƤk44)?ÞdêM݆àÍòü,›[?†öGyµ°Ñkóï“UÚ,"  »Ëı¸ÉØõg¾–-úÝïèßDmտ඗}gwÈs]F5>`iZ=EMP*F¢Êžfu¡©Ž[]pxZU\‘óY÷}äT˜Ê -¿4È®¼Íβ¨¿«µãéØžÌÐÙÓ­¶ö!*Jkªñðô³‡†`Þ\îäùðØÑã*‡ßdÍáøúëÛÉæÙÑϽƹÌȲǾ»ÝÝ–v+–KESDiµ6Õ(¤±8=u°Y¹%£·¥ßd¤ÎúäвvØôª’­ÐßÚÌœT6øó)ó?ýÇ{íÝîT£üØ6Üï F“¼m&š/Šs-äˆL6Klif®¥µÌêýûPÉåDûåâþ籯y¼×CT7Ù?ý°oMG<=Rg_;7L\X`þP>×¢ ”‘‰‘€fIVŸðþ[òH¼&dƒ Þˈ೰È̽¤—½ãöôØÕТ ¶ÄÖë  ,\c—ÑĸhMbLõr,óËçæëæäÔÍç-Òu/#ëïõØÐɼ¨˜´ÐêÞÛ泞ÒôÙ§_ët:Sti°&·¬;ódÛðå°ÁWE Y´apÚ6~ ÓìÎ~ÄÞ -·»¹ºÄµ•^<ûîON=Zfo% >g‰iéðI’Š%÷‰Uf2çs.Iu•Žz¬¥Ãßü>gfxæûmâæá×Ä›“Ù´¦2sƒ!• ¿ŒtU6>^djoG4DXVl½NÈ´1Û´¥ã…Ìp¼[AdÑ8ºŠN¦ùW}‘½ê¨EìßÝÍ¢”ÈñúäèõßÊÒìûþ;/ )#F|•£¨¼‘PL~ “Nó¢»ÒÜÆÍð Câ$¸‰IÛÜäõéÔ®œŸÇØÜÜïäÄ«½Óá´wL>jš0=\IȽ¤)Y!ü–TÚÛÜc´J -n¨ëP‘¹íûÊh©èHÉž”kO3õˆY~+ ö 4P5 -"YŠFþsº # ¶R&GŠ£”«Ÿ¦¼ÓõS¶ç9|ÜǪ£ »ÑöRØ\Š¢Gç’V=30FZkeQ;98BRš'ŒmǦ§*&ª ìYGƒóYjeЋ÷BžÜM¢Ó*Þ‘\ûò×Íæ+0ÍÚú5?JL$Tš~H .|žˆUZ{nesŽ˜<ž=ØÛÔÆÂåY„o†àVa)ãÙìóäÑ»Ÿž¼Ë»»ÍßÚÒßÚʧy, 3rj˜oÔõwþéTb) Lß—ËÍCTUÜ• N‰çø©&ûÏ6Ѭ™‚ŒuW&õøêâr¶¯m ')2gj6u©ò ©S'L„˜›ñ­¸ÀÇë-;:éf%ãÊÑð -:|Ê''&ÈtUY<,SWT>1+8•ÌĤn?7¡”?ÌÐC;z苳¦Þˆè-ŒÑ4’®é÷Þß¼Lõð)&áÜ&XLXrŒpSn¡³•'åé QŽŸt&D>][NeSâc5$ý˹Ðé÷(pŠgtˉ0odȸ¼ÇÅËÇ»ÁÖèñïøõåÈ¥C°6õhäÒé§Óc-'×BPï©NcìÓû*]Þwö$å̼…#¯dX-Ûºôª° n8 ÷çøèòH]) - -þòó/O1%Hr¢×&:ÅN#4`|¿YòâÅÛw¯ÊšQ>>äù(B)b¨èéáÌÒÙѤ²¸sðý8WRz†hK$@jšC*gÑ/çm*?_¨I·¿£ó3×.[W€&5õŽ4 *1 þ @mtuwšÕÿâßÁ‘g&ýM‚h]a. "Oopm[ ”@ á´»ËËÙö0…‹WGÝžƒ· ¯“ÙàÖüðýôîù ú½eÁJ ûV«G@_Ò©Ö–9­·£î•”>éÕÚãìþXó™°fÔGçÊì9»&ÜÎàèà¤S.þ êäòúú'4"ëÛê -.:!&C^‡‰¯-QáZ7B{ÏLþ÷ðü#Øä5RYQP7 òWsAR”ÕÙ¸˜•¬Áä®ô±V'2Ig³d·kgm…c$:l„]:,Ge•{¤šýI‘õO[Q}ú9)ä‘c7;6,%*1_yar‡“¿A|fö“clzfOx|X5G3&,Wm‚nSG q& 滯¯Ãâ쎼¤¡Àþ ºin¢­®ÿÿðìÙËÍ´w‰ßUqU½ÜCùúR -«à¦HðGv(ëÆÀÐÙâ =¿Q_öOèϦÃùE±Ð ®ÊÓÑÄŸ`,öí  +21ÖÜäü%8W|œ Ý@Séq„ÕSøtÑ.ÙÄá',&Q]H:x—cSj—§¤‘— ”~i¥Ý½‡tŸ«9tà«wV  8UZZP02DU› q²B­„÷Fgct˜Æ,'¶‡ˆgZPPYj[]:Ck”¾wƒ!’PPns[PWG! 3LZZ{¦qHãT/;À±ÀÈÛî E‚¾çÜÌâ ãÙþ-JW_`dt‰znU#Óy%æÍs…Xí~,ArËVüdçŠ7äôôéáæñÞù0´3,¶Añçн°Í%ož› ‡{”—’f4"þ % %'ÿõèõ(<|´³ž× ÔÌÈÖ;ЀÊÚ äÖáòì:I;*Bk› cO{³ÎÐίš–€`APƒ¬²’°åkóÙ'À’V"PYZN$+IBA-‰àvaÐM­¸£˜”£1Ë´®“mS\qeW,1jƒÇ%lHã|?  )&8,0%c°øÒOÃ[PjEñËäâÏðöáä"•ÉÝ˲•–¸Þñâ½ÄÖ×ÒÀŇ$ÍØï'r|VÿK _’Íý þÈA§;+#ðÒÊ*ýöïê BÄ"öhêÔü &1Na…™ŽU+3Y•; ù÷ü'1(  'GNOHJ˜º¤šµââå9ÓoÔ×ËÖÐÒÐØïöøï -.=9Wer‚{Me®å öɵžnMPRb‡ ¢uh—%ˆy ¼r)ôó%;]`0'MYmáOž)ÈWg´iîÖŽgVjÃ$+Ûž~wmD<X7(#-7xþZNžèçüõü@<û\ (—U_pf!ÚÛÏäêÚÂ±È Hmƒ›—šŸ˜~jh|jOJq^ÅË Iyk(ÇfçÖ8W^:»0É_ùÖÈß( ôßÕû7j¾ã *ý,/DPB<J‚£q#  HzqGÜÑéçÚøû"9H5ø(+9v”‚ytr|{›ÁÊá ?¼uêÿïÂÛزŠ~°ãò:<V~”|K.:_”Á±Ö'Õ¼˜‰}†‡‰Žx;E¥øþÏD *(?FEYhgn¬0|Ï&TBkñˆ˜„kb‰²Òê¹v`X.225 -rø"#ãg øÚÚï& )*T–Ë»îu]ñÎ=εÈÉ¿ÂÅÆÁ½Úõ$$*BEE' .6(êí;}¢²‚­Œ›çPJüì%F+  úÛÐä ØÄÄÛFTuˆHòü - +D07^‡8ùû7\a\,áÝáé 23/;=÷ÿ0ŒÝôǧpY{¬ÏÏö&:¢Eã - öæ·˜…±Ûñ5Y[|­•FüõG‰£jXžÉÍ®­ÂÄ¿µ›~|K þ÷Ô÷}àÆuWiwlE%9„ºÊÀ¸ç]†é®<f`=[·)Wz‰‘œá ç¼›Y1A:ý1òoØ -¶XåÓíÿÿõ7HUhŽ™°‚½¸–Á)(ËàçÏÆÔÓ¸ÅÏÀÆÆ«¶ÕâîùÑÌâØÏƾÐHx¢ÇØ¿ZB‘¿úá>DR™(*02*äà÷ ÷ÅÁÀî"+Ýú3#.+NuKúòþ .^lQ,ø HL,8?KB+(€ó î»™zk›Üú "Q­<ÆüMU$áÊÑâðTVceSæâõZwN4B~¬½ÔÔ×Õ¸€d€§‚G!öÿ[¿­zw ¾¸„F+6yìLsd5T•Í`ªÎ–IZ‹¾î*FwªÃ·“{WIO5 ,Üù2žÍÆ’<羿ýF<ET77Dcƒ[ìÏëO{ë5ùïàæ¼·ØßÏÖŤ¯âïÜÕ´š©ÍãÚÂÐHd\„ÊÒ–SHž8id',¿µ5þ"4SNãç#N6ôÕÖæò  ýA?0CZ:9VQ# -  FCG Dn}BJue1!$,’øíµ“ ê5T]b™¬rˆv ÓÎÕ`‘‹g=õî%4"%FmŽ¸¼ÒáÃgP ðÿ¡AûñC‰˜„±áëÓ¨‰kP!¹ã¥»·œÞe¹Jý–t…§³Ø7‘¬žpbD$<S+$'ÖµÉó)7&õ×ÎÝD?+7ÿ ->0ëÍé?¤"pØA/$ïÌÖÑëïçÙ´¡§¶Þíìð¼¾ïöê%]JMGW{C*qºèªþ·?môóFjKôß%ˆ³±v9  -3Vjvv… }8&;„u8'(%   (úý &KibZ0)Z}wK5DI,iä -нØ+„Š~ ›' \ No newline at end of file diff --git a/build/lib/WORC/exampledata/elastix/img1/slice091.mhd b/build/lib/WORC/exampledata/elastix/img1/slice091.mhd deleted file mode 100644 index 1e68f3e0..00000000 --- a/build/lib/WORC/exampledata/elastix/img1/slice091.mhd +++ /dev/null @@ -1,13 +0,0 @@ -ObjectType = Image -NDims = 2 -BinaryData = True -BinaryDataByteOrderMSB = False -CompressedData = False -TransformMatrix = 1 0 0 1 -Offset = -67.6484 -265.368 -CenterOfRotation = 0 0 -ElementSpacing = 0.703125 0.703125 -DimSize = 256 256 -AnatomicalOrientation = ?? -ElementType = MET_SHORT -ElementDataFile = slice091.raw diff --git a/build/lib/WORC/exampledata/elastix/img1/slice091.raw b/build/lib/WORC/exampledata/elastix/img1/slice091.raw deleted file mode 100644 index 66907f6a..00000000 --- a/build/lib/WORC/exampledata/elastix/img1/slice091.raw +++ /dev/null @@ -1,190 +0,0 @@ -m}xgt„„yzŒŸ££’•Ž”’„‚œª¥„v«ª­ž†pz”™”—£ŽŠ¡¤Ž‚™žžš~ˆ{|xvix‹£œ¥—‡¤¾²”Œ‘Œ‘”¥£ ˜œž˜™’Š~€“”rs|”—‹‡”’……s–ˆ†‰”“ŽŽ¨Ÿƒ¥¶§°°­©ˆgoxŠ˜„‘›’}vm‡²£ƒ‡‹‡‹…Š•µ¡€Œ¶®š—œ£™˜˜§ “†€’š”–¬²»³µ±¡¥À¸ª²¯œœ’„”Ž—»Ê´¯­Â±¦ªš–žŸŠ`¢¤¥ €wƒŸ¾«€~š†Ž¢¯©Œˆ¡§–’“ ·±–qu—‘t‹|mmltˆr”–”‰z¡›Š‡‚‚™©’pmˆ¥¦­˜|…‘‹Žœª£Ž‘ µµ¥¢¥ ’Ž”‹Š~whk‰¨©žœ—‰™ž¯£¢¡|z‡”Š‰†|†‡}|ˆœ„kƒ˜}ˆ–™› {z‚ƒ”’˜™˜„Š¢œ‘¡Ÿ¥¬°¦˜¤¡‘•’’rZllt‹“‰œœ†vo’»ºŸ——‰—¦•‡„‹›‡ƒ~ƒŸ¨ž– š‰ˆ™£ —ˆœ²µ¼¼­©¯¿°¥¡°–”¢©¢¡•“’š¬ÆÌǽ¯›˜¡•‰‡“‚rj‡¡¶»–‘”³Éµ‰ˆ”˜‰Ž¼Æ‘ŽŸœ ¢•‹†…¢­Ÿrzšš®›¦›Žtel†…‚–œ‘Š‚—®‘x€…’¢ytsz‹¨‘‹vŒ›˜‰ƒƒ–©£‘‰“š••¢£ƒpk€†ŽpxŽ“‚…›©©¢}dfx‡‹‡‚‹zy‡ ™Œ—¯£„”™–˜“‚lky—Ÿ—•‰†Ÿ³¬¦¥ª¡™•™¦¢Šƒ‡„wŽ•ž¤¦Ÿ¸Ç¬˜–«Åꧦ¥ª¿¾¢†‡’š››­½³£¸³©œšŸ«¼¹“‡‘²¼ÈÄ´°¥«Ÿ™¤¥žŠ–­§’”§®¿Óƽ·®••–„‡†’†n‚–›¤ÂÆ©””©Å¶“­ª›žÌÈ‘‹•™³ž€‰Š©´|Ž˜Î¶ ´¦~jx„‚us}‡”ª–v}|~”ž‡x„‹|zž—“™Žƒ‚˜Šƒz‘–’˜™¡˜—”šŸ¨šŒ†€w‚—“‰€„‚’•¤\_hxƒƒ‡—Œ‡ou†œ™£¬´©…p{‚ŠŒŒ‰vo}”¡Ÿ¦¨¬¿­¢ ”“‡™ŽŠzƒ”™ž­°¥µººÃÂŽ»°¬¥¾Á«®¬¤©º ”¢°£¬°¥´À¿Ã¨–ª±­§°›z…ŽŸ´®©±¨’ˆ~z—¯ ž‚‘±°œ¤­­´Ð²˜¥²¦œ–’‡˜Ž~ ¹©©¦§¬¡ŸÀȽ˜šª¨˜¸±”‹œ¬ —‘~vž¹¥‰ˆ Ë¿µ«–€†Œƒ~……ƒvˆ‡–¤§…tvwŒ—‚vŠŒ„pˆŒƒšƒ{{ƒ‹‚‘{s|‡ˆ‚‰†q«±žvgƒw|~‰“‚‡˜wfd}vƒŒ‚‡Œš{›‡¤¦“‚xuƒ–Ÿ˜’‡•…›³¬¸Æ¶³¹­¤›‚ukv‹Œ’Š‚xŠ’–£œ›°¬œ›†x”¯¤«••š£””š›€‡¡¥—›£”…—œ‘~–›Ž•¥†ˆ‰šš—›yxx• ŸŸ‰yˆª™‹‰›¨¯ª”›««§¢©–›‡ª®™©¯ž•–«±³–ˆ™˜š´±†…ŽŒƒ€Š¦¢ŠŒ†Œª †„¤¯­¢‡twŠšŒ”““ˆ–›Œ˜–|…“¡ Œun{ˆƒƒmŽ­£Œ‚‚uwrcy†‡˜ˆs‚’Ž€v}rx{ukv”“‰‹{€x…~‰Œ‹š”ƒw†vx‚Žˆ‹‹‡‡™ª¦£§·¥›¤š”ž™ˆ€„„ƒyvn„ˆˆŠ‡{Œ™‰€}†‰Ÿ–ƒ‡‡x„œ˜¦§‰†’’Œ‡€‹žˆ{¥’”š“‘ˆ}’¡–”¡“‹—’“Ž}ˆt¢–ty›–•…yq{ƒˆ…w‘––£¡œ‘·»™“Ž‘£…ƒ £ƒ}¢ª©…i–|‚¦šyy|Š‘zo–¨£Ÿ¤›…˜Ÿ•~…‡ ¨’}€†‡‹‰„‹’«›“—Š|Š~‘œ¤ŸŠ||”™‰znz‡™²¨‡‡™Ž™œŽyq€Ž“‘„Ž‹›Š„…€†ŒˆŽ¡´«“Ž…‰£ ‘”™–ª¢˜Ž„}u€ƒ•‡…†˜¡ £¤š‰‡}€yz|€Š‰ˆ~‡…ˆš¯šƒ†‚{…”°¡”Žšž¸¾¸™†€”Žy{¦€¯«¦˜š£ž¤ª±š‹‰”œ––”‚wy{­£ˆ‘}Š˜Š—˜™Ž~}‹¤¤¡•’¡Ÿ•‡—´¢“„ƒž¦€mw“š…q}¡¸¥}}‘ŠŒ”’zŒªª„„«¤ž¨¸¿› ¶±š”†ž§ž¤Ÿ‡†’Ÿ„}’ªœŽ~sir}{„—¢™ˆŽ‰ƒ…xwv—§“‹§¯§¹¶¡Š|’š›š•™­®˜‘Ÿ š¢Ÿž®±¬ž«µ¸®¥ª¡¢¢¶²•’‡Š©§—»¾«–‰Žytsywyust„ˆ‚ §µ°¥Ÿ˜˜—‹yŒŸ‘xu}~Š†•’—¦±« ¹¥¨²¾¶¡žš£­£•¦¬“”§³µ ¦©”ž¦Œww›ª£¬œ€w„ž¢¦žŸ¯¦ˆ˜¤¤°­š—°Ÿ—§©˜”Žªªž  §¡„€Ž™’}t‘·¸›™ŸŒ‡•’”£¤ª³ž°¿À²¢¾¤ˆ|—›• ©¥¦®¡˜—–’‘¢¯§Œƒpu„ƒ†– ž”“™¡²¨¶«¢ƒ„˜ª²Æ¿±º¬¯¤’Ž£©£…¤± –˜¡ž›š‚’­¶¤™©¦ž§ž§›‹}r}|q‰Ž‡¤´—‹¦»¾¡‰Š‹wso|” ™‹ŽŽŠ ©¶¬®¨ž”“yrx“…|}†„~›¦Ÿ Ÿ¡©´¦›”š˜—Ÿœ’£°Œ†ˆxzƒx€t|‰ƒŽz|§ž£±‹bu€¡š‘ž²¤’Œ…‡„™¬¨Œ‡”¢‘€’ ••“©¦Ÿ”¡›‚ƒ¨„œ‰‡€«¸¤¦ž„ƒª«™”’‰”ªŸ‰‘—Ž“§±}rš’¡˜¦£–™±¢³¿½½­¦¶®£ £’™™«ÈÓĵÀ²ÃÔÁ³·«–u†›¹Å·®§¥²–ŒŠ¦¡‡‚’£²·¥‘“«©žœ©©›ˆ€„†‚€‰†‚zqilmk€{hu“ˆ‚…ƒ’œ““™‘sˆž§¬±©ž’§¥Š…€‹ž—Œˆ‹Œ{ƒ†‰˜˜—’‹—¨¡£©²¾¯ ¥–…{tˆŠ…„™˜ˆ~‚px”Š€{‡Ž–“¨¡†’¢u^czžŠ’ž¬—•š”yuª´¢†œŒ{v‚Žv’™ˆš‹qˆ –¡Ž„‹Š†“©°°›¤¾À¥…ƒ€’¬•~“ŠŽ›­¤“‹|·®£œ¢¢’—›­§½ÃÁ»­¦°°¢©¬•ˆ™§ÏâÛ²š—¥¥¢••—‘‡wmk»¬˜…‹•ˆ‹{‚¢““•›¬©ŒŽ¤°®¡YPN\j†“Ž|rqvreudYlˆ‹‹€€{†Œœž£™‰’œ©¤”ˆƒ—¡‚te|šµ ˆŠŽš©žŠ…€‹Š’—’‹ œ¥ŸŒ‹–”‰€ˆŸ™‘œ‘“’‚‹‹°¤™’¡ª¡¤—¢ –…nduŒŽ’•™”“–Ÿ™qŸ´Ÿtu‘Š~zclƒ„nz•–žšœ”–˜¤œ¡®”‡˜›’‰¤º«™¦°¤‡€…ƒ¨¯™˜™Œ{›­–—¤›Êº£™œž§œ“œŸ•¦­‘ £–›ŸŸ˜‚ƒ’§Åµ¡””œš˜”†yn~‘„}wv|‡Ÿˆt†”†„€ ³ª¬“‘Œ’”Ÿœž¤›Ÿž™Œ‹Š‹€ˆ†€yˆ™—š˜Ž}‘~olu„‡l^m‡‘Œ”„¥«ˆ…”šœ®­¡ˆ†„€|‚uiu{‚‚†{y€ˆ£›™«¹°«¢§¤¥‹|ƒœ˜”……ˆp„ž•’Œ™„~ƒ’”ut{‘¤¢ž§¢§œx‡Ÿ¤ˆb\{‹ƒn~xtƒ“¥‰‰¥—™ª¨‡ ¢‘§¤™ž‡†£Á¶¤µ°“…ƒ––œ§“¨ž›~†’†…––~³´»§’ƒ†ŽŽƒŸ‘‰’ ¥«¤‘‰ƒoh”¦§ž”˜ƒ‹‘›—ŽbiŠœ’Šzlt„‡mh|y“—«¯œœ¤¼ÁÁ¿º²£š¢œ—¨°£¬­Ÿ‰†’—Š ¥¡š‡nu…{omw{}x~­¡†‹”‘¢¦…‘‰Ž—“…}™œ}zƒ“zƒ‹Š“ª¯˜ž§¤œŒž«¦˜“¨®’}gYN[ktxyx•ng•—‘‰ˆ”«§¹¾­’Œ©¤‚˜¶¯¨‡všžŠ‰¥šŠ‘ž™ƒp–³›­˜ˆš£œ—‘£•²¼½´½¥‘w‰ŸŽ¤Ÿª´»¿®› xt‰„Š—“‡±«‰nu~…’|uŒ•œ¥˜“š¢•‡{zs{‰‘†‰ž}„•™¥©©™|˜£´£Œ}}…„‰q…–š„•š«¦“ «­¢¶«£‚|’¥¦¢­´¢{X]Ž~pŒ”ŒŒ”œ„™«¢”ƒ Ÿ¡£ ¡œ•š’”œŒŒ’‰“‚}‹”—›šŸ›­ªž‘˜›šŽš¦™‘”Œ…v’”‹˜¥«›’Ž‘“‹—›’—«’u¤¨±œ“¡¹¾²Œ­°¨¤¬¸¾·¡‹Ž‘¦ºÌù§»¹™z¦±«©’–œ§µ­‘—¥¦¡š¦£Œ‡–ˆ­¨¯ÎÄǸ¸É±‡ ¨±°…†–£–|x“‹y‚Œ}rm‘—¨˜mRdroŠ‰}‡“‚zƒ¡ …wŠ ¦’–­§ŠŠ“¨ª”Ž¨­©†“  –ˆ“ˆ ­•„yŒ¬—‚ss…ž–ž©¨žsyx~„¬¥‹€’ ˜–”›¯£|Ž’†›ª‹„‰…‡‚’’’¨¤ Ž‚~ŽŽ‡}|lm„–‘‹…–“’u~zl‚’Žš¡¯¸¿À¾¿µª£˜½Í­š˜°Á´¤€ˆ£¨¹Ç¿¤«»¡¡¢¬ªœ¨–‰…‚ ´Â̺“™¥–Š…€‰€ˆžŽ„zfu„“ƒˆ›–‡•‘››†¢©­ÎßÀ·¤¸Å°•ŒŽ´½¢‘‚Š‹’¡›˜‹vz‡ˆ~|…”•”y_HK_†Š™˜€gŠ¬˜ˆƒŒ~z“¢™‰­° ¦ÇÆ´“ˆ£¬›~‡Šƒ„¥©“‹~Š…ˆbc—–£©¦¬¨š™Œ–±³Ÿ—›š‹n—‹z…„vds˜^bix‚‰~uz‰‹‘—œ–š˜Š†qqr^YWdrv€Ž—£­©›–’›™«¶´§¢ ›™¸º¥˜•®ËôÓÅÃËÔÖļÇÝåáÜã̹ÇÕ×ÛÛݹ®«±µ´´·ÆÉ®sjŽ£›|gl||{{‡liy‚Ž”¨Ž‹ˆ‚€—Ÿ‘›œ–š³Å¼±ª­·½±Ÿ‹£¹¤u}ƒ|}„œ–ŠŒrax”ŽŽ~x„¡›™†xicpŽ‚}•±‹rrŸ¦£›ƒƒ~v…Ž§³§Ïǧ¨¬´¦‹vv‰•˜‘—’Š–”xi|u}|}{ƒ‹ƒ]nq{‹‘†›œ„yy~‡ ¨«Ÿ€wy”“™ „q^xŸ {^z™–”‘|‘šŸŸŸžš˜¢—”•­¶¯«—¤¬¥ºËâæãÙÁª¢¡«¹¥Š’Ž”®ÃÁËÓ½ÛõàÝôÿçô åÛÎ×  í×ÜïüøöáÜö µ©ª™}€~†šœ’“Œ…Ÿ–š¯ „‰xz“¡˜©ŽŒœ¡†…—š£¯­ ¦©¦¥xqƒ™šŽƒ‹Ž•…‚˜¢§­£’“›Ÿ ˜x{~™›–œ²¹©ª®¢¤¥œš•Š––ª¸­©«“€}ˆ{w}–œ´»¶®Œž›|evwƒ‚Š™•–¤•x…ˆ‘„€“ s‚›Ÿ…™°²‘Œ‘†~Š‘£˜ˆxe£š’„˜£š¥’”‹˜‘›’w{–—”²ÚøðîÒÌáêíè÷ -îûèÈ¿ÔÜÌÌÂÏ×æ%þ 2"ñûù -=;63$æßÜǺÙèèô % ÜÂÛçÝƸ™ˆ{„‹‹¥±§ªš’”¥¡““§»©’‚yˆ‘šš›œŠwŽšª»®Î¾½Ñ­‡tx~}}–Ÿžz{Š’›†š¤™¤®•ƒŠŸ¢›ˆ„„››˜œ²Ê¼Íϱ¦¤¦•“Ÿš”˜~vŽŠ“š”–Ÿ›©°·¹Ã£š¯·¤Š–§°«¯« ³¯”žŸ™–™¬±¸›ƒ ¬ŠfxŒw…‘–†{„™œ†vŒ‰}ˆ‹’„†sovwy„Œ’§»ÉØôíðýû - þÿ "#$*1þ$úõêìñ4+îÖØÍÒ¸ž¤½ØÎáø "3,àÏåíåȦ—„‡Ÿ“œ¸¯›‘ˆ–£ª¤˜‡›¤•‚…u†‘’œ’}‡—¶Ã¯³Àº¾ ”¤¨Ÿm_xˆ{‚…{uxš¤£œ£¢¦š– ³´œ’™£È˸ÂÓæØßÝñáØÌÆÍÉÈÀÄËÜÚæÚÌÑÉÏÃÈÙȶ¼´©µÊ½±Í¾µ¬§¶±‘œ›³¿°«ÄºŸ¦½¹ÃÇœ£Á¿«§¬©¢œˆp‹®ºœ—¡´º¤‹‘ ™žª¢™˜Ÿ—’Žš¡©¼®ÆÝ÷òú320:,+).8>HA2=4,' ýóñö"$ ëúôïáßêÜÞøë³½ÈȸµÊÚëþò÷ì#23<&ýÖÙèÝ©Ÿ¿Â¶ž ¡–€“—•¤¢ƒ‹’z†¨§•”Žˆ„‘™ªŸ’²¿ªŸ´ÂÊÌ”txz‰‘žš¬¹ÆÁ¨­»ºÈäûæÙæêûëþüóú  "5<Þàðþíì -!õïÔÞÖı§ ”—›‰‘|ˆ¦¶§µ®•–šž±¢¡¹Íº³Á°¥µ§Š—–§“¡­´ž~œž—ÄÀ´´¿»­Ž’›³¼×ãþ  09CKFAJKCFIHGB9=*(*ôåàÛÒÜ÷ õñøòûû÷úöëëúþý15!Nb\X?*þïܹ¶ñðÊŽ‘™™«®³™…Š˜™ŠŽ¨¥´¿­Œ‚ŠŽ‚˜¨¡¤–‘“ľ±°³ÀÆÇ©’…“š“’ž®³Èº»ËÕêÝÎÝèòü0"û &'*373<6>8991+,>CB<$+%46" ðüøÙÀ¢˜™„‚{p†“Ž‰…‹Ÿž£©ª­žˆ•°´™Œ•’xŽ–—˜‡st†•œ…}~¢Â¿µ¾Úªœ£Åéü73!,1$#$'$2IN<DXWW>94 üÿ '-2&,)($)"$7;4<7956>]iY?,Or^D!AT/ùðýƤ–žž“—¦°¡zsƒ—’ˆ‹©¼Âɤ†ŽŽ~•ºÂ°|…¡´¿¸²³ÆÝÒ»¨šœ²ÀºÕòùúùìèëôýðããäèô+ö -!(/)4:--<EG1'+/5=E3A[mcUC-6<<2 %&'%?5ôçÙ‚Ž— žŒ–Ÿ«°—ŒŒ„vƒ˜˜€zqyœ¡ŒŒ…~€ˆ£´®‘€¡ÊÎÁÑðßÉÏØ "[inEøÙÏÝîöB7.8?>-7@MM9;>&%#(:DG?Wql>EWI:;@5*AIScp©ÁǼš‰s|~\O95fkT4/SkZ0%IY2øĹ»¶°Œ•—Ÿ—yr‘‘’Š ½»™xˆ««¨Í¦†“‚w‘ ¹³¬¿Ô⵹˷Óï ÷åãæðõîæØã'!*/&@J! +.%$4>.ìçßèü!+BTK! à· –——§§v‡‘›€{ŠŒŠ‡{m^{——Œ™¬Ÿ•š­½ÓäÒ°Åßêðìôïßæ"'QQM$íÓÀÁÜõü7X]8>E3-02Ngr`H2GUUKVeij|nZ]rh^]NGCNY„»é8£×ºs¿‰u^RWPIo…\TKVh|\>a}gEÙÈÍǶ¯°œ“Œœ…Œ‡¢³´Ž}™±µ¥›œXU|zw‚™«ž°¼–~Þ -)$  ûøöòñôùìðA5&+8C5!2<3;DA(  õÑÀÛÿ üàÙÜçðøü/:5@>ß¹’“‘–”œ©—uyz†–šœŽŽ— —£ª¨°­Ÿ±·ºº·±‘‘§¡§¦ª©›”§ÒìøøéÛÕäÿì÷ðâν®«Äí/RbcZRQF?R[yƒZVCQcWNf‡—ŠrgYVtcz›ŸŸ—Ály³H ‰­™`VS]u{;)MWKA%Nk^E;1ÿèàçßÜ»ž˜”©ž‰ssš””¨¨€‹‘‹¦£Œfbu–“ƒ{—¯ž§Žˆ)2  1AD<@PH8+'?auuwnj„…‡odfylG:@/ÿñÞÈËÙíéìýþýøöè ÿ -ñÛ¿£Š}€…x€––{…•š¨©›“ ©¤ž ¹À·«ž š‡‘•‹““Š…””„w™ÃÃÍØÏÎáôæ××»½Ÿ§ã" )N_nxfYdioy‚–qr\NgXNp›» {YX\cl«å..$Q¼ÝškS:þÖŽ[ˆµšueuxzf6:LF45Z[ZZQRE@DA'ò¶¨°¨§‹q_m’•|q¨‰›ˆŠ¦¬}€sŒ™¬€—œŽ„Š—øý 'NTXZkqqTZWNXfŒƒ“§ËßóóÔ¿™r{†„gVBFTXCàÞæìþ÷êÐåÜÎÒäðí  âò+&$)" ñ¿§~„~‰Ÿž—‹€–¢¡¬¬Ÿ¤§¦Ÿ‹“•Œ››¬Á¯–—œœ­ ”—Îݾ¿âôü -û㬼»¿Ô(ST\dq~Œslzq ÇßͶ×ÅŽ~pg“¿íÓ}S^ab’á0O|Áìú5â>̃XDS57sÄË™ˆl]n])@aY[ajdqƒpt’¾¨‹vC˧´­’|yuŠ£‡{{ŠŸ£±ŸŠ ‰s•Žc{š©¥–ŸªŒy–­ +.,@8/&198XbcXQVbbZRaq›Ìô>žÜϤl É xbhlzpXE?IZFý ëáá϶±Æá -ìÜõù -úø *õîϲ¦¢©›¢¬˜‹¡³±¥¡¢°£‰|~‰˜”‹¥¤ƒˆ«™˜©®š‘µêðÀÓð øûøËŽƒ•¨·Èï Gn‡}_fvyoeijr²=*1˜Îw뚪ÑåðòÍbXfÈ*H.K¿N‹uï<Π|‰˜qkœáÌ‘f?KcQ:BMc]FANb~›Êö×¹¥œv#Æ¥Ÿš—«¥ˆ„‘ˆfx¥¬¬§’”‘‹•|rsr §Ÿžs~Šž[RO[MV\\H<DIHS]P>>UbVV€ ÙLÞ‚Ã$°;ˇk`W@QVTNDFioM242A/ýÿê¿À·®ÙõúïÑ¶Þ  0ùÜÕ¿«££„‡¬¹œ‡™Ã¼»³š‘‰}sxƒlm–§«£³«©Æãëú) þøÕ­œ«º»Àå+]r}z`VpcI,<ZŠÖC…tV£A&iÓ´Ê´¡Åóâ‚d›5±rþd*Ž{<î£|K%ðØÐÑ“S$(<>@HDKY:%+;j¥Æ²‹’¹­‘‹ §³’±ÕΟ…•™†ª¼¿·²¦‹”€‡™‚er‘¤œ†’—RGhufUcm_OZ`TMUYSJPa–£µÃÛlÊûÑZksmb??KKGCPkƒtS:32,/.ëÒ¯¦¼ÜA7óÊÀÒéÿòêýê̳µ¢‹ƒ›˜‹tyœ¢®Âª‘›“vmhx‚ƒŽ±¶®ÐÛë#Zc’©»4þÇ‹Ÿž’›Ð -!IVYec\>).CÑ8 ž õ%Ûš•‚~¼èÜ•c»‹—gµ!èéÓÓ¦m1ÛÃŽ]+ !2!)'->))+s©»ËžrAJTGXzŒ•}²¤ÉÊÁ¥“…—Ÿž«¶®™jwx‰’{‡„‘|‰•¯™‰Anz„zietigrqbb_eenv¯æÝÀ¬óþ˦j8)CYv‘x|~|pVc€q\8?D* -ïðÞÑÆÊû93Э¡ºÈë!fsueUF "#㶳 Œ‚–Ÿž“‘‰kv Ž¡®”rkt¡˜¢Ãæ]“¼ã ;Z\>¬Ë…r‘‚x¹ .+=;%)IE</"AQHxÁ+À b-ÍW³x‰ŒŽ¯¼²ˆfýÎŽ¬‹‰TÁFûìÜÊ¿©¥™”ˆs^/ " -/:W®Ó˧n:4Sd\m{†Hå½¾¯¯±Ÿ°£™ƒ˜®˜smvvŸš™”“€–ˆ˜š‘Zkowy`e„Š…x_gqyr‡´áô¿b7461% ðßû#i¹ñ61 Ñ¥zM^ow~h<?MA&êãØD:ýÑ´©ÖÛIJ˜›¥ªÿ“WxlC -¿’AìÖ»ÂÛßÑÙÖ¦}œ¸¬ÀÖÖßÙÚÑú+X”Ì>~˜‚Z, ŸÞ™pnn€Ê@Sp_NZn\Q]FDje^vº•÷¬Mž’ïnJh‡{v^XVUdѱs‹^à1¥PYga^grfebfdB+((08<9;h”Èêã–U?M7J€ƒn„†qKîν¸±¸Èª“”…|‚Š—•‘¬¢››‘rb‡…z„zpo„’…w}‘—›x^\€‰‚ŽÃíÆ‚[9÷âåçèíéÝÌÜå$¥BÚd\¦Ü]bS9E[B.,3+öÞáN<ýÔ¦‰|—«¨£¨¤° ë+/3?ae0!ôä¼vF//-òîøìï 4Xb“Þ&7FEG7 ĸšwlˆ¨iÆ”|{x˜ÔRp~„•´±†a^`QZUUU]“í0  Ö€fpvz~kM[yxmr»hnH,FZ^TP^WcYTcSED";VqZ)!b›¿Íùà“a{og‚„{xpU55ìÔÇÄĽ¶¯¨}˜®²¥ž–£®³››vWX|œ†p‚…Š„{y†‰a<@Ydjl`_y…™ê -¬F -ò÷"½äèØè»*p?=M?NaSH4õëÒã -븘—wTdƒ„|‹—ähž€z µÄâ#'0ØÃŶŒ_QPF3-=d‡¡È$\[OG0ßͳ•~_+)G`v’Z©‰’¦£±í'Ve`j™Ç™T26;YMFCGEqy…‰|{{‰›yw{bia\Š£„G,/:LQ>FNTPNVF9=+'@M-+{±ÇÐÓ°[HMGD#1TG3-9üåÕι®À»µ¦¤®°ÀºŽ‘¦ŸŒ‹…ksŒ”~˜‘{{j]^V:"8DY]X8Ep¬(WÖ0êñKX>+):RipoU‹û«fÞ6í!7A;.'ÐËÅÏð#Þ¬ž¢‹jep€jYk{žóS„oH+)9i ª£ ¨ÅÒÞ !÷èåÝèú "B\|«–J×¹‡UCB<<B43@hšœuØ©|x©­Ã/VYJO†³¸—T=9Y`WR[]jtbL[hv}uuv€dRE1%)4%/2#.@!+&  ùöþäÔïGw—Šs)ßœ`C*&‹âÿ  ïèèÍ°œ±½Â²©™Ÿ´±˜vwyuyfr}Ž€si_RNGGSC5:7'60(*f¸=€*‰;²è'2TŒ’Po»ñÎýyTâÙÜßìþÞÈÐåò¿¹·‡^Wiˆ„gi§ËnAäê 3NSs~…³ã@F/$ ÿîÝ°rP5  +<@)(=h†¹¡5׺­Š’¬¼ÒK_cKFn¦°€_YlhtslLCZmWHL=BB1 þëÕäæçóþåâåêóôãÉð"ææîÔ¦™¥‹hg]4.p«Àá"û˜%ˆêÊ¥™ÕsúK”±ÅÅÓîíÓ¯­ÀØÊ»±ˆŒ¡¨¤|kbˆzqykd…t\_QJ88=?Re`E."+0-+:e¦âÝ°|‘éXÉï -242ÃW³…¬ÃÈà1ÙÞòò'6-'=4÷ðûÜË×ã­ecr„‘¥¥°ÊØû]•iëÜèôýC_r_LaŒº¾ÃÓëݶ›Œ~|mWO%þ  ìñXŸ±g𨚞Ÿš¤¶Õ#m{‚saz–­Œkƒ¤™¨£~PC]}aJ0îÚÀÓåáÛáø ðâØÚÔàÍ¿ÒÜéèÔµ­…\ćdNKE2:}Á<º‘ÿ=‡-ù׿åbÙ-ƒà<}¿éáÙÔÑÍÌ°•Ž¡­ÑÙ·€ƒ“…’‚v€ŒŠt~‡(+?HQLPR>,$*40*!Dr”ÄKg¯Ë÷ ü­ugq 1€'ùý9WU)10;4÷ÿ+6κÔäÁqbo‰š·ÑîöþT£„Aô -ErjT`vp[f`bNJB4CO+1)úNF-dœ¥QÒ¤³ºÃ¹«¼ñ3vš–uˆŸ³®‘¦¸ÁšŒc=`~•’…K ùÔ¶¸Õë$-,=9 þóìÞ×ÇÁ³žž yZZa)Än9<8FMEO‚ÞCÁ9u =^îÕË̽¶©Ï3‚ö¥D®åõ ×½ÅÈ϶Ÿ£±Ûðç½´«± zrŒš›£­,+#3HS23PM:2$+8D7& -6f¢«®Ÿ€jRT[:$Ïži5üþ($ õððð7D(åÅ··´ …“¬µ­¤¾ÕáòA»¤Q  -:ppYl}qiQE!&òñóÿ"C!ü DG'</)>¬t¸·ÌàÞؽΠ-C‡ª¥zpicmxpz„zQ8 :m’ÄÉ‚ìÒ·°Û%9JK4/ üæâÔÕ³³ª‰l{g) -âI¨4í¾±·Ã±±áA½X#z|㵬Õü´²˜—”Ÿ¡ÃzT²@2óÐÕáâÛº²¹ÏÜäûÝÍÏ«Šz‡š©°·¤N2%A\TGA?@0")AQ8,-CW“ÔÊ¢ƒkVD-"<'ýàÈÔêîÊÇÞû'Pbe]TMGHJ3 -ïó¶°”Œ“¢’ˆšµÂÜ;É߀)!ýøJptgqsshFóñúÝæáàûú%; %+t¨–Mæ±­·¿Ï¢¿ñ0Smh\UWFNQa^WGJ/ATšï¿L寱Éó#ü ÜÈÉɽ¬Ÿ¬š¢›zog5 þàožǨ«µ¸’¶ð6­FÝËßµ²ÖÜʸ•…w††q~¹Iê½ =ûí÷èÚÓßæòù÷âÉœ•¤›˜ ž$ûßçúîËËÑÑÓÒ×Þ6A-ìîòÞÐÔýøÚÀ¯¾Ýîì6@;Pry\ejRK3ø íÓÊÊ¥Ž•·²”Ž²¾Ì'¿ð¢I3"ÿ;z“wUUU5ÿæ÷úÚÌü*/$<;)@’½‹)å¿¢»À°¥©ºÐ %6GLScdq`TXI.CZPI2X®Ì¨CÛµÀʺÌàÖÉÆ®‘€Š}k{}{|yn4H@4Íb﹡ªª¹þ5G|ªõŽ­ù©­ÁËÈʸ ™µ¿¡—­›÷ÕÛ˜þ÷ïãÝÚÏñóáÐ͸œŠq–«qT çÝ˼µµÀËÕø -`ƒ‹—šš£­µÀÖïïæºÀºÉÓÑÉÑàíú8 ³‹Q=6# &)êÒÆÏúóÛÞ庪ÈÐÄ£±®¤ûˆ«v0'1&:^[H>=9"ù  õôB@þû -*/(-\“Ä+Ýк¾Æ½¥¸ÖÜ1:SSS^JG>&(.<?Kóþ $Ù¡„…‹„±Ë¾™Žjo‚z—š“—„Š‰@R}wrvLå<•-åËÓVt–ú‘_¥±¹·±œ±ËÂÈçàÃÈÔ¤r‹×Ì™û ôÜØËÄÆÆÝêñÇ’‡ˆ~hiTúðÙŸŒ›«¯£–³ØÞâû'MdlsªµÊè Hffnƒ˜¥±¨©·Þñø¥*£2#ÿêË·œ´ì úêîþ궬ÂÜÐÅ­§éeœl4þÿ&BA)/5.5&  ùü$þâçÿ&5)5:XÀ‹,êÊÇ˽´¸Ìôò>OCN<.üúðëóîɺÀ×Ѳœš‹°­°®Ãµ™†vo—š³¥“–{qd|–‹…Šn -}Ìd^¶âÔšQeÉ'Ź¯¨˜ÂäÔÕÞÉÀÐÉ–‹ŸýÌÞ§ ù㲫µ£¼ÙÙÚÓ•¦Ž[].   ô,KF7)-.FNSe€’‘‘ªá - Nržâ'RmŠ¦¾Ò›>;„åÝùîíÔ¬‰†€™ÈÖçêÚ˽º¾¬˜»Ý÷ᬧçwÀŒG#>[U#ý$8 )9H7ó05ÿÛêUS5,=hš¾–RëÎÍÌÅÀÂêù 5:+ÜÁÁ³·½·¨Èϳ¡¤¦¢¿¶”•´ºÂ´§ª Š’Ž˜±­ž«¶ª’—š{{‡”“„‰‰noQþ»l]{’“Éhf›RíÉ˸šÅûéÀª±Á¶¥—€”¹Üëªÿ - - -ß°ÆƯž³ÊÎÛ¶¨ Œ‡•œ¡±¶¾Øìæì  ûÔÜÏÛìîù ìêç÷/7S™Ù‚íGlš½º¶'°¯àþñÜÊ­“~‘­´¦Ÿœ¤œ‡¨ª¤ÍâÚÅ·ål¿|7#>9AV3"#.N=:8++]” ”wš¾”vS&,P_MQo™Ü¥*äʽºàëãîìÞó!,×¼§Œ‹‹¡›†„¢’’—¢¨°ª}†›””¦—œ€•²¯µ«›˜µº´·¥Œ•—›¤›–¥°aM@##2Vtc5ßX½Y!âäïþë° ª´¯®š…£§.!Í"3þßàôóìÚ¤¡Æ¼»Íº¡¨œ—›¦µ·­ÆÖÑÙÖÅÉáÛÝðͶÌòüßʼ¹Âàêúýøþ(sõˆðGŠµá츣žÈÝßÉ»­¢†‰{z„§¶¯œœ˜³¯¡°½»¾¾çdÏ XQ|ƒvr\==k…zz—¾ÄÎÝñû%VoX>4íêôâÁÏÌçñëÿ05®íÚ×ÇÜüùëнæýá¿Ä̪­¡š¥•‰¡¬®´¯©©œ€›…y’”™¡¨Á§›´ÔÆ¡–€—œ®¶ª”zx•¤£…x¦ª§œry„j^kdp…†yM»€e[Aä̲±£Ÿƒ‰§¸·»ÃÏU%ã-)ÿêó -üöɶžœ¡ÚÜↂÙÛÛÛº¢«¸ÆÓÒÔÄ»Üý˲¡¿î÷Ù¼¸ÁÖüüûñÞ({ý¸Jƒ‹€††žª«ª Ž’’‹n|‰Œ‰Ÿ­²ª¢¦¢´»¶«¥¡¤µïeçÕ¿ßþ/*$DsxJ2').)OBý LL+0 -¾7à˼±ÏìûùóÛÎÈëüùïÐÔÚÚÑË»®¿»®ÇÍÕ¼´Æ§¤²¥—¢¶º½ÍÛàËÃÄÑË¥••²¬‡˜‚xx‹˜¨™z~„¡®’mfxnzj_iŒ§£¦ž‡0¼c õÒ’@üôÙŘy›ÎìþðàÈìj>?1)öõòؤœªÐÖÀ‚‡ÞßçãÏ¢•¡®ÊâëÞÄà"ÔÆÐÌ®’ªÊÙÖÙÌÊÜíÔËõ òÉÇä0Ù¼c†sq€†‘ž¡‰–j›Ÿ‘„ ª¨«Ÿ††ƒ…ƒ‰¡ ±ï3+/J;íÑ×æÄb"6<8<OlnH3Gq¢Ÿ›€iZ@'Û¹¯ª™¨ÆæàåâáÔÏÚåèñ'å¼À¿»»ÓáÞÉÆÜÁ§°¿»¥ª³ØãèáÜéêÖØæ×˨Ą̀Ÿ«°¥«´»Äº³¯£˜¥q}€€‚pdr‘Šš²¹Ÿn-䪠i¬TSN$üÞ×ö8Q ÷ÜÐüŠsn -8ù -òÖ¼©³½«ž„}Ѳ½áä°³¿£¡ÆäáÒñOJ⤫®¿¹©£²çÿòðÙº®¨¶í!õãèâ1þŠ™•„lˆ”«§§ ”q\t„lguvˆ±ªsnwzfjhm®FVYuxpo€ˆa/&2.È·ÝãåðöèÒêâìö)  èàèÒ²®±­¶«±ÈÕàݸ°½âþ!F+ÕÆÈÑÌËÙéÓÒÐʼ¬¯»²¯­°Â¼º·¶ÅàÎÐÛôìĺ¿áÑÁÛÅÌàåìÝ×åມŸš—¶É»ª˜œ›´»Ã«›„N8=øŠ'˧‹_43?>HRC,óãÚ®—oè ü& Ô¶ž¬¤˜‘–¿±¸Ñåöëä°Æѵû€föáâÛéÝÁ»³Ñöòïýõ˜ÝXŸq.òö’¥m™¢«ˆq{–ŸŸ©®¢ˆw†£§„{“š…‰“‘’’–’{Šˆwš±Éäüõêêö ï¾ÅÔÇ·´º¿ÁÑãáùúïæìðß²ÅÕèàÍÓÜüóéíàÔÀ°·¶›¬Æèܼ©ŸÄíúü æÙÈÃÛàÔâòéÖ¼¬­¸½¿¶ª°°«¨ ²£˜ ®²ÊÒË©Á#G)öÆÀ×ÝÜæñÿñÈù¶ÒÚâ׳«¾¹¹±¸À¾º¹­KÙoφU116,5=(ôïÖÆÁîu:Æ  øà úà·—Ÿ«¯³ѹ°¾(å«®ÛÙÏ^ƒýÓ²¯¾ßûÑ´Ï6—nâäîi†g›¥©„g\f‡‹‹‘ž£ªÑÖÀ©©ÌÇ­–‰Ž¦·°Ž¿ÃÌÈÇ­§¹¹ÑôÓ½ÈÐÃÁ¾ÆÓÌÃÜãéäÞßçïÍ¥’¢Âʶ¥§ÌÌ´¹ÌÀ²¡›¤ŸÑïßʶ¥ž®¾ÂÛß¾²®™›ÁοÑÞ¯–¢¶¥ƒŽªµ­‘˜±€Š—•›§Ä³³¨Ö–Üʼ±¶à;+êÈÓÛËØѶ§£§¸£›’¤¨®ÁÂœaìQñ£N ôäñàõôØÒǽ³–‚ÁWÛŸôý -ò÷û縣µ¿¨­¸Ùα¹ë$<C1ÛÑÑã<¹è£;îÄÇËÐû -íßÝÕÚ÷ 𺥤¿!.­­£†bXQTtynv{ƒ—¨º¾¨’¬É»¨Šš§ÄΕš±µÌѨš³¸¶Ç¹¾ÃËÕäÕ¼ØÔÄÃÂÈÒÈÂÁÚçÙŨ°ÃÑÀ˜°¾²‘Š›“Š•±Ä¾Á½¡³©¡{•°Ã²¢–…‹¥·¢¨²±¢¡°¡¥¢‹§­—‰˜¯«¥¥¤®²ÁÓ±·Qêï›"æÆ¢Œ· G&-×Õм¯˜‚ƒ‘“˜šŒ­ž—š‘j(ŒØs#ⶦ¯§­ÓãѺ  ¥ª’•Ï½¦kï%  øó -óÎÁÔÜÀªÀÌÀ²ž§á4pwÝì*¢ÝÁUþê;â 0ßÒÞ!öÔÎËÎÏ̪†€„y꡾“¼Ì¼£Œ}„€•„lUINiw^Yd…š–w“¡Ž€¥É¸§­›´Ç¡¬À¹¶¥ª·ÄæèàçØÙν¸£––”Ÿ¼ÇÔÄùž´ÜãÁ¬ºÍ³¥§Å·Ž¯Ä—š¶¥š›¢’l|~‡‡‰‘’¢®£š²Â¯ÆÙɨ›”ˆ§ ©¡«·±¥¶Ã¿»Éá@¿¸T亜–ž·Æð÷Ƶ¨ž’€ŽŒŒ‘“£«•†{{\ÓPì©Ž™…€ƒ‘«ÆæÌ®¬¥¡¥¡sŸé‹n3Î4, àÅÝåÓÇÇȨ›’‘”ÖO«ucÇÞ¤0ãÀ ¯Èb#?àêûóÍ£‰ŒŒ£¯Á”“•ÁQibÅÕж“¨ª•™±²·˜uqoa>YewŠ••njŒ£’Ž¿ÔÓ×Á«¥§©¾Ë¸µ¹ÈÜéëâòêͲ±©¶¢Œ¬ºÚÔµ· •µÇÁ£º®¢¹ÙÈsŽ l…Ư‘šž¨¦‹~{‹—ŸŽƒ›ª°¢¬¤ª³Å½¢ˆ“›¡š§°º± ž¡»¨ª»öC, ò϶¯¢»Ê£™ÕÜÉ·©›w»­¢¦”“Œ’–~q|†X•‘䣅„€nwwƒŒ»èòÍ«™Š†˜yp€¡í}*ö³  ñóäÁÃÔøìº̼¡™—ŸÄ§á®ÕøÖ¹­˜–˜ãÿÔ‘ÙÀ¶¿¾¥®º¡•¿áÖ¤°½´ÝÛ -¤Ä±”€•­¬¶ãÛ¶ª©§›—w‚› ¡°§Œ„‡ª¶Âɽ©­¡£›œÁ·ÌÛÏÏËÜÔÚßßÃÉÙâ´—¥§¶Ä¸»±”«ºÀ©¢ª©”—·¢mwŒ†‹¦©¥Ž¶È·¦—ªµ°ŒŸ«˜”„€v~zy~‡·¸ª™•¦´­°›Ž¨v¡·ÏÝæබ¨£ªÀ¥ˆÀáȼÓÀ©“·ÙÁ¹Á°œ˜œ™}“‹[‡O»•xns`V^n­íêÚ¬’zxƒ{vžÅÍ£ˆîïø ô¶¸Óïá½±¸Â«›ž«ãr ë{ö¾Ã¸´²Œ…Óú³[²’‰˜¸ÇÚúíÇ«ÅÖɨ°½À×›žjÁ¼ªš–¨®Çéƨ’’°Ì¹’œ£´µÄÓÊ´‹tp–¬—®¦ ¾ÅæÕ½ÆÉØÖØÀ¬¨¾ÆÉËßÜÐÚÛÞÌ£–²²««¸¨”¨ÎѲ­Áªœ™Ž—­«ÉàÔ§Œ¼ß×”qs˜š£­·£¤¯ ”„”‡„ƒ›ÄÏ·Ÿ–›—…w†¬©¨›~u…¤½¶¾¶¥ Ž’–¯´¬ÌÝÔ×ǵ¢®ÚϾ¸½¯°¬¥œ˜žwÅq¼¤Œri^OVYb‘ÏÕÈÅ´¡™•Œ€w|†‘ŸÛ•˜oÞþýýÝËãòðÙ«Åéѯ˜—³?EÎ ­™§½ÍÀ´«½b¨Γƒœ¦Ãæáð»Å°¡¤Î -FÒ›(}†Žˆ–›š—¼ç÷ɦŠ‘ÃÚÇ·®ª¬¿ÙÒË̬•ˆŸ¬®´ºÇÛýôÙÝðíÞÙ¹˜›­ÌÀ¢¯ÆâüæÜÖØÆÏÊÎÑÊ·‘œ¹ÄÑÓËØǬ®±®¹á×µ°·©›šŸÒûìÀvt“²Ë³¡ÆØØÅ¥˜™³³¥«£°³¬Œtao™¼ÐÓ°Ÿ¥š²å׸« “˜©«¾Óα¾ØÉ·›“ÀçϽƩœ µ®©§¢—šŒÀÍ€jrˆŽŒ‡ll‹«¬ª³¾»®Œz‰†khŠ}ŠÜ–‹]Û úõþô¼ýb:¡¿J!9zòÁªµÀÎÓƶ±þ?û¥ «¬«±´ÀÕÀ¸¿ÄÀ’‘Ã4³ÛáhßXŽ¦¯¯’±êþàÃ¥ƒ ³ÈÉ·¢§¤˜¤²¼¸±¢¥¯Â»·¼ðõÛÁÖâËÏëÞÆÌÙÛ¾»ÆâöèãúòïííïÙªŸª¥¼ÛéèêÒÎàßÀÊ×Ò¯Ž–¢­Åå >M73 Ò¥œ£½ÐÈÌãîÒµª¶ÁÀ² ‡œÊݦ‚§¶¼¹ÓáÛÌÑÜãÍÝðþûóùùçØÆÑÔ¿¨¯ÏÔħ°°ž”´½´¹°—ªÁ],qx©ÊÉ¥¡œ‹‘¬³¯À®…€~rju…“’‹¸dT`ø!íàù6Ê‹WÒ²œ¤M6#KÒ¹±¤‡ºÝÊ«¿ïÙ•“«¹¾¼·Ç´Ÿ•£±²¶äXÐ ÞŠ^“iYÅÜÉ©›š´ÝêÞµ™††•¶¿³©´©„o„—¥¡›²±£¾âݲ©·ÃÆåõÞÍÜüøÚÁÓôôßßàüüöÏ¿±©»Üò # íäÏÌΰœ¡®¯î?n‘«¯‡F#èÒ»³ÎC/çÑÏÉÄÅêôñóøþäç :DDcumI/SF3(''#õÜÚãçΤŽ‹Ž—·É®Ÿ£š«Ôš¸l‹l€´îéÒúÛ™«ÉÈΛuŠ}–¡«¹ ze¯VsŒ  óñêé´è Ñ›€~ü× µ›•‚wy ÖöέÂÀ¡”¡±³—¤¡y“¶Ì ¨¡TÛõ@ë㽓¢¾Äŵ¡Œ“®¶»¨šžˆ‰Œ€ÉÌÅ°—–Ž˜·ê多»ßìåÞ×ÑßâÚÎÐÙêçåëóèöø  ñÙßó5h^YNàÄÊÛÙº²ÃÄÞ*ŽßøÏ­{ø -&Tj’¸àÈ”>0R±@)" ]cj¡Á¨¸¨—†p[ku{gBGKF9<G,'2!ÿо½³›ªÏ­—¥¯¦©µ¶-ë¿VoŸÎáJ<ñ¯“®²–pda}šÅÚÔáâ”t|™Åjœ{ßÿìÞäÿ—²­}iz~çˆ|õ¶²§ª™ÄãêëЭ¬­ºÑÎų£¤¤¢Ýˆ]2ͺ­ÖŸ -ã -⻕‘£ÄŹª›œ“¡ž¥¼Æ¦” ÆÙ¿¯–’ØýñæÌÁª¥µèäè¶ÇÐÌ»»ÁÂâàÏų¹ñ!) ú'J©Å±¬e3þÓØëÏÛçûK©ö2îÜ—mzšª´Äçùðì»xŒ¡Ò÷̬‡cW}©”¡ÌëÃœ•Žl_{œŽgdvV;;NJgyR1* ô±˜‘´È¸µ·®jn>mŒ™Û+YNט–^Kpruº73ûÇ”šªªÍ“°¥ÿò “ °°¯œ’©åHDóÅ·¼·ª¤¹ÙèíĨ‡œÇè÷ú@WNjµ.sE°Ĭª©ÀŽè©ÕDz€¦ºÁ¦‰}’¥®¤šÄÜ»­À½µ®¶©“­ÔúÝÒ²­ÞòÞ×Í£©³˜˜·ÈÍÙáÖåûBtvƒ]?:IbO[œ·­º®«„=ãßï75<fÏ' (äÁÄÌÓ÷ÐðüáûðÐã0&-ç~•w©Àį‘Š}{ƒi^kzqdf^KHC@Z|u\H7GGTN7 Ý·°ÆÔÞæʵƒ›€˜Öñ3Œ¤kè•udl{‚‹£-†Z÷ £§ÝëÃ'!œ“ª© ±è. -ѵ´²§©¬³ÏðóÔ¬”†–°áFö‘½BåÉ›NõÉ ˆÃÂþ…˜»ÆžŠ¯Äµ•‘€‰§¼ÆÁÀ ´ÎÔ³¡±¼Ë°®Øåѻ¶­ÐáËÍëÕ·¸šŽ£ºÙÿ4Oƒ”elšš‡ˆ†ƒ„y©ª¨­›“‰Y ý!Qdc{Ëöþ ,<ëÈÙáÑÊ×ÔëçƳÕû!C770駘“‚q–ª’£œshzpOXe_OhWIKUZZbdIQJ5TOO[D0$ ÿúùøÉ®›æÃ榥£¶å4“ÑcÂ|{‰Ÿ™š§‰LñòФ’§ž«üÜ4ˆŽŒ„„œ££ßëʾÇáäÈÔ',Ï»¶¤‘œ´  [JŠ!ÿ\þûÎ’|d‚2jV—‰šµ²•¥®»µ§›†¶½º¯¢Ÿ¼Ò¹¡¤ÇÒÕÄÃĺ­¦­žÄÉÔòä²¹¸Æáõý6i{„°¶}„}nr}¢­Žyˆ§«³¯¦¡»˜nK>Zn^mŒ—£ÅÁ¿ÒúûêÓÓÈÃȱ¹ÕáßÛÜš…šÛ#:=+$à”™Œr}zv„rSc‡`ESd^hoo]B^umYD=LT_I6KZI?:JN* ÷ÍÁ´o ‹赨½ÍÓ*ªœ¹›“Š~}¥÷>ïÌ®Œ““™”œ ú» ‹‹—§²Š‘Ì'bVE`‰{iSH4沺·¬¯Ò1Õ²iÝ¡Óʽ¨¬›£š£Î‡]H£º«‘šÁ¶·Á»´™“°°š’ŸÄµ„p°Åº´ÈÇÇÖÙ­Ž °¤Žž¯¯ÏÒÃÍÌä]}’Œxe‡² }y„zyv‰¡–©©ª®­®´ËØѳ¨u[Zz¥®ž”Ÿ¯ÉÝÏÑŸƒ”¯À¾§¶Éº¯©Ÿ…Š£Åøæͳž—knr[OYX@9SjkMTZLT{‡jZB[ujONVYQ[F:LW<1=QVZ=ñɽª®¨)!#ª­½²ÅýNŒc䧂_QhªàõÓ™z|Œ“‰–”…‡œ0'Ùþ˜½êÓ¨‘ÎlõÉ’–”ŠMñãÛÊ»¿ÌÝ bÓ5¾PèµÆÉȺµ§®%‹Éͽ¦˜£ ¡¸«š†„¥¢Ž—™³¿dmœÃßÜÏìٹ㈑•®Ã½²•±ÆÛê÷Ees|yNi¤©Šf`y„‹|y—³°¿»¶®¶ÅáЯœŠA/Š½±·Æ¿½áâàÕ²—ŸŽ ¦«µ··¢…}¤ÉÂÍÑô”ygw‹]ASH;QZFJbtiUurQ^sbEC^d^I2RjlP\kl_80PaOVpMïÐÁÅÐÀ‚Ğͮ¯¶±»ìa5Ù oMoÀõò­|{™†”§´¶ÆÀ]\TÜ’žÚü̲ßS̺[ù- ÑÔäòäüêê#85í˜ÈáÒé;úï^ ÕÞÑÅ®¨›‰•œ£œ¤ˆ‚Œ˜…‡ž½ÀƵ¬¦©ÓÕ¶ÇäÒ¹´©››¾ßÓÁ§ÃÚÝü#Qkup]f~ŸÁª“zƒŒ“‡vˆ‹†¢­±‡…žš™´¸›£´})>›¾ÓáîÞßßÕÙÓª§š†šœwp| ªŒq—×Ú¹Ÿ¢‹v]gn]ODRQl…|†qUAXf^UHH;NJKFD}f_pY<7GVI9?W7 ñÝÞßÐÌfncŨ¬œ«â%\wZÁš‘äò¤‹–‚­»ÀÌåá³Þuli¨£±ÛíåÓÕàù âÕþоÞíø)qnÜØçé°£À¼›µ½Ë¶ßb5­ÀÆØñØ°´¿ª}‰Ÿ™‹«œ”Ÿ›•†¨«¡¿ÒÍÞÞØçÝ¿ÁáÓ̵¥¹¿ØüûËÏó÷4`wŠ¢›–xq‰žŸ—’•…yxt~ƒ†Œ™˜Š‰Ž¦‘~¡·²ƒN=l¾ðÝÜÐÇÍż¦™›±½Ä‰c`|£“¥ÄÏŸ€…–|gwbem‚bZn‹§ŒŠaJDH[O@FGTK8)(pŒkF30HRG=58A-56"ÝÔÔÚÄ+Ÿ€‘±Úélôdä/á™…uÏÚÔÊâùϽë¤Ì¬§¥½ÐÔáìåÙÔÝÜÇÅîË´ÂÝòY>íÑÚ×À‘yŒ¼ÒÌÊÄýŠuL±Ë»©¦­¶¬¨½º™—ŸŒŒ˜†”¢¡—§¥™¼ÉÇëÝàèíØá×µ–ŒÍâû'.Serw}‹ƒŒ‡mˆƒˆ‹Š•‘zv„ƒ~—Œ‰–’…mc®µ‹ejkŸáâÙÙÊÀ𬧘—¾Ú¿xŸ¬ž‚k}ws—¥ˆgfs’ˆfOy©ba…ƒohKOqmaI8XXOHKd ³µÜ½LCLYmdLIdX;KJSÜÊ»Ê׶ƒ¾‚}•°±·…ÖÛ—}xn"É¡…˜ËÓÕ¹­á -Ç°¸Ñˆ–›¸ÏÞèáÛÓ°¨¦¹çïÌÁÑÞêøãÍÁÎÈ´’“ ÍÝÕøw8äË­«¬‘’«¾µ°½ž‘ªŒ˜™‰¢»¤}w ÆÃÝܵ±·ºÖèæîÚª›»ü+?PRrvujhkgdf{tw„sy‘ytzs‰•…w‡nz¨®•œ²Ÿ¡¯£g[|›×øèàվľŸŠ˜ˆƒ®Ô¾™rm‚ŽlUE8T_q~V?T|——lAWyeBI^]P`]ev’›zfbpr¡Õû%48V3º[ZbrfT]ggXPgw6ï¿ËÏæÐA&sŒ}¢ÊõL¼&àl붮¿ÊÒ©šÙA'ßÅ·±ÿ–¤¯¬±ÆÛéÞÖ¸½º§ ÐæäâÑÓÄÌÈ¿¬°¶¦™¦¼Çá0Õ¨^¦ÈÊ¿¯´´±¨·ÊµŸµœ‰‘™—ŸÃÍƼ¼¸³ÊÒÐé»ÃÑêè÷ðÉÕñ(Yeusˆ«“€˜mr‹€xƒ’”‚ypdqŽª‡|€jZxš¢›²Ìɾ²¯¨¥¹º‰gvŠŸÂêëïÀŸ­š–¢–“¬Âº²|FXy€baC9?/23?OK]‚‘qJMkjODH=68Sr~¨ÏìàÝó#Olahq“–M§`Z[NRGSrqvdeR -ÿøÚ…µ‘µŒ† ¦¡§ë`ã?{lÁ¿ÇÏÞÉŽzƒÙ2/ Äœ©ÄÆËÉ»ÌɾÈƳ¿ÎÏÀ´´Á±°ÄÌØÁ¹À¼§¡–†›³Ô4ÿ­ðØ°²¨©±¶°±Àž¤«¬¯©•œ°Èѳ¢°ÅÈÚÜŲÒîãÍÑåô8$)Lˆ›Ÿ“¡¼¹¯¼£pRe’œ«¦µ®›’”„Š§«’ŠswŽž ¢¢¥ÍÃúÁÊÖß™z_x’ºàÇ¡»¸´®¥¥«´¶¿IM‚yvsNA>%&:Os~wzsKT{tYD-5Df¨Åñ-IOaˆÇÒ´Ž‚ˆŸÄˉå}e]:,8”|_ZmL>/óÌ»O^Cž|”ÃrÄD‘,I×ÒëîÉ”„•èA=£›Ÿ·¹¾·´º¯«¹ÉÀ³ÊðìÒ³¡—¢ªËíõãäÝÀ²¹¬§Ê: ÆßĹ£“’Ž”«ª›·Æ½·±¹È¾¸œŠpŠ¾Â«°Éàóã°¼ÐÓ¾×-Q^AhŠ—¢µ»£°ÃÔÚ·’i\O[}”¤—zŠ˜¾È±—s“¤£ž’š¢£³ÃçóÖÖ椛”yxfTˆÄ³°ÐÔµŽ}ab^…’†ehƒ‹Ž¡¨rPR[wtlrib`U[gt^ZW[Vo¬Ôü!Utx”§®ÛàÒ¶¸¤ãë¤Ø¥uL2)P‹™qUSbR:O+úãÓ  ìçˆqx‚{·öŒ(OªÛúõ嶴ëA1àϽýž–¡¬ ¨¹¶Á»¯°Âí÷á³›š›‘žÃäûèÅ«¯É¿Í8*r¬±¦¦›Žœ¢Ÿ¯«Ž™´º²¶¿Ã°š´¹†|­¼ÒÛëÚÛúç×ëÌÁÛà(cy—§x ÓÑŸœ»Ð¼«ÇÅ—‰€„pfmvš£€‡¦©¶Á¶i{ž›±Çµ ¢¸Ÿ¬ÒÕÑáÒÍ¿‰†|£žqz–—¹½˜gXNINs†t}”¤‹~—lMPt¬°r\VXgv‹‰n¥š‚®öL‰«¹ÌÚÅ­ºØÍÇ»¨ÀÔ¦W;¥\2Eo‡yKFO]HDP2+òφ d¤l~Šoe›·¤®‡ûËàõ÷æܾ¼æ4ßÇı¢ÉÈȶ¯¦§°·¬®©ºÚÝÓÏÆ»«¨¦œ·ô»¡¢½Ù-ƒš“‡™µÈȬœ¯½³«¶Æ­›ªµ«‘š¬–š¡§ÎâÒÃÆ×ÖÎ÷êÅé'ƒ´­³¹¸¼°Ÿ}…ÃÚ½—–¦Œ‘Œwsu½Â‡ˆ«ÃÒ«‘y¥¡–x^cm‘«›©µ——°»¥£¹™…”“—Ÿ—›—œ¸Ã¯“€v^Y}sz’£›n_I=Iˆµ¸‚kw¡£¥‰€ ×ýóëÿ:b”²¯ÂÜä꾺¯±¹Èų¥»Â¯šü|B]shI67SaU>>HJ?)Ô8 —‰†{ƒ—ž£¾Õ)³Ú^êÌÎãÛÍèü&,ñѱ½ïÔȱ¨±´³¿Æ½¹ÏÕÆÀº°µ´¥¥Ô=3îåÜæ?"µª™…‘®ÎÕ«Ž¢³¦œºÂ§¡®°¦¦Ÿ³•›¬²¶¹¨š«Þò¶¿ÞØÿVž¾±Â̺®ƒt[_˜Â´ƒjnlqv‹~z¿ë¸³ª‹‡pY¡ŠoZaz‡‚Ÿ©®´µÊÚÛÒÙµ“”x˜¤¹°ËÕзa>NfmMbmu€—€h]aZˆ›w{©ÈÛæÿͬîR@(&(d–—‘°ÆÏð뼯³¸¹«µ±ÌòêШ'z˜ƒXJ(*OR8BbXOT/ý¤áÄöŽ ³±­³½ùb_ ÛÅÈïëÙÓÅÅô×ÒÑ×ʹÙëÛÅ£¥Â¿¬­®¬®¯½sþ÷7ü´ÁÁ¼¸¶²š¯Ã¹·Åºš—®´ºª¢¥ª¡—¥°¦³ÄÄÀÆ´©ÝôÐÞ'MlŒ¡»©´ÓÐÓ¤|›ÁÄ¢v~sxz€—Ÿž—’²ÒàŠ{§È¥ow„”—‡•¢©v|¡µÕãÏÚç×˧zu‰iXa”ËÐØçฟeSCh˜‚y–|_la}’’Ž–˜› ¤¬× al*û@oF..+s”tVS‡´Áßص±Éž¦ÂÊåûã«<ºŠŒ„S3+JA,"<TSSWR$ág}fÀ ¯··¥” ³Æ=-Þ»Ù,h:ÔÂÔòèÑïìÓÏæïÚæáäöÜ«™¢·µ½¯¢¥«†§DÒÛ?ú§Ç«ËÙÊÀ²›­²°ÀÙëË­„‹¥±Ÿ˜»Á¦†ž¸ª§²ÃÍßïëÛÒÈÒB”ËÆ´­´Å¼®²¬’ƒ§¸¢‘•}’•} š”of~¬É {¡ÊÙ³˜nrŠ{}‡‡ukw–²«¼ÈÀÁÔšp]n_B^ªÖÕÅÑзœ‚Z-T—¤¡ÀŸv_ZSp’|›µÈµ®ìYP"olomQCVYC _­ÓÇ´³°Ä¶¢ËÚÜíù÷ñÊvùÀ§´Áf6"2IQHNWGRYBý½" ¤®¨™°ÊÑãñêÁÒCœgíʹÏöýâÎÙØÍÑßôùÚÏÖàϲ›˜¤Ÿ“‹ÅeÔƒî²òµ§¬º¸¨Ÿ’™šª¥¤­Ó嶛‚‡°À¯ÆÕÝÀ­°¥­¾ÎÄÅÇËÝ×âî#…Ì׸¦€x’³œ{v—“m}’Ž‚—s›”xfy…¥¾¥Œ‹xr’º¢l'/XŠ¥•a^‚™š“¶È¼°¥›gWE=Tv¶Í¾¦Àɦ‡mWP¨Ž¨Á¤|jeNO~·Ä×íçßÙ6‚4G^Wœ½® €V8zÀæÓ»Ëͼ¹ÔîæÑÜÎÖïÚDê77 2Ja[emdeh9暸†Ì®Ÿ|‚ ¼ôõ®ÑèضÈIµëØϺÏáØÈÙÔÇÅÖñ÷íб¼ËÀ«¢¨¿¸°¶ó^‘(ÃÉ‘ßµÙ·µÅ«ƒƒqsjZm}™ÁÔű¦¦®º ’£® ¢¾µ©´´¤Ÿ…Š¿Ïû(w±³›ŽŠƒx¥²ƒ_v¦™•Škr–ˆtƒ‰‚Š~±ÎŸ|“¡—„ª^0qœžqx¨”Š©°££Œy~o`UHV‹ÂÓÏƲµµˆch•±²¯§¨žyrgp—ãB…H"R¯iNx]G‰µÈͤnG1e©°ÕåöûÛ¹ÁÙç˼§š«ÏÉÃ}%MnQÈp[L<Q]it|nYNòáe[V¹ƒƒ“®Ñññ¼·ÂDzœËB³‡ôïßÆÂÙæÄÓØÉËÓÚëâÖÀ¶ÆÊ¿¹ËÑÞÚúß³®%P_°“š±´««‘}e[€˜©ËâÔ¾¨Š“Žrxz†•ÌíÁ®¨‹ƒƒu¦Êå#|¼´™“˜š•Š˜up’ž”’Š“®®Š‘‘•Ž’£–t‡ÂÊŠo‡’ˆ||s`ŠŸ‘‚yœ¼Ô·Š®ÄÀ˜“”_KafQHŠÆÒà»’±Ë®hi’¬™¡ ­Æ’b_jÍ2«wDVƒµÍÍÓÆ —•Œš¨¢¹µ”{Š·¿²Ðúï¤ÀϹ§©š¯Ï×Ú¶J5Yl6ÔcVPSNXme[pI Ñ¿뫨µËÐ×ìãÒÆ š°Åk]öÖËÌÑÓÂÉÐÁÂÍÉɽ¶»ÁÕÝäÑÎÛÖáGd掀ý!¤¸Á’¥µÒÝØ´™– §¹¸Éè“–¨”{‡–ŽŽºþûÔÒÀ«¦§ÇãÞøG¸©¨›„z“°Ÿµ›†„„©«©•”¤›’­­Ç½€h´°|›Š†Ž‡™£–~•Àͺ¯­‘Ÿ°™wŠyx{u^\o©àК€±»‡|‡ŠcO{–É›t^P›Fˆf^›Üר­È½§Áʽ¯°¸²±¸¸½¼çöЯ©´·¼¶¾ÕìôÓÖéàÚ’[ZJõ–e_S]K4FkjEOrj'êá]12Å·ºÊ´¸ãûíʬ°²Åå"óÛÙÁµÈ¤¤¿ÉÈ×ϱ¬Ÿ¸À¼ÏÕØÕÊÎý{iß‘ÏÃã…¼ÌÛǯ¨ ÃÞèØȱ™¡ª®“ºÝÊ©¨  Á»¬²¶´µÚ÷ö÷ØÛѼÑáÞý0„¼µÆ“hv‘–°©¥Žmw}…ŠŽ†§¢•¥ªÐÍ¿‹ÇÊžž¾²}™­¢„dŠÎƘ~‡šŠš‹ic‹”„rt”µ¹¦´Ë¡xs{i]T,8s˜œ’ˆ‡³ &HxŠw“áÓ¥}”ª·ÎÐÖÑ·»¾¶¿¨­ËÃ훉¦Ã±¢¨Àù$ -Ú¿ÁÇÇÁŒl8×qRX^U10EbY[ljZèÚ–a¾—Ÿ§¡Ãø - íÎÃÌËÊ»ÞëżÌÔè´©¼ÆÓïéÈÒμ±¯°»ÃªžºýO5¹¶b©†§¢ÂÜÔº¢š¯¶ÄËíŠv‚•Ø÷Û«’»Ï¿¦¯§—¥ÇÈÀ¾ÓίºáèüåÅ l‰°´l|“˜Ÿ¥‘{s›£€~ž•Œ‘¡‰xq‰ž«¾µÆª–¢¬{cxš ²¢„›£­¨˜‹­¯›˜„UVx‚pŒ©¯¾Ñܵ™‡cep„™qS~–°»·±ÑEw‚•pxÆø悔âØßøʺ¿°¤¯ÆÏÄ¿©­¹°£¬Í÷ó⬴¶½_¥c]_gjA@OKf‡qT:)ÙÂÇÝ™«±³ÒïèÅÅÌÊĸ°¸ÆÄ¥—²ØçãºÁÉÔÍÓóóòÜ¿œœ¢´º¥ ¤Á¦ÿ/i˸ž ÇÏ×¹ª³¶²º¾³¦¶ÉÔÔëÿÿ÷æǽÇƪœ¬”~„¨¾µ«À˹°ÄÊñìÎ7]‡‹…´º©œ ¤–Ÿ¬†h„v—²Y_†˜¢¿¬•Ž’¨¨•jYMqƒˆ‹™¢¨˜›ž“›£¼™u]_‡…wcªÅ²¬§‡kszlq“kh‚’¹¹°ÏA¾ÌÓ³š¢§Æ鼦±»Ó¾àüлȸ®ÂØÚÅ®¡¨·É¾³Çåò¼²Ù½«·¬€3ɘƒfFafOQIXW[PQQEº¶‡k-ÁÃËÈÁ¿°–°ÏÄ«´±««Ÿ˜£¼ØäÝ×¾ØÜÐÏÎáÖȾ£‰“¶Â´ ¡§Ç×á•õ·»È¯œ¦´È¼¢¼Ì̯©Ÿ§Ö1EQBûéæ×½¼±˜°¥—•¯ÚÕ¼¿¾·½ÕÞþÞ×ò2WmƒŸ›—¹Ð͵Á©t‚‚{¾¯Œ ¿¿¹¤z|˜¬¸°§”v_sqhxsjqŸ¦³›š®Ä®’z‡›”~h•ÂÁ¸ŒkejTKuq_irwœ{‹¿¸µÅ -”Ê×­ȶª¼±ÛãÌÄ©¸ÙƳ´»­®½ÝâÞDzÀÕε¸åôɤßÖÈؾUöÕ¾½¸”`UWOKKJ.)KZeA﨣Ÿû¹êË»¼¤›Œ™Äи³½§§À»¼ÌÝôûàÅìèË·¹¿­ Ÿ¡¡œ›£»µ«ª±´ÄcŽiš™¤®—¡‘›®¦¨ÈÖͽµÈ·å)%ï°ºÃÆ¢’’ŸÏÀ­›¡Ëðß³·ÁÛòÞäôïñïïï +Mh•²Áº¯¼»Ÿ¦ ‡–·¶´×ÒÛË“e„™¢›ÈÓ¹§¤}^VZWdu’¶Ç¿­½ÑÔ·ta‹¡¦£¢¤±–dvz†rz_ay£ºÉ«¤åÐÎê'¾Ú×»ÐÔÕħ¶ÙÞͳ°Èµ«³¬¬¨«ÕÊ¿µ¸¿ÄÐÉÑáÚ¹¦»êöͪgÖÜãçÞ›hajTI4(>VaZ6ë¹ÄÉqT&»½Ä²²¸ÂÐÖÙظ¬ÄÔÖÑàïùðåäçàØ̬¦¡®³±³½Ã³³Áº³ÇÕÝ:š¨’Œ«ºµ›­ÀººØòäÏÆ°Ëèæäçѳ«¬¬°©§£Ïаž¨µÔÞÍâÕØåÙáòîèàÎÙîâIƒŒ“’¬¯¼ÍÆÀ°À¼¯ÃÔØÇ¥–§Œ •žÕÔÒÅ”be–±²°Ãļ²Õáñ×°€`‹´¼¿©{xtkjx€wylbŠŽ¥©Ò¦Ãèè=yžèðÖàôᯉ”¡¼Ñ²¬³ª¾Â¹«µÜÄ”¡¬«žÂúáÌÄ´·¾ÆáÒ£§„1 ¥ks}_B5Pawtl3éÀÂݾºRÀÀǾ¸ÊàéëûäÉ×è"û÷âÍÑîßÞãÛ˹©§¹À¿Èì¸ÙÒÑèùÎ ÌÁ§§š²¼ÐºÁÏ»¯Ó×ʵ›£Ÿ ¢±¿±Œ~¹·¯©¬¾Ì©©Á¾ÆéëóôîèÒÊ×ëßÇÅÕ ÿý?_v‰²»§«¶ºÌÙŸœ¤¸³¯»¿±©¸„®ª˜È¿® |fm±ÏÅÈÆнÌäÒ zIg¯³§‘}tNYZtm_Ee™º²Œ‹ŽØ -õ*a¦ÂöðÔìñÏ­¥°­Á°¯´ÁÑÊÂÊ®¶ä©}™¨¼ÄËàع±Ã¿®¬²Âµ¡±{B@H) šeeS\USapsfP.õÒÏÛÕöŒͲÆÚßÝðçÜêáå/n¶’ ѱ¯ÎõãâøùÝàÜ·¥ºÆÀ Œ­ÔÕÐì|´ªåƶÀ¸º°­ÃȽ®Ÿ±Á¾¼¶³¬š¦©›r~ÃâËүµïêÕáéóûôôåìäæéé ,,8p­¿×¶©½¿º¸™¡Àį½ÀÁ¬™ž“¥¨¬²©©Œ€†bPcŠ¼¹ÐìݧŠµ²…kEo¬´« ˜Œ`bŽ{MVm¯Ç†Š´§„¯ñâu´ÂÜÕεÙãÁ±µ¥“·µÀ¸¹Ó¿ÇÖĤŷ—•¸åÔ¾¸²¯§ÍÞ¬–¨ÂÔשfOs}Y3¢zpXX_gr\WI?/èìè×;ÏàÀÜ÷ØÂÂÉû!pŽ@Ë°Ãìî×èýöô䟡¿Ì½¼ÀÀÉÓá97eº¶Æ± ž¢’™®·«³§šœ½ØÀÖǾÏд{‰†´åÙϲ²Ï·¥ÉçѹËßÌÓåèõïÉÉÆááØïñ $'=‡¹Ö¤ËëÓĪ’¥ÄÐÖóΞ‘†‡‰¬¶¬  ŽdRa‹v}Áäï⻟Ãß´‰‚t~¯Ã§€‰––…g_r—¦ž…ªïÓÎÙÝÖn©ÕÈ´ÖѲ¹Àº Œ«©·ÈÁºÁÀÀ®›¬Ë¼Ä×ØÕÉѸ©‘ÏùàÅÐäÑÆŒm‚¦Y鼜”vYHmxYAHI>÷Í«bàÏú;Ë©µÆúºÈ4piîÉêäãô÷êî¼ÎÕåßÎÅ¿ëÃȳ®¾žŽ–šž–£­½ÑÄŽŠÃÓÓµ¶ËÚлÉÚÝö ìàß®šµ †¨¸ÊÊ͸ÔèâñèÞÝ̾µ»ÁÐ P¸Â£ÔñÝÕŶ¥´Ï«“œ‚u~ifw±›ˆ‹mh„‡³ÕùÛ˦™ÈÓ{IF®Ía\|rhŒˆv„¬×³s•òß­š½Ø sš¼›œÈΖŽ®Å±ª³¯´´ÍÍ°¢®·Í¿“œ²ÁÉ°³¼²±¢žÌðèâëÛ³¯œ‹ºÈ‚:úÍÈ¥Œ†gr‰jG)GX[0öÊ —zp8Öæ&VÜÁÌì 1æëD‡1.$úç # øáÄÛÌǼ°Ç¾ýwÖ¹ÃÙº¢´ÄÁòµÓàÚ©›ÃÊÉËÁÌé !(%-ì×¼¯Ã£¥ªª¦‘²íêßúÿûöãɯ¶Ï÷ó2ƒ–’½ÕËÂÆǯ±Œm}W^r‰™y†”•ª™†¶Â‰kz¤Â˾§—ws:C_vJ Nobegeaa›¡†ÂئWb±ãõËÎÚòX ‹‰…®ÜÉ®¢¨ÄÚëѯÕžͭž¤¸ÌÈ¥±¾¶£©Æƶ²£™ª¹ÍØáØż¹À̯c'Þª½Ê²‡\gpI56K[I×È¢¢—âŒåó.X0áÚÙâùKÊ’ùŠº;ü?%ò1íáܹ¬³Ãþ«ßÜÓÓäݾÂÕ×ØáéèçåлÁ¦Áêù_oJ69꼑x•¦½Ô·Ÿ«¬«½ëêÉÏÈ°ÆÙå ÷ѹ¸Ýòéåû$Mfy ÆÝÙ¤‰ž°¶¥xzPTs¨Ãžˆ¦¨¬®²¬œ‹‘¤´µ†oW#Sao]E?:@QV]`v”›½®Ÿ•—˜× ++D„±› ­çèíÜÞ±¸ÄÍȬº›°°¥ž¾ÙÑʹ¤”¹ìݰ¹£©ÛéιÃÃÊ»¢ƒr: éôê©R?CXbcz€Päß×Á«)4!Dp^ ÝÓÌé.Zm¦$Hê„-M,æþþõÝÖÍ¿ÎàPˆ²ïïëäÖÀÇßçò5ÿêʶ±³Åú5PTS1æÙØÀ¡«­Úôí¬£ÇÙ̾ÉÊÉõÄâÁÊàÒÅÉ©ªÓàÑÒôT˜¤¹³™–Œ”¤ ‰‡‰ntŠ¦¸˜Ž›„œÉ¶¤®¾Ÿ¯¶¦Žƒwe6(LcdspgccXEUy}y’¤¨­ykŒËÕÈ$HQL‚¡ÃÔÓçÔÆÄïÒ˜™­»¸´´ÌÒÆͧ¬ÉËÍôªÃĸ¯ÒçÕ¾¿àÞ§°½¸©™›—Ÿk8; ¶]]J==b}}“Œ_@ ͸¬¤ÀÔsXOXøѼâ:]Øã¿]BPM@M<ðÆïëéØÄÔû 4Ä%ü  -ÿÚÖàîû"CXbCB4ÿÞàâìï$;㬮âãÑɾÆñ÷Ï´ÂØ俸ÏÒÝãÿúµ³¯ž¹ÊÊÙÜäç÷ 9kˆ¢¶Ä˨…Š•–°²ŽŒ¡Å¦°¥£Ÿš¹µ©µ¾²´§‡j~iMrxh ¦–š”‰‹“šŒ—˹†F9ƒÌÖá>XRP¸ÚÕ±«›´Ú´ÍÛÌÂËò ÚÆÛª£¶Â¾²ª¯ÔÕ¬»¹ÓÔÀ´ÉÈ´´ËÁº¬œ›ÀÇžXCÿ‹W[YSNV`€Š€xGú°•¡Ž/ªT2,æÎÙìæÙ\³œbj)TmFñþéïøòÔÑ&}}ÿ2F0#,)(A_wŽ˜“’`øîı¿ÆìñÜÞ¹Ž…ÂìéÜ̯ÕéÇ©³©¢¹®³¼Áã÷ö)àÚ³®¼ÅÑòéÊÈEB&p‚—Ç¿µž–—š¬´²–¨Ç®­Ì©‰žµ»“œº½ÃÐÌÌ”l‡•‘­¥¤Ó»£¢’‹¤ÅDz«¸ºŒa[iÀÈÄ×éz v†‘§ëå´©¶¦™¬ µ÷ ã˼ÍÔ»Ãβ–º¸–‘ºæ÷ߺÑØ÷¨»Ã¼¸×ÓÖçÓ¥”ÍáÊtí«vƒ‚pi_W\txdA²Ž§±¨]nuàÏ×áññÖÏÁHQEt­ª9^io:#Í»ÃÛÒÝÿ&Ëç"\ˆŽ˜–meHNxŠŠaz‡H缚™¦É¿°±¦™”¤×òäÜÅ´ÐÚ±½¯–´µ¢µ½ÈÕÇ. ûÖ¼ÊÛѦ¤Õ0  AC^‹¦¤±³µ¡ª³´Çµ’ŽfǸ’“¥Öûß;fc‰‘pn{•ºà«š•{±¡µ¼ª¬³ˆŽ®ºËÀ¼Ø¢¿¼­¬¬¾Ñɯ»Ï¿§¯¢ÄùýÚµª¶½ÞÕ¿¿Ú·’©æÿûé¹¾¾­£¾áÒº¾¯¬ÝòÁ¦¯ÔäÁx=ðš‡r_g[I\mhI>â»ÐÌ °¢þåëÑÙýêù£»æ;?Vhf*L\v}cS?ù©Œ¦ß  nf†5\•ÆÀ¯¦‹jdE@nk\aJ\gW?íÁœ™¡·¨ºÅÒÀ²¿Ì×òí¿«¹®ÈßÝϽ¢¡¦¢¸®ä-:5JêÏ»¤–¢¸Êé!,hŠ‹ ¿«¶­š‡›ŸŠ‘pbÈÖÅÉÖ÷ûÔ³‚KZibP?Y…†|o–›€‹Š†”{w‡žÂÚÈ»7²£žŽy›º«¦¼Ôê°–µ¹œ¬êåÉÄÉÊÎɼÇÑÙ°ÂïÛÖåгɿÈâèðáÚ˜Œ¯¼¥ÃǺù†sÊ¢ˆcXM@7AUPD8Ï®»ÖÙ¸!V Ûµ¶Æ­¢®½í .. ýSbšáÃxBݾ¾^A¶þûTmxˆµ¶ŒpdXa`YyqcleZ^]fH!趖Â̯Áâƨ¹½¦¶Íϸ£…—Âϸ´¹È®¸¤•Ùï $&^g!öÑ°¹µÒ0Wƒ}•—®¶“}š¤·«¼¯™Ÿ²½¶Õîåν»¯qQIBPJWsNU~xii‰¨¬š{kf]?T®8ìÌI£¤‡he¦ÕžÎçÝÆÔÓÛ´ç°¥åõèÚÅ·ÚÕ½ ™Óáι×Ö·ØïôóìÔ˜z…‡­Ò¶µÊÀœz"Ñ©”sR?=,&-P`[:ç¹±ÂçßjNt6àÅÆ»¬´²«Ìù8ò -'qŸõãm+îÛë,UK$‡L³Í¸“Ÿ‚†ƒzlƒ ©’yQ;IQH1þ¹—£º¾ÞÔª–™œœ¬­—ª­‹xª¶¬«ÎÝѶ—‚‘½ç T…k, -çðáÙÏÍã×Ë?PxtdOkŽ›£Šµ´©—´¿ªˆ„€w™É¼µ¥­žfK;Jensp}}io‹¡¯§™§ŠaRJR|ÊKr/6|¢Á³f\£½Çß̸•Íýâ³Ä벉™þ×ÛǶËÉ«“ªÑáèij©Ÿ»ñÿåÁ¹¿²°ž£À¿’ž™Š˜y3¾•{G<KVI5Hiu3ÿÈ©¹Þç…f§„/ÙÚéÒ»º¿¾Ñæ7!ø /%)~È“¡x$çÄÉý$U‘ ¿ë÷Ï~™²©¦œ€`’Ÿ¡›Žq^Q8:3ëͱ¾ÕÖǧ«§¨¡Ÿ›Œ‘®ÐÁ¦†“»­Ÿ¾Óáά›šªÊ{¿j -Ú¼ÞûäÜíðÇ¿î"BKE@HRfdh†ž­¨¤¢œ}r—’qs½À‹xw”Žr_Vg€¨²™iU†µ·‹Œ••ƒvmp¡²Q’’¨¨›|ƒ²¡¬¹¡“™Èôس߽š´õÓ´ÄͶ¯§²¬¹Ûþ碢§ÍóË¿Ÿ‘´´ÍƺÚà±bTYm|,軩rJMj{†jguf7þÔÏËÛÑrº‘3éÿíÈÀ¹»ÓëK%öß¹[i}QíÀÚ'¿1nêÝÝ´™‡¤¢¥’xw”‹‰—¢›~^]E2*õÚÐË˸¿¼»¹‹nrŠ©¶©•’£Ãª¥ÅÙßûǺÈu¨dæ#$ 6;BR@5GQifDZizhi‡¤— —¥£Š—¯q€ˆƒpltxy¦ƒ‚tªÑÔ°¦Ÿ‚®ª™«Ú{¢upif‚™¹ÛÅ Ÿ½×òêؠ͵³ïÿËÒÆÄÒ®µÑË®ØúÄxƒ²ÑñßÅ»’œÕÞâëßçÑ{2#BhQñÅ»°oYf—Œˆ}ul3êÙÜϺ™¶ÄLüøôâËÒÕÎÑèø,aGõý•,%…Q„jÉÜ0FXVȘÿ©˜ŠxŠ‰}~†‰‚…Œ{}€€udKõËÌÖëßÓÏȦœ£¬£§žª­ž˜Žª ©µ·ÉÉö2aG(.Q^71[iw‘œ®¡š€‰„v[?aƒj@Ov€˜š¨®§™{ŒB#?a`jˆp_l™›—›«˜omuˆ›ŽŒ¡Êô$KDCoWYx”½ãÕ¯²¤ÃçßПª½üØôÝʶ”ÈáÍ­Êʧ‚–ÎØÔ®²©›ÈÞÓÏÓØÊ“IêºôᲩ“lfxbHSbgfp8ꪤÈÔʯõÇø - -õâäã××ßD{i+ò ¹q¯ëx‚…LüþHU~Å4ÜÕº³¤š‚rt—›œ„qbekgWNu•zfA6þà̲¶ÚÄ°“Œ“µãéƦ­®£•”Š˜™«ËÈÞü/0:80jxr¥óøõö÷&%)V_:(ç©|€kf?&.*`Žœ–Šfl‡b8;]ustzˆhi}vvŽ{mS.S‹š„Ž‘‡¨Øï÷"hxo”²ÏÓÉÈ»²Åá¼¾×Ǽ®Éñ¸»åÚÞ¯yÏ秡þ¶·½àƨ¡­©É嶕°ÊðÚwNá•Ëòìô·€†Škmd> P[rp£x˜Ëáη á+ ø÷ýîÙÌÖÖò_h;# pºX¢“|C -7G·@ä躨¨¥•‡sou„gOQTdl^_Š­¸ª…XB!ú˨¦¼Äªš°¨›ÅÑöºÅ±«¹¤Ÿ®­¹ÎÄÉÙ',=ZQKo¬ô7}˜ Ÿ›¬±¡©äÈ’¼Ï¸8Þo)'34G„¢¤pjO]TF€•ŸŠgbhus‹™ƒj•zVT|²³Žy›ƒ›Ùüô (ORe”üݲ¡¶¿ÚØÁ›“—§Þñô㨗±¼ÔÀ¯Öº§¬ÊÛÖÀ®³µ·±››ÂÇ› ¿èãp?Ù¢ËëéÓš{‚s^]baD0ALic¥›«ÃãÒª*(OßôßÊ¿ÂËóE`%ö)¢‚7e­è½\ ïàø*l2œ™¯Í½¨„lQGY^LSbea‚…zn‚™žw\L'ÿåÛÔÜØßÉǨƒ‰”›´ÓÒ¾ÁâÌ´Æ´¢²´Áß"BBT}§æ+pƒ²ÉÒðä»ÞÍŽ±ÞçÍ{—;ÿ0*=E/,*G: X­Ê”e^]h}ˆ ¤†tpqu²¸›`f€‹ÅNTjyeÕò󺔉ŠžÒáëקp–Òòõ綖~ˆ|—Ð×ÒÈÜÛÛÑ “’³ÆÈ¡¢©¾ÄáþýÀ_ݽÚëÝαŸ‡VDVgbWGNTL9ÒÌ·»àűlw^âËÝк½µ·Û 0øîýõ sËö¯£¿ôÊXèͺÐG”Ð.Px©È´‰Š‡|e42Qiaftqx{€yk_gfc|pCà¾ÂËååÄ£€~ŸœªºÁ°¹Ñáʺҵ­Àñ.Uqbiy’ÒQ¶½Ç¾ÙÜüîðùéÄÖòñ÷úð½jÎáø ÝÔ.0XY_xš ¡‚eqxYz‰yrw‹»‹zuW[–›©÷x¾®—¤×úÇc~”±É³ØòÆ¡ÁÉ­ªÄö–crÎ üäâÙƹ¸«¡°Ä°­·ÂÜïÝæõâ‹1 ûÕ½Ó×öðÌ‚JAQ^TQahREJ'àÄÁËÛÚì¾ÉŸýæ¯ÀÑÍÚñöÍÅâø?ÝE§Ñ¤ÖÂNñÕÑè©ä>€œŒ“‰ZG\qbHRaPIjŽƒwwXIQ[{ƒ…‰` ËǾ¬ÓçÙ¸” ´¬¨¡·¶¤›¹¼ÖòSt‰o‚Ö<u ÙÝÿÿôëÚ÷ñĶÃüùíáøõt¨!þøïò19:\}ƒeZm›¿À§ˆ˜–o‚’§Â–qYa†®ÅüqÄèíÉ«£‘™}jdqºÌ¾½Æ×·¸¸®žˆ¡¶´ÔÃ…¡âîýôÖùÙâÄ¿¶³ÚÿôöæÏÑ®|2÷èÓËíõÔ€SgiWTd_nwlb*Ó¢µìïüÏ ú,åлÌïøüêÍÐ>ÈY±"†&̹•Fñ×Ò Nå;o†rb57hŠtZzŽ…ŒžlQ9TjzqMEPÓÔÛÑ¿Á¾±®¤¡ž¤~‚‘|»Üù<Z=:Od}ªü\®êúÿô÷ûúÊÑêÑ¿¯ÅâìùôüêÙøëZ—' åóã D@V]XW:NjŒ‡œ»¤˜®©xt‚š¤Ÿ›™£Çè=²Úöѽ¾§‰…‰‘´¹Ç¾ÃÜÈžž£¦¢™®¾Á•¦¾àôÞÈûúçåξßìʼ×ú ãÓÕãäÊ¿«DÙÈÙâø æ‘ikvfS_gOWzyXÄ£°ËÜæåÖ]XköÓÃÐó êÖùMÁH„äL£IäÀ¦nõÖÖ@zû&Mx’‘Š”`&Fhš·¬” ¯¢”–‘t]`OeeSb\KaS×ÊÉɶ²®­—Š˜‹{qŒœ¸ÔÒàïd…¬Òò#HÁñ121ø÷íð¾Ñ׿åùåâÚÚÛÀµÌÜדþhÏ×!<?_o^NGLxr_v¤¼¢ —¡žnA<_Œ¦±ž£åP›˜½áÔ;º´®ÆÇÀ¼·µ¼Ìœ®Â¤¢Åé ²ˆœÍ  -î··çàÓÏÉàèе¸ÌÒØ×ÍÕÚÁ¼³D×¼ÊÁÏåòÃ|en]ce`ZYgr{] -Á®¼ÙÑÈÒ‡ˆœ/þöçü  ÿ{m’nýYžFæÄÆ‘ ûþJ„¤ 6\y•ˆ³²’y‚†ªº«§«ž‹‡š‹‚l‚~jz—†poRô¹°°ª¦¥šœ¨¨¢««¾¿ÏÜÌÙY¨Û6k¢äìëð&úðåáֺʷäùîìû$äΨŽv‰´±Òø¼j“ &C/JXO]i‚‡yŒ„€nœ®™–“ˆŒptdb|…Ž›º`“¸Ä» ÄáØÓʹÍΓžÆÙĵ±¶¡³õ°¡Öó欱ª–¢²½ÆàÒij©›ŸÖåäÔÆ®½¿MÈ’•¨Þ龄ts`l{ebl|YmOö¥”–¤µ·¸Á–Ç¥S07=`k@=¢JƶIÞrŸPèíÞ€A†ëè(c‚u_Rt¡œƒ{ek‹˜¡ ‰šŽ—–“Œ‡‘Ÿ”Ž‡jqxB䶼·« •°ÃÌÓÓÉÌû +e¸ñ'g‘ºíëéñûøàÄÊÍ°¨½ÉÍÜÜÁ¼Èçà­£§¶žœ¾Å×ׄn…˜†rQg‰oI`oƒ³®qhlqz|‚”‘•~°š‰[SƒÇ?¥ËÚáĤ˜½Ðට¹ÁÁëòϽ̮¶»ÀßìÔÑßíź֞™ ÇÒ¯®±¾Ï¾°ÁÐßѱª³ÖâÚÍåíS°szˆ°èÞ¼Œrqbd{s_^x[WBÝwyš§·ÅÏʲVæBa»âÝ -¼Ê]×ýf¦N\ŸdJûÅn4Í"pŽ’†rm]^{sjhdDIVhˆˆŽ’¢–uo~Ž„|UI`wpààεƔ‘¥ÃòèÑ·ÂùDƒÜ5iŽÉ¿ºØæÍÈ·¼ÚÝÖÕâáËЊš¹É¹¥¯Â·³ÐÙÏÚàÆ´‡†’Cºq‰…‘mcfX^«¯gM`iH^Ž•—…›£iŠw-xîcÃöíÿ²»ÞÕ¥’¤¿ù&ûº½Æ»¿ÏäèÅÁÊÕûÆ™¡°ÁÐãïéËÍêÕغ¼ÕÞèùଗßæÑòê>ÔÂÀÉ -ùÎJ68Js`EC[PN+ÒŽ¥»¹·ÉÚïÇ]Ç’²3–‘¥žyÎ2{Ç,C›kDÚ¤ôÌiƒ]t%nŽ†Š’›„|{ˆ}inib[W€u~ˆ”›my‚bEXlg9ôƸ¯† ªÐË¥—µðlä[±Î×ÖÓëÿή¶¿­ÞìÔôÞÚ¨Ž›¬×ñѽ¹ÃËÝëíòܼÆáàÉ­‡È`¦Ú°…m‚’œŽ—V=spGHmŸ˜fe¢²wvxVT©o¥Àʶ¿ÛÌÉèÔµ¦„®åÏŶ´ÄóÚ­·x™ÁĤŒš»ÃâêðÝÏÅÍøãÅ¿îØǽÅÙÕ´ÜÿÏ-ì÷æ£Ñ ×l26V{n06Gjs\ ʬ³Â̺Ìàè¡êQ#è²$î1JKoÄŠáëJ -ýë5v ÿš_ÚÉeå êG_…‹„yƒ…ƒphu’‹lAF`mcl†‹’§—Œsfp†„z}uD æÁ¤jkˆ–‡yx{–Õ.³L—âýêéèü áºÐç““ÃÑêåò.ûÃœ¬ÌÍÑË¿½áåüùâêøøÙΛä5©†ˆ¢u_Z5toUs˜»™PdˆªŒŠ§˜›´à:€ž›žÇ­ÏñÙÉÆŽx Ÿ¿ÞËãõͽ¬q\«Õ¦u‹ËÓÏáÞ¿›ÀßÙˬ¿Ý÷Öº­ªÄÑÖõÿ-žïìíÞéó·uSi‡V/Ht|[ -ȨŒ•¨¸¹À¯éNá‹‚Æ6XK?]ûœñ=ÒÜ{(¼Ã¡Rs'YZt‚z‚‹•Š}}˜‘ƒ‹sHMe_h‚€r¨km{”™Œi8ùܶ°›€u`€¥Æ†ëêÛâàÙñ϶¹Ä²˜Æó ñê+þàѸ¼ÆéîÕØÓØÚ¼ºáòû âïãEÛHY"Ý«”|U[bi—¦–¬©£t]‚r€}‚œ®àôõ<v©Æ¬’¦±Æçר¢¤‹£±åôʾ³¸áÒbcº¹£ªàÓ°¢±½œ±Ï˺«·°ÅÖÅÈÉÕÎáøúëuÛÛôÚ±‹€|H'T`if\3üÍ’gj‡¨¾«¬œGÌmd×p #­®3ïït–ä¾ë}¡±±‹‹$~—¦¶¿ ¤ÀÁ¯œ´‘ƒuŽž‡vvhT]u—•ˆv‚Œ…hU=&ê͸µÄ»±´È¢°ê6pòs¦ÏÎì×âñéÁ°½¹ÉÁÆßøøÙ·¾ÉÎÔÍÚêáÓÁÇ⩨¿ÞïDã+o¥YÂvwo{›À£«½§€mKwŸƒq˜¯Í+ll ®Å´¨¹½Å³µÈ zƒ²ÔÞçϭöÏþÞ–¡ÒÁÒΨš£­¨ª¢˜¦·Ã¿±àçîöÚÑÝìý - ÆNàµâýóÁsXfeQ#RfF.2ù¸ukb¼È°¼»Hã§qS¾8ø“_?ÄÙuTßܟЫ嚯³¨œ!šÍÑÏÂÀ”“˜–”~_j{~|„„{‡€]px„g^lc\erf\ed@þâÆÁÅÊÅÅàßã0· -€Ü¼§­ÂçÔØãïÒºÌÅƸª¼´ÊøÚ´»ÛåþغÑáÅÔÛ®³ãêÔ£¤Òýô×\ïbåâÖ¹‚'ªrˆœ£¢’©©Šfh^ŒŠt‡³â<´´Á¯­»ÇÍÄÁÇkˆºâþæºÍØØÇÎÄÌ×Ñíò ï¾›¬»ËÊ´”£¾ÂÈÈçãÙ÷â¶Ê×ÕÒø¦¸¯âñɪ¯›L;G[KBG]tA8>ߊ\jm¦ÕؽÏÅ 3§‡|oËQµ`Õ=)/ôÎõ›ÁcɃ¾ËТŠ²¼¯“£ž†–¡zzx}}€_Vs‡p\hnTAT]Q_smbnvd)ïÛ²«¶–‰«Õ]ù‰ÍóçôÙÚîîûÿäÆÇØóÿÓº·ÙÖïòåùûõ؆Œ›— ²¢¿óãÉ©¿ÖÏ¿²e+§ ôíÎpǶÐÊ®ˆª‘sy‹qhx£¡¤Ú'¥É¼Àɶ²›•ÈÑÚɱ°~’¿çåÀ·ÉÑÊ®²«¥ÊãÕ£ ³ÕÚåçÕ–ÇÆÑÖÏ¿Òå×ÔçäØÞ⸊ -´¹Ùššmd\[Va‚pT5Ú”qz¦ØïàÛÙ« 1³§ªÎ¼§º‡Š6ÞÞö1ßò±ZǘöïÀy—”šyrux…~ˆ}xyzqw|wy„r^\mgVaqhkneCQchN³›˜ª¢‘¬ñ;‹+Áóû üí þ -ýÜÓ - ÙÑÝóþþþçÕÖœn™®¥¦¢À¼¸Ñðâã̪¤@BÑçêæ²™x,æÕÌšŒ³¼¿µ¦ˆƒªüúó\¶ ˜Á°¢ÀÉÊÀ¹¹¯ ©¸ÅûüЭ¦®ëÿ -Ú¦žš¡ÃÀ¥›ŸÈèí¼¼°™ Úèú渻ç̽øúØèé­•|ÿµÒÔ Ÿ¦—žyeIU_o¥¡œ‹^' -ݬ”žÌ -ÖÀ«˜%[öÙÙ;R׶–ùÕâðh«Ò{È¥;½ž9’—‡iih_y€xqavŒœ›”}mf]kdkokbhsTW{tVUQId1͹¯¬ÄãøNˆ,¹êéÔæâåâ×¾º»ØèÒÖãìØäÝÏÛØÚàâ囤½ÑŤ½ÕæÈËýܳšrpªü÷äýÌ·¨vG#ïÇÁÆöúëÛãJ‚\VPky~¦¯Âµ¡¼½³¬ª³µ¥°ÏéëéǯÏÎÒòâÁÓȼ¯ÉË»ŽÔçáĤªÊ¿æ÷ïÓ¼ÅÓ±ÇÕËáøж¾£Øð¿”¼ÅÌ„RH6MwŸ£rB7Ä´¸Ãâù¿´œœ@dèÁØx¾À7=}íÚü - -ÈMl£¸O-LÝÎw ¤®¦€›Ÿ‘«“•……‰­µ—sp~¢ªœ~xhXQ\\_rntb>G'íÓŶºßýV¨3ËŹ½Õùþÿ굯½¼Å•šÛßáÏĦ•›ÃãéÌ™‰™ÖòÚ´»×ßÏд­²¶?\Ó ÷üÊÝëþڲňSPHYq^cw™Ö¼ž‰ehŠƒˆ­ãµš¦ÂÕ¨¥²¶°¶Îé·¨´ÈïðÛвœ¦ÏÎËËáϲžÃèÓÒÎë¾ÅƼ²Ìâ׻ˮ­æùÑô´# Љ£ÜÕŒ\SD^”‡k]MG\Á³´«ÇêÍ¢—œ§'4»±æ´J~¯Häå $"-¬°)²ÌCB¢ ß’ÃÁàÛ¸¯©“¥¬·´¡‡zŽ¡±©‡” sZDC>UiokUWiŠhBíº»¾Á¹Þ!¥ÒÚñÞÝè ß¿« ¶¯µæçîêÑÊÜÔÈÎòÎÌÇ­ÜĺÂÊâØÅÇÕŸ0RÁ×ÞËãé $àÈÇ®—·ÞÜÖɳºÓਥ¼‘“‹z“ìê¢l…·ž±ÂÀÃÑ®Žlƒ´ÔÞ×ÚÇœ¶È¾Ä·ÉøÖ¯ÁèÖž£­ÀÓÞר‚Ž»ËäïÎΩ™¿áó)§2 㸳Íûõ¶~YY‰œ˜e<Efbý¢±µªÏãÈ¡š µ)AÑŸóëmFöcl -( ×®K*™»+:×¹aª®·Æ®ˆ†ƒs~¬®°¢›”„ŸÈ¯scmYQ=DDfoUmoYWx~a;%û½¬²²Ô/Ô_©ÌÝï÷ÛÈÃÖêÜÓ¿•ªÚÕÉÊÖêââýçÖÞ³®Ôó$ÝçðÚÁÓã¾Eõ6òì×ý?öøèol–ÉàËɾ¾Å·©›´¾žn‡Ç˺æÓ˜~™¹ËòÃÂ\h˜¸¢¸ÔÔ®¦ÒöÑÃÀô åôúÓˆ„£¬Ãñýߨ©Âº®ÉàÒÈ˸¾Ö1 š4 Û³Áå§}`y™˜{NR_‚…"Ç‘Š€©ë褨³»ŸƒÉãp —]!|<$ /5 úëb‘}Þý;Ât¦Œjw©¡¡sok‚‚’ ©¦œŠ¢”\@`]R6EUjw\m•U]‰‰^ ýÇœ¥¹øQò‡¹êìÑÅÒàÀÐèÌÃöÑ¥ÄàÆÐÉÑÐËáõâÈàÚµÇòÿöÚËÎïÛ½Ž¤ŒP DËøîÊß×ÎÓÔ³šjv ¥œž­¹Þº‡›Ã½´“Š¾üëƦ€q¶«¢ÂÝÁ¥ÄÓ™e€°‘l“ÊËž²ÜÿêÀÈàçò﯋š¾ÎßãñØÏÅËÎÌø·ÇÓáÞî üì–2 -íÕì'Úžmn‹†ƒmaYYi[úÈž|q£Ðñö×ÆÒ»½§rvÑîI¬þÊåp< (#ÿ «šÖ¨ûróGÒÒ og«¨ ~ikR?BK‹¶|ijfQNFG4?\p‡…isA6Jw‡ZµˆzŸæ5¤D›Ãèóôßîä¿Ëš—ôÒÉåìÊ¿¸ËÖØîО­Ü´¿ÜÕÁË´µãÓ“_xm´£0’¿ÞÛàíÄ®­¹´˜r–ÁãÒ°„Š¦Ýïʺõêδj´×ÊŸšŸ¤ßé¾Ðã¸ÍߪŽ«¿°“¾êËžÀøöή¸¹¿äóã¹µÔñæåþéÛËÌØƸ»»ÇÒßâôí¾˜E* -6ß™yqoq}ynuN[j;óʯ¨ŸšªËâã”jpcÓâØL`È}Jÿ+Xøù³ß;ãÂóÀ·Üö⨉„{˜˜Šw^OPLq¥¦nkn_Q]ƒ•|lv|sgE&(Ng^0ß›€ªô9¸G¢ÁÆîöîĸ앶éÀ»ÛÚÕÙ͸¹ÒÒº˜¥Öر¼¸½àòãÉ‘F-QEüˆ ÒèÉÕçνÝÉŸªžË ⽞¥ÝçÜÜíÄ©­…pž²Ã³ÌÔÇèí¿ÏÄ­°³Ýø×ÙüÕ«¥ØμÂÍÓÍÿòíÞÉÓðÉÑ÷åÚƸ½¼ÒÒÝéÓÂýÿçÍœ^9;9$îšk{^dr‚ogkm<𼤧š´·ÚöøÍ@(xˆÚÃ{†û`ý»¥yA&o´ûËž=7EA ðÿïÕ½¯”}—¤Íª}hhms{x‚|qn]Zj—¨zTbK9<<5##% í£¤Èí•4˜ËÅ´±ÇÀ¦³Çèì»°µ¤¶ÑßçýÖË¡¶¨ÓìÇ¸Ö -ÖI.UfVÞ¯ºßßؽ²´áòÔÑßÎêñš–¼¿ÍÎÐÌØ«›®¦›˜¡ ÂØüÜ ‹¼ãȱîð·µêãÀÔß»±’‹”˜ÒòâÑäïÇÊÄÂÅÕðËÁââçâÁÌìÓØÇÎåÝ×ÞÐÏȲƒ=G*á¿~we7Dr¡‡{‡}u/Ì‘‘”—¹áïÞçéË™y–í¡HYø¹¡žUéŠX|©ûí4Ô]ûFTp)ñʼ¿§¨Ž…–¾¹„qkyˆlV]nnjmfxjhrZCGKSTD ÅÈôî鵮 -bÇI¸ðýÙȸ µÅØËÓÔýÚºÇ×ãòïüÜÁÊ¿×ýûÜñéé˘îÚ’'":cž­HÕÿx•›¸ÏÏßÚàÓÁ¸‘€¡‡’›µÒ¼Îèϵ®Í®­²´¯ª®é ç°•¦ËÑÌÍȹ¬©ž°´®·½¸¯†êݯ¶ÓÕÍÅ›ž‘Ÿ¸Á½ÊÕ÷ÝÙøÇ®¯ÎÍÎßöçÖÀŽ\\5å°dS\>@t—‰}Škµ™¬©§ÉøýÚÍÜƦv˜ÆQƒxŽÙðÑdÐJô»yÿøLÚKèAROøË㲟”|…iz¦¸±˜†{}Ž€aZho‡}cxYZŒm=QaaT:öÌÉí/øéå?vÒO¹ò  íÆËãÇÌÇ1ùÈÏàæÙ·ÝþïÖÍâÜ¥ÌÛ¾£Ë×£‚d`z•®{D+7€ÆèãÇÔܹ~|š¢ËÏ™¤©£¶ÑÈåëÀ¬¸ÀÉ¢ž˜ ¤ÅƯ™¢Ä§¦˜~y¯áÎÉѶ±Ú܉~¼Ö÷×Á½”u¼ÎÉÁ×ÒåàÖÍÆÀìÚ´Ô÷Ô°£« u7ß“[Z|„mqZS[oyb6ý¿•¨©¥È÷ÀÈé³¼Éxf{#ÙxíB¨üõŸüCn¹oàûùócå1 -ó«ŒÁÀ©¤œ{syž­˜—‡iL]pvg\_c[DDR[bYEYrd]C"# ( *qÚEŠÜ ûìÛÜű×öìñÓÜûð̵¶ÞÛÌƾÏ×ÕÂÏÜàüϬëÞÙο¼Ÿ‡r._ÌöôÊÇл ˆ˜°´¬ÈûÜ–Æɯ§´À¬°¤¡¯ÇÊ•€uv€´Â¶•§²­¯‚†ŸÉ¹‘š±» ©ßÖ¥•¹ÕãÔ±½Õˬž«ÑÙÙ³±²´¯·ÙçÝåÜÕÔÞ¿•’ž«ŠQ -Ñ’jr‚„g^GDS_d.ôÄ™›·¼û1ïµÎî…k|93…3 ÿ}ðLrc]X > /ºÓøõüdå2¾õ¼sQn­¶¦ˆ„palesŠŒ}S>^lin]ODB78?Ah~‹†ŽnCDöÞô[³x¤Úèãßýќ£áå»´Ø貇’ºêÜÏÕÎÕäïâçôï¼µé ÷ÒüùãÃ’ŠcL|ÐóëÑ‘†œ¬½«”ºóßÀÇúÙªœª©Œ½×ØÈ»ÀÆ¡˜‘ºà­Š²µ‘m‰¸ÕžPlÇÈ¥ˆ¶ê»¢©¯ßÌ‹y£Ö½±ÂËÓϹ¾½Ÿ«¶²¿èñâÓмƾ²›„N Öo\dc\ppupxSù½“™»Ý #úÏÙÎ* d)4–HSG¹Kk 7y ÚÂðîê~Xî2ÿdþCPUeWj€ƒv]`~d(,CIT^RQ[PANZƒ£‹•˜‘™q/ìåãüøiéc‹¾ý üþç×Í¡ÝΚ•ßÑŸšÍùÐÀÌÀâõäƸ«ªÂ®»ÍÕøüÓ²©Žs-ä5¦Ô¾›«¦“Ÿ¾ª›¯ÒäïØÍ™•³¯·½¤ ×Ü®¶³¯¯½ÉÑ¡j‚›‡ŠÍéÜ—MS~’—ÔÍÈ毟šŠ¡éöÔÛæÍÃ˨¦¹ºËÑ·¬³×íØÝÙßú¬‚ySÜ¡lNLU]`kvk]9 -Ø¥ž§ÌôõޣȼI,3‚(ûä=™à(A ŽçPÀ’äéï¥-bŽÎ!ë,Ze|”©¥~dc`^eEG_bBI_ggt~v}‡zŠƒ†¥w:& æÙë4œ(zßüþÍÀÐßò´ÂÍ×ÙìôȤ«Óýí¼¿ÏÒȳŸ¨­ÎƹÊÇÀÖäí˲ˆŒY ~³¦¡±˜–ØÚ¥·ËßçÇ‚…´Â˺̨»¸š–Œ‹ÉæÉÀÌ …—y¦éúܯtM).`‘Õö½´Ì¤¤¯‹•è6üºÚ×¥Êê´ºôÿäÖ°™ÇÛÅÒÊÕ -ÂrPRHÅŠxnnbU^sZ720Ñ´ºÈÚúÖÞíÃdWf0 A»L~‹Ð4ÕõÇn­CÖ|à«=m­Ï7\ž¨«¥†Š´¹Ÿwfed^Sg~rMBUn„‡¡„“ˆ~TfŸˆf>0/+ õíý 4Š|ß  óÌÆ·¸ëóß²°ÑùðÍïò¿¡¹à×Âáåɳ’·í -ÜÎäÞʱáìÅ“¹Ý«[T•¥‰‡Š€ªÐ縲ɺ¸¹Ÿ–ÈéÜÌÊÒ§®µ…„–²÷ùÎÊÓɿѱ•»Þת‡UGWØÊ™´¿¹¦­ áÊÌÀªìðÓÒôùýýß¹´¸É×£«Ä§Rú°t†Œƒ‰†bSR9.B%÷áÃÒù#í»ÀÇ  -êXCK$.‰Ý½‡©é+Lgm;ö͘_HÛóÚˆZu•Iæ9¡¬À›‚t‘£˜†hZzkEM]yxdWz“‘”•‘ƒa4:PGVL;?*"&•c´òû¦‘ª¿ËáìÊ»ÌéÓœÌðà®ÈÒ¤•Ï͹»È½°ÙîÍÓ×ñóÏòè´Ãú¾sbhŒ¦®‹z”¡¾ÞÕÍÔÁ¨¾çùûäÐÖ²·²”ÃÌÀéñ¸š·¿Æ»æÃÄáDz¦ºÂ†¦ž±Ñçñ×ÁÀƶǹÌîæÕÐÊÅñòðεÏÞη¼Êç±v‡ •K ýùìÈ‹„yf…`;96G["ðÞÐþ[©ˆÅ¨–n¹ÈiO1&?„o!ú&7?TlhWHF&ö¨áȨ—uÍ]_”۹Ѵ’†|„y_Rku[6Ch‘~p~z‚€‡oOH;DJ-;LB5(!+& -pÅxÛñÁ·ÊàÙÆûáÆÎ̱‹ˆÀÏÀ¿ÏÜÀ¾æÑ´ÀÜÅ“ÆáÿîÔéæÍÄÅÝûå´…b+e¾ÃÁª³ÆÜóæàüáÚÈËÕÉóýÙ×Ϻ¢Ý -èÉw%Bk„{«åÎѸ©¼Ÿ¨¸¶µ ›œ¨£³À¸£²äÞïéÎÒÃËäý úཫÆϼ¾Úä™miûêëﶢHI>LJI8Kcm×ÌÓ3Ëžû …Z…Ò‰B++IT&Þ¾°ÊÈÄî#, -‚e³¸½Äš±-¿ -èiÀÞ¿žz}r|r[\L><@c|z‡~un^XaYYrb_bhmcM>$!+×éY©ê>˜ÑßÙÜøøÉÑ÷÷óÖ–•©¹ÈÅȳ¥©Ë×¼ÄÝÙ¾ÅüòÖæð¾´¬ ¢¼ì׌iMàj¿Ùþ æÞÅæìáÍÆ¡“Äýè­¹ÔÐĨhû;KQo¶ò¼®´¸»´´®©¯§¢´®…¬Ò°·éôàú϶ÐÅ×åîÝÀ¾Â»Ï·˜³ï Ζ¾”ÚÑÇÛÝ«„zW?UPQDMTx…^ƸÍ%¤¹FË´¼I^Ü•M0HQ&äÕØÇÀ×ÁÝóöùöîåð]I…Ë·µáùÓ×9ÙZÂÙÙĨ«¯|P/,.1%&*3Yc]e^jM;NWqog^ƒ¢¥–}oJ!óÒç`£À^èÝæòøèÞñę̀£ÅÁµÍÚÝ«•µÚßÄÃÊ´ÅÆÝÅ¢ÂÊž¹½¬°Ÿµ±ˆEé ˜æãñìáÖ½î÷Îëã×Þ¼‘ Ì!ÝÊÏ¡£ƒI ö#~|s£àÑs˜ÇÁ´ÆÇ¡µÀ»¯®²¹õÙ¡¿èýþèÍźÐÁº¥¥¦¯À¡¶»²Í2ú®¨±´MêÑÉÁÂÌ›qOE`wne_ft{xUú´­Ñ=+ѨßùÄ:@Ã}2)A2îÃÑáêûîÏ·Ìæ! ULìî—¦¢ÖóîˆÖ7­ÑââÊÕÅŸw,ý)GTZV\K+EVHMwˆ€‹»Å«–pcFüøh†‡¥Û_¬Ëà×òûÕãáûÒúÌ­Å˽¹ÂÐÎöÕ¤¯ÛèÃÔȳ’ˆ§µ²Ñ¼¡|dWr½ÀîÖ»ÔØ·Èß¹äñå¼£ÎîÙä÷Á¯€”gR ?}†±æ¿“Ãϧ»Þ¿£À¯¦Á®£Ûñ³¹çǾÑÔ¥‹®äÔ¥ƒ‚¦Èª¶ÈÞ"`?쮜‡Eî×Ƴ†_E@eZ>SgzŒt@×½ÉÄÖÿüÒêéÉ)2§`AB<ýÓÏËã×¥“•Ç%Ú‹¢å\žÚ:OÞýÿŵ±ÇÅçiÿíûA}}vtnA+naVUl“˜‹Ž™Œt„xi\A3_rWOfÀòc¸ÒéîßåàíóñöàÇÓÁ²ÇàÉ«ó6úÎÕÕܪ¤Å¯Ÿœ·ÝÖÐÀ“xcüZ€{¨æÇ¥”°¦¸ÝÝáܾÌÇÚáƳ‚vteWŒ™‹^7Hqh{•›ª²ÈÝÒ¯³Ï¾¾›^“Ëη·¦Ÿæýßâûͬ§¤œž~x¯³ÇÑµß íí#úÕ¿€=# <(ïâ­qaOOrJMPeŠˆq4÷ÉÌ»«ÌåâÔéäÖ¾û'¹gm=ÝÍëé÷¹~‡¯Üî*ÍŽQ€ÞÙÈ›ÑU;ñoµª¬¼Êã¾]üèå$Iwi^fP=5%7giYbib]xxl{š€`J._[õ–àã$…ÀçÖÓÎÑèåÎÑøüñÙãíçÊþ þÛÙÏÝßÏ·—ÚèÇ°¨~aÝ*Ax¡Ç»­€¨ÔÅËÓΩ¥®Àºpp¤w;kgƒ‹j5!Y„™Š”¡Èùñ²««Ä¹ji£ÓÒ©—‹ºþúÍÊäËÓЧ±¢©½ÒìáÞ øáíçÖÈêÏs&ýø—[`a€|wpz‘žj6û¼¥ÅÆÅÜÜç ¸À êÀ}<àäÿ𾘕¢»×ê<‡%gŽ$u}È `šR’ÿQ}ÀÑÙÖ´FýòñîSb908RFCL8Ny{ƒf|nOf‰Ÿzk‰‹}m? >DôÌî9v½Bg~zt¿¸°Õí ïÚíûíôäÒÑѳ¢±ï觜“¤¶Ç«|1é³óü]e•ÍòØÇŇk‚‰••pY:-d–g=OahwS@Ÿ›’–¦ÇìÌ—›ªÓŦ¿Ê×͆…Š¶Ó½¯µÆòæØìÜÇÉÊè÷Þõåö×ÎÄЭl' íáÊŽbo£°’vd†oa1ç¾’d–¿ÁÃÓîç Žœ&ùÄq(øíîóïñüþòÐÒÏÎÓëý/f½l…Ü-`±Âhpñ"ý+V¾ÞÖÌ~ÚçõGjUIRRUWQ\k•˜vhyoV]bzhYkzP`h?&E;æäæ n©ªÆXš”Œ­ÉöôÓÈ¿ÍííñØÆÕͼÅÆàâ½Á⶜¾¿‹?Ë€zt±âá½Í-I]P àçÎÍéÕÞø' -4WKB=C+÷;|¤·­«¿ÎѪ˜§«Ìû'àµëÖªœ££ªŠ›¤…ÄîÎé çÉãðüØÈîöÜíýìÎ¥’ƒLúÍz‡¢¹¸~ZLmh7"þÉ«—Œ›Âø#ãëð×O‚ì¾\âøðæàíôùüïççÛÛë(9JϦ /d…òFƒZœ!%-k½Ô¦8ê½Í>t–lSG[bqaOYri_s•hOIeo}zVRpsA%'#%ÓÞàÔô Q ÕÞ÷Di_Jc¸³¿Ô·¾Å»½ËijÁãÔÜãñÒͽ dRfX3Au}ZVudtŒˆ©¹Ÿ}°¿¿ý-2W[RW>U[/f“¬ÙâåسÀ·«³Ðõ­»Ûª¤Ä´­ž ‡—ØçÝåãÞÙÜàîçÔÀ¨¢ßëÁ³ŸyN"-. ê—Xlš{‚aZ_d5Ðœ¨š¥î”·ãûÕ#fÏdýíñï þôñûïÖÙø$QAÁ›Ps„|¸«þ, …Þ¨-óêò!G>ax‚zc^lŽ¥ŠiELfer¤µ†[Ea€ƒumZuž£].) -ÕĬ¹×ñú/i{žž¸Øñô-5W’ž{…•¶»»°‹»ôÞº¥“¢­§pS%²^?$)YU õ/:C‚ªž®Ê 1glVr~”À¢‡š‘Oœ¿Žg—¶€j›²Ùꦌ¦ÂºÙʿʧ̘—ÁèÈÂ×͘¦˜¡Áº°ÜÙµ±ÌÞßΪ¬‡“œ«–{pa_Éü›dMhsb`Wi—E᜙ˆ©5éÌ#ÿ."²ãlO ÀiôÝù!:D'!þÞÚÔÐÉßúü Ϩ݌vek?Äðñ::ò 1tŽZ -6-MWWXOvƒnWv †wWHOciPvweS`|„wch‡ÀÆt4&êÔ»™¡ËÔÎòý"":j•“œÇåÑëCAi¾íë÷åÉÓÝ¥ ¬‘sz…t^m&ÛÖ7*9=s|¯ÇÝJRg¢Ô¼ÇÍ¿Ò ñÅáÙ˜Àª‚“Í -äµ±³²Ë°¯ÖгËʺ¯—Îà¿™»ñìÿû»§’—«—™¸×ͬ«ÆâÂÝã¥xŒŠ†s^ZS5뤋wu]YgeQB8f°ˆ1üâКq“À;˧1û\¡HLø~D6ý!TT!ñèϺÁ©Ëöÿ j>ôÔ¾x@ìDˆ¼; )-<U@EH:8Gkm[BK_KRarVV`FG|vncu€m[~›«Šn=ÿÿéîíáµ®®¶¶Õîþ,I_peˆªºß >—¢ØÜÔÃœ‹‘‘qdojRßxøöÕZ á65j²ÄÕ¯š½ÐËãáÈÏÌÍκx–Ïô óÉÈÈÅðùëËÏÖ¬Ž¨ä濬¾Õý㻨›©Æ±·³ÉìøçÓëÍ·ó㟃ŽmYU77G´qr[Tavp_OHQj…‡^ ÛÏÛª‡Äý@ut9ë–å_iVÁbH<''90)üÚȺ¶¹¾±¢²Ô*Ñ_&¿%Òµ10ÍN›ÍÄù?QA:OZ`\?&%<RV[N;V`w†wdjc[cx…š†sy¨«xS -óê꺞¯À¹É×áñ"/¥«¼´Þ1|®Ç£¥¦”’l[[¸_ÿ&\®ø]}~’áÓ’–¢¨†‚œÍðâÎÐÂÑãʽåõÒæïÏÓâÁ¶¿Ò¼»´œ¡åüÎÁ›¸ÚÝ×®„„¦ËÐÅÕôûÕÔ§ º¡ƒuL0 &,&êkClvd†ŠRNr}‚m?Ó¿²ÎÇñ '@.ÿïÂRÒ±åv¦VB8#/3ùÓÇɼÑâ໩¶ -—>øŠˆþ8©Å.×¢ÈVfQK[7#" /SYQQTo~tŠ–ŠfVK7g~m„¨¤³É«†ƒn=îäíãÔçõôðö (@ MO*8o±A^bumDD6ò¦dQ0!50OX_’ÉQtºÍµ–ËúèÕ³Žz†¯ºÙ×ßååѬÚäÌßìÖ£Ïá±Îá±€hzźÇáæî‚›–™‰ˆ·îúÝÉáùúóñݵš´¤RB&ýûéóèà£REc|s†‹c|®•oQ×µ®Ÿ°üGMCÝÅñó¸ZE|y›²U!!L/øÓÆÈÒ×ÍÒÑÊÐÒÃÒp9tï"C_ȹùLÐÁÝ Bcla@%CRjwkdsuffgŸg71D[nwv’¡¡“·×¯”^#úÜÁÌðû-9FL*$2LGúëóàɾèùõ(j„•¾êæÆ®d.PK3@CTy„þj–¥¦ äðšÂöß×È›¥æù¸Äݺ­ÛÕˆ¢âíûðÒ¼¤½òðÍäÅ…{elŸÀ´ÇÉÞ㹑‰¤°­–p}ÐýøéçíÚ»¤¶±‡vˆÔ‹ ÑÈé öʹ¶€TH}“r^ˆ²¨^' Ü—“±¬çKt™z ijâßÍ:¸µa' ,ˆ¦g'õëëéÓØѼÁËÔæÀ­±×X#®”Ž:uèìÞ»MÁÍÞ÷'SD6>OO\€‰mpƒˆ…pKVkaos„hbd~Š‘pik^g‹Œ\ëÝäßì1:AczF(8ht-úåÏÛå =E;O$  FxžŸn>GI( )ŸÐÒ»³ÓÉÕ¤ÛïãúãÉÔÞØßÿعÉÖ¦—ÇÁ¨µÍåز‚‹ŽÔàÙÑÀ–•žÌÌ¿¸£ÊÐ|~Ï̹£j·äêþçÐÒ´›¾^—+æÀ«ÓíäÅŸ•˜€_e™•sbƒ’‘pL-ƦÊÓ vÆËgë°»øq¦K‚n¸zZQ’çÉt+ûöõîéÖÆÊçýêéK -Ö -Þã>ÿìas¯£Óÿ (>iqjzˆ{M?t¡ yUSSLFi’”£›™“…ˆŠ‚‡yˆoDþÙþ&ïó%:wš–‚¿Ú«ˆŽ§œ±®Ž„uSU^{nq=)Wˆ~¶B34šÀ«¨Òпçõ ×ÎÎÁÐÉíà̸Š€°ÂÁ´¡™¡¨y–›£ÈËÇå½®¾­¼°ªˆŒ–…{²Ú¬{˜™Â ùßÑÈ©ÃãË̲_u­”Bì˽£©²~nmy|o`„•_s|eW[RÏ¢³´»)á4ÃEâœÊ "pÓÐ>2?ÇÍÔ6Å|< õñëÒÏå 3 ,r©:&̵fž²/2ƾ쉒é4-*4G\^K1EpXQ‡Ÿ…uSPTEOr“ŽŒ­¬›©°œ–Ÿ–f4)9*óñ=a–ß$<IUSIU~x[\sd[O0üã¾Â¹¾¼¼Ñâþð7tŒaKÈÓ¦•¬óéÿò¹ºÁ¨¡ÉÏÞЗ„—ºÜ䖕ûÁ¯­ÔãË®³œ²Ä¬Ãܽ˜‡­Óº§˜ÃáÁµ«­ÃÛñⳇ_€ ŠSÓ–ƒ’’uKUoon{•‹˜«oi€{xtIòÞı«Îd-…ÿ­«ó3gÌé¼æÆ,3gž¸eù®ŒG -öíìçâù,%;L¯7˜yGÑ™ -@z 8'8ÎÀí8S/0-0QZ4O†‰|nTM¦¢…YVQ=[‚‰‹¦ÉÆ©¨‘dZeXN7 ',9rÅw¨ÕìÔ§œÝô˳åëÌÈ‘–°º•„pv¤­Ì¦œ§rœ•³ïòÄ»Ý! ᶼ”kœÍÈÂèíµ½ x°ÃßÂŒ®Ë¶§Í÷ÞοÇäÔ¢®ÁŽ·Î™ÍØžw–·àöãßö ¶”§¶×éãÿåoAP|“cS!Ó¨¡¤–pWb…¡®—“Ž†s–°®Žt@ãÉæÁ—ŸþÍxÒºð=‘ÑäÀWQn}áûË`Ìngb?ú -þô>V6-;\›|VÜ„ë¸ö÷w4|aØÑç,VO9+Yx†£¦šy^GdŠˆ‹…z‡€V`‘~t”š‘Z7 0øìåEr·ÐOß÷ìíŨªÏôæÝíëÑÈÁáï;=FúѶÂÞêë΢¸°ºÔÔÇêè–c‚´ÈÙÚÊÕËÄë•\`¸Ô¤º­ŒÄè·Ä¼¥ËÍÌÑÕÑ®±œ™µ³–u*7^Ž¬ý -þÍ•±Ç¾äþàá¯B<e•šza:íõ¥ƒx€zt Î³†rn|˜”‚‰s^ÓÎÇ£y«4{C ûÒâ2}¸ÑµgÏñ‹Õµ%œ)0 ùéì  7e_** .{|+­ ÊÚ’*®Ãé¬Åö&=<--AMs™yffdƒ™ubƒŽŽ›€r™ÀbkdIB(ãÞñνÈô!KŒÈ÷8qÊßÁÛæ­³Ãõ$ýÖãÝÝûÖäø âäÍÎÖæê絤µ×Á¹ÈßþÖ‘~‹§ÑìóàΨƒ¢É£y‚¸çÒ•œ Ê¾ÀÒÀœ¶á嶵ɫ”»ÒÊ´ŽˆôBŽÑßÚÎÙäü眛ÑÊØàÚÁ:Lr‰¥]$úæáÉ pp‰{zŠˆ†nTVˆ’cg[X=åÏ®˜¥j;øÙy®žŒJϨ¿ÃQÏ€Küæâñ ùü7TD6WÌj·œ»u˨Þc›¹  ÷Ý'½Äêý÷û( ._€’–’‚™ˆlŽ’ƒ‘Œ•´§ƒs>êåäÜѹÎF’bx¨Ð߸ œ’ÛúáÒçñîÍÖóêîò×ÛÕßÞáÔÜçÓÍ˼ÍíÖ»ÑËÑÇÀ×ÛÇîùÌŒ¨¸Å­¥ÝíèÒ¡’™ÁÿæÖÕÇÚîÓ±µÓ»±ñ å¾Sï4ºóܘ–¾¶ÕÁŒ·ÎØòº‰qB*Ri„Šdôá×äÇ«ˆzxvofObmScxdPVYLùÕµ²Í(xh ÿóå |¿­7¦üvXF}C- ôéÿ*4)%4APIP™é ¼ÁÅ„çUNü’jzÐöñjvðßØÑÕÚÞ -Cq‡•¦­¥¢©›Œ˜¬¤ ›„r’ŒoU%ýüîõÜÓßçý 1x X¦º¿ÎÀÆ»™—¼üãÀÊǴϽ¨ƒ—üˤ»ß¬·Â¿¬¤¼ÊÜÞÕª¹­¸ÏÅÜéØåÚÛ½‘·Ñçö½ÉÊÊÇ«ÅÌßÍ·ÍãûÜÛáÛÓÇÖùæ¤iðS}°™–¹´¥¼ «ÁÉЫN4@k—N ÷ßÈ«†žˆ„‰{dKkzaUb`O.ëIJ¸Ó%‹˜s4Ðá9¬ŸP -ƒ²³¤u= #* ó#TOC?RmœÛKž4Bçá™14Q%¨0Ò'<Ü°Üħ™¤®ÅñJgou‡­´££œ‡†™jCC1þçôøóæÛÛÑé.\›,¹²¶·½ðùØØôöÿ¶´ÚÍ­Óñ ïø⽚˜Õí¡Œ”—¨Á»ÊÍÌ­²¥¨Â¦®ÃÈ«Š¬¶›È õÞÝ[˜ªÔÛ×ðâÒæâÑèòå¼ÈàôÌÇÉÙøÓŽ>˽ Ymj¶ÞâËeq˜± Á·f 8¦°…I÷Ø®zgCLŠ•“”›hKa‹ubafi/ä­“œÂè@©¹q*Ôà WBÛv„ÕZ$ô èÚàèé;VB^ŽÁòJ¶$k»d?®'C$7:¸âÙµü4;øïí•œ¤—²ò"*Ajx{ˆŠŠ¥œ›”{}Œv@ØÏâú ùö ôüMŒÁgèÝÓÓÉÙäææàÛèæ ™³×ÒÛë))5 -ÕÚÌá¿ÃÁÆÅœœ‚”ÍÙ¯ÃÔÜ漺ãóþ϶±È»³ ´»º½±Š°À²¹ Ë¡·åŹºžyÉïÑäÌÜÑ­§OÀwË7{}¤Óêß‚8^§©ˆ“NîÝëu˜R3 ͇e<1$W}|‚”tnRTtziY[V¬Šp{£í{ðÇDìÄg-k´]­Aúêï üõÍ­ÀÎÕò&_…ÁåB}¶ÉŠý©X¥%SÙ÷Þ ˜…4%úT"ººÆ±´ßõõ5Fqvu}gŠ»š¡”y’x6ÿèýþüõ*z¾òG¿ìâëøñï¹–š¯±ºº¿¼·ÁÄêûÓÒÞØåÐÇµß â³›sš«Èéúù¼ÁÍ×èâÿÅ ¾ÀËÊÔÚÇ×Ó¿«’ºÏÑéåëõϱ¦ÁÑ®¸ÜȺ÷ÑÆåÍ·”Œ–hà¢ÓX{‰ŒƒonŒwe> &ËßDˆ=êÕÀlGO9&ISnmQv¦Ÿ›wosng]^(½{VdÅYᨴÝuÁå×w\+óôõíðîèùÛÀ°ÂÙõ4}À-@Wfr`¯+Ñœaª$j&›À4”\)ívsàíæÒÈÚÝØáò 5O[šº‚‚ª¨£Å«|TI æûïô/NÞWoŽÄ žÉñÖ»¶‚ˆÇÍÀâåìïîÑÎÛàÕµe ÛÙÂä౬³©¹¿û ýäÀ·«ÈáìΫž§º¿¶™¢©¶¾ÝöÜÀ¾É¸Þýûé°œ®ËËÕÞ éêøÜ­ž­—kÞ¾ Q8(9}“m1"åÉ»À4ƒŠs;Þµ«qB]|II¥§Šw¥Â¢ž‚pNNlJꯩ¤“žÿ‘êÛXÆ¿@Ô¢v0|'/J;òêðýD6 ÙÕéòM­ NJ' ú:rDs…ýLy5„è-A«$Ê Ûßþåå×µ¤¨Ò×ÍÑ*/aš¥|WF>Sz“e)×ßíìïú 7uær°Ðóàš€¹Ëµ¶³ÄñÞßÎÑàßÓÐÁÊÒÞÕ|f¿òçȶ˜«ÉÒÝħ³îíôÔ×ÑÈÖÒ´˜©®Ðíöâ­¬›ªÑÞåÞÎÉ°ÐÒ­ºÑµª¶©Âüûè ¿Ž›ËÓ¼µÊƪãï‚ߘ¥ÔÚÒêV]ýÝÓûu_篚’xy}„js±‘xŽÎÛ¡‰‡xuymKPÿÊÀÝȽÒ÷5{eÍ8ô?›H+{ô*Q@&üçâü'IA÷ñA…Æ -5 ï—‰zááöR–tÎÍmZ;s(Û|ÄÞôödCÈË¿¨œºÍζ½í%% /Q_EãDQ:ùê½ÓéÞÚû)Žû_œ½ÜþýçæÚ¾²ÁÃÈÅÍÊ£–Êßß׿¡¾¾Ñ÷À—±ÆÒÊÅËÀ¾¹°¼¢§äùçÑÑôæ×½±´ËÝàÍÐúàÕèõÞØÁ½Ã’z†•ÉÏéï½ÙЦÉãЗbˆÈ¿»Æ±Π-¸PÇmkk±âÒ½ô#ñã)L·‹w–º¢yqy€h~¸”x•¬—nzurxfNàãðÚÆÑó*%Hæ—y„;.UÀÂeb(ýæÜáô-õ /T‚­Ñõà¿›c?+ÐÆ6Ÿ¶]uÓF¼ŒuÀÿN¾îìéŒx¿ÒÔ®£¥·ÅÆÕæî #õþàͶ´¹í J¨kŸÄÙÙÒØòéÏäÔÉÈÄ«¹Ò¿Êõý㢒¯ÝÍÄÙÜà;ÍÊÚôÓ¼œ†ª´¹¿îÙÇöùÈÐÕãÔÑþ£x¬áø"в²œƒg„­¡¥Þ -ðË´¯Å·ËÇËòâýÖáØ'òÞµc4OžÔðߣ²âðÛÓÚè⫯ÁË‘PPr†€‰—‘¢›rwdMXhQI=âÖÜÈÄÇÐú-"ü)¹]¤;1Þ°å§Ò;.ñÙÞæí *i”ªÇÖÆ…^=ùób´(ÒªÓ¶ V“Ç}ÂÌü÷ý¹¸úö ø®™™¥³ÈÕÅßïååþæ̵¤¢ÔCTgÐq²°¾É¼®º×øùìÿóèñÈ·Ò¹¼ÄÏØâÎâô×°“°ÔÛéëô˾Խ®ŒŒ›ª¿ÄØ­³úþÓÓÐ Óö/®×Ü&õܼ¹¥ŠœºØíäÅ¿¯¬Ÿ«Ë»ÌÛ½ßòÌ´ÕïøÚöÆÛOAE‹¤Ê¹¯Æͯ±ØÑÇØΤ˜¨©vVWuh˜·¯‡fm>8hsE6üɧŽ€±ÛõòÚ}ö`c­‘[TÐÃÎãÜëúú,!D|»ÚáÙ›Býýø¸‰AñmêïeÞ -ûæï\JúÎâíöí93ÓãÞÚß±Ž•ÒÉÉáÕÜîéñóàòÞŸ«å D‡¨ÝÕÉáç­®áóæø -õØåá¹Ï½ÆÖÔÜú Ǹ¤®š‰Ãøι·ª—¯é ᬬ°ªÍáÕ¶²ËèÞÀèÝÜÌëøÙѯUA‰¨œÑ ýðûÞ¬€®¤©ÞõÔãÚÓçèò ëÝÿãêü©ÑzYd—©¡ªº·©¡ÈìõÙË­‰‹wu€}‚zsœÆ­‘d4+N~q= -îµ{{š¾íû÷òÉðK¶ÿ!ÜìÝÿEÞŸ¨ÐáÚÓÛõ÷0,.o–ž»Öù÷Ït6!$$&-ólhÀæò»‚ÇUþ¾ÿÁ‡òàçñ·Ñ%ñûù宣¨À¿¸ÅÚæÏÄÑÖÂÚ÷öéîúL›:ÇûßßÐÑËÎîþïíß½²¹Ä¯ŽÊàÉà­šÂì꼸ÍØÈ£–ÂÞ£·Ô¨¦ð0Ú¾¤ ´Æãî䬔¼ßîðع½»ëãÀžl-T‹u™ñÔÄÃÍÄ´²ËÙÃÔÉÊôîÉàé éÚäÒ ézçšpƒ¥š›¯¯˜§¼ûÿ¶žŠŒƒrv‘ŠcU}šÃ«„ˆˆ_PX]cCáÕ¿Œ™±àóåÝãê,ŽÕá”ÊØPêi稳ÕÏÐÒÖñ$(6J`›»¶¶ÉÖà³nDAKE6-7!„ÅïµJ9qàM†ØŸ?-ò  ç#B -û׏ÑÛÎáîââÁ¨±ªÉêú$8,i¥þz¾ÞæíÚ²ÈùéáÔÂŽƒœÌ»Šz¸àÀ•umŠŸœ§ÏÚØ×ÙâĵÄÁ¼ðåÛÒɯ›°Îî ô侩½¼ïöÇÍ®ÕΛ³¾¶·ª±±™¬¶ÆçòΤŸ½ÜïÏžÄÀÊòåÝãÀ¿ÉéöÔæ àTܧ…ul’»¨“² ŠÁɲ£—µ±‘ƒŽ‚_N‚‹žpj„jWmoMïÔÔ·¨µì26óèí÷1€~B¤×éøiîÄÈáÞÝëü0+)Bg…¡·­¬Ÿ‘•Žo`[g_÷ùV˜ì£í4XèåujC‚ç¥×Ò æ,!ÖøðîðÔ¸µËì⮩µ¹ÊüCoy¡ g¸ÃÒÚêü÷ôݬ¦¢ˆŽ²ÒÉÑÆ©Çο£—¥œrsw–½òìÝ̼–§ÌïáÖåÒ¾ª§³Øº™‡£¬¤´ÌÞ½ Ð·}¥×ÝöÿÛÝÕ™ÂëÍÊ©¶×Ø«œÏûûîæòåо¹¨åÝÕèêÄy‹bx]k¤µ§°¥w€š¢Á³¶·‘xwtlt–º‡ibJquHQb[C.×ÉǽÅÚ%]PðíñÑ”3›Èrªº?Þ°Ñýøê-$"3=RlŽpW`xtWDLX.øÖÅþ/-Ô­¹uñœ›\·›Î†­¯óèäßw CA&í¤•©Æâý궵Áäl¬Åîn¼×ΩÆËàõòÓÏ®–Ÿˆ¶¿ÉÕÊé -æÑǵÂ×ᆵ ´Èæùìέ§œ­äòÜþÿŸ×Í¥¶¹Ž„m€µ´àíåÔÑò“~¾çÞð&øøÑ©ÈÔ¿ÇïçØÝÜÊÕïóÿúýÕ±¯¿ñçÎïé¡zà>rŸ­žx}zi—¸£‰~ƒª…]SRPa‘²¯˜{g}zSE;=OVp]ѹÏ6`q924¥îˆ8É[DFÁœ©Øÿ (&;MPdxxz`<:/>_D;@óñ <ÿŽ©¾òÝPSE¦xþIŽ÷ôùñƒ¬ï4P:5!ößåÆ«™Ãßåð>‚® N}ÂÀÃÛǿǵ»ÍÆâൟ{®Ùɹ¯ÑèÚÛàÏÜÈЫÏÇ´ÏƬ¤µ½ÄÌ¿ëâ½Ã³ »Ð©’À½ˆ•™‹Ëä  -áôØ“ÆïѾÒë -àÌÌÍËÄÖ) -åÚóòøø êʱ©ÁæîäÚÆäРazéo¢¢yn‡®Þ¿ƒfJGbk[^S\b“®¢•‚z™ˆV #bäkèÝ/hq‚wB"@•F(§O' õû¿¡µÁÚæ - 2BRbT/3EG?297. -ü>*  ¯SWl+[ÁñÝ$Ý·å!kÝóý °öêZŒuZUTT=๰ÉìDˆ¾c}¨¥¢˜½Óо°ÉĤ¢¯þ⤊¬ÐåäÞÇŒ¡ÙãèôÛ¶¦¸Ëâʸ¶ÂÑÛÅÎäíÓ”¹¹øø¾®†|’Éù.25÷Îê ¾ãùÊ©Ÿœ·ÝÛçüõûâÐñéíÂÀÆÁœ»éðìÇ›»å¾¹ZZà$_yŽŽœËóÌ~ga^`^ku`l|‚¦³¥œzŽ?ç÷/’Bh¥C¤ª¢kU#_­Á¹ ×ÓÈÎÓáðèàÛõ7hš|2þý %&  5$ý - õd0¥²Ûì0ªÛö´³,ùëô{´ìs¿t±(L4ñ»„T7+$=U¤O¦½ÑÄžÆßÕвŽ‘§Št®îûüóÏáùòëïÅÈÐâôíÚÔÏÛ踶Õñݨ”¾çÑǹ¼¾»È ß´·ÀÙ"í¿¨€Œ–±Áœš«Î×ô÷ù -ïÁ¹½ÑÓÊëüÝßÔÈ瓦Íó÷ÙÁÁÑöÛÄÙO^^o‚«š¡«•|opsvL\odTe¥Ð¿£~WdŒˆ`  ‡3Š7[Ÿ¼¸’h!ìÇûFZéµÙÏÌÏÚóÔ×ó./\Šƒ>ôéíîÿ -3#/ úàÂU¬d·B˜ÂÛÑdò±k$tµñçêÌ•Zn­Á¯‚H1æÀÁÎÛñCX_Ž±ÇçèÔ×ÝÜȵ©Â©¯Ïï#;ôÆ´ÓúÞÜÞïûÂÝþâæ×äñÜ’ÆØÖÎÅž§£—’©ÆÅâÿ -ëËÇÛ½·ÒÙ²uƒ®¼ÃÓâþ#ÿÖÖóô̸µ¨´ ž¯·àøùç˱°ÆÉÞÔÓÓëûçж`K\e–Ž¤mZgpip]3O|„vu·Ù²rGA]hGýú×à<­«V@†•¥féU=8Z‹0ÐÙÚÚÔÅÍÞÒé <\rPé×õû)0*,!þíý,, ôæeni€~YTOs®Ê¥ƛ9°lwèíéäƼֻ¼ÀºÇÍĸ´›aF[Ohž¨i^Ž¥±¿ÞäÅ©¶Á·ÇÖÞÛÍýÉí4겺Ðà÷ûßìè±ÕìêöïÞ–«ÃÂϺ“¤Žy¡ØãÕغÉÙÑ׿­¨„¹ùìÝ÷ôÉÒüÙÔÎÃƵ¨­â  á½ÄÍÔ¼ÈÑçô×÷é¨ýw&"T† ÀŒ’T<zˆlr–²·‰–nQ:PRé¼ÖÝÍêáø"J6øÔ;ŠE˜e‚7”/  íθÂàÝÛû>@6ðÀÃå".?L; ü&="êä°2l“§»Äž™¾Ò̳cª?ÃÚÏ¿º¹µ·µ¾´Æî"óÄ¥•’®ÇÍÓÆš†ŸÆóùõÖ¨°ÈÆÀ×àä⸨ÃƽÀÑèîÍÉçÚÚòùÔäëÛÕÁÏÍÚÈÙ»¬ÅÚÓÁÇ¡®Å±‘—ÍâØêÚÂÉçÚÕÚ±‘‘§½ÛؾÇàå»À÷$ ×ÉÉË»ÁÌ­¥êïúØÌÁ½Ð½Èì& -ÊÍÿú¯6ø -J{ »˜”ƒYdŽ‘¤ ­¾’rpR.2=DòØ×ÉÎ÷òÞÑÏßá,D¿eQúpýäÖ²Äó$$6èÎÁÑõ#41%# +ARSF2& 71 ðz’hÍÜéþåÛàöãÕÐdŸ³ƒ»›š•’“žª¦ÁØÒÞø×ÁÌÈÆÊÀ¬­ÈDz”ËؼŽ¸ÏÎƹ¨«ÆÆ®´ÊÓ‡e­ô곤ÄÂÁÝßé¼€¢©Á½·×ıªÛóØÓ¾ËÒÏÝÚãÌÆÔ¼š«ÛÝ·¢»´¶ÅÍÚçÞÜ°Áö ðÏÚëäìÞÓ¿Æ÷àèе¬¯×ßÖÍîô¾”¹âí²%®EâÌ/Nwdnƒˆ„«“‰ŸŽ¢MJX1#<?ßøã¾ÇééÏÀº×ð3Déˆ*Ë‹„ùÕÞöèÙÏâ0A.ÿüïÎÎÅÇ¿Ó'"&:?Y_=-ìYLûDElQÙ  çÉÔöɖ(±:+”Ÿ¦¡ ¯²Á­­¨zs“®¼ÛÕÅÇ¥Š°ÚÁÜé­§›ºÖÀ»·º‹c~¦çÿòïþ˵¾ÙÞǯ¥«™µäÙºŸ¦³ž“¥Æ³€ƒ£ÌàçÜÒûÛéÓÖïä’zµÐ¬£¶¶¡È ýìÊÌÕÈÍÞìÐÕߺÆÝÓÍÕöèèã³’Ãïý÷ÒáÖ«ÉÔӿȨ!ªDãÛãá -3W‘¥¢„jXb[pdO4)ýíûЯªÔáÙ×ÅäGd0¹?ùפ4/þçÝ×ÖàõûüæàÛпËãÖÇ»Ð-òú))+GX8ðN‹QæPÚËáÆåÅÇ»¿Ñß½ƒÜ”ùr˜šž¥–®àæÇÁ·®ª¬½Ôͦœ–€“Î×ÎáÅŽ¸©³´¢¥•©ÕÛÚñ óãØéóȧ´ÞìÁµ¹±êúÃŽ­æÝÆŸ¦ÊЗ¬¿ÅÎÎëôӑྡྷÇÒ£–¸¤¿³×*úijÏäçÐíׯ¼¯¡ÆÔçæáÚÞçõûÖ­¨¸®Ç³Êà­ºõþóâÁŽ:ðàÒÑÙâý/Tx†tiGKRg”P÷ý÷èýíÕµ¸ÑåÑ¯Õ >vY¶Ö3;U"ŒõøçØßùüÑ£±ÑÞʹ×ïØÍÜ+/ "/1+>“›&ØÅ'{3]ràäÐÒɸ·ËØÐvæñY”š¡ŸµØÿ%þÇ󣓦»¶¤¬¡²´ÐÈÙô¹…§¥¨¡¢»ÓØ,(ïèèëÚËÚÓÂëûØÔÖÉÁó¼ÖÝ˸ªµÊÙÞèÝÁ¨žä÷åų¼µœ†´ÎÚçÃÏÝÐÀ¾ÊëåÏÙÛÎÓ౧´¸ÆæÂÎØËÊ¿ÑòÖÒÓ®ÏÕÀèü æœã{ å±ÌÞÍÄÙøFM;:O9ìÓßßâÆàõ³Œ³äÜЫ–ß0dKÅÜÍJ„Åxúï  -ôáù øΣ¤ÆѽÀÜØÙ×ô5994+(üû  ;vÃÔÑ7û2×õF8‡ÅÎÂɦŠ–}3ó&‘®Ïßåæëÿý¼´­Ÿ£¨£¯¿Ïòúá´µúôϾÕíä¹Âóå¼ÂÝØ®È!ìÊ·ÀÔÐÓáü·›Ž©àéÒÅÚÕ³¾àðÞÆÖÔ³¢š¼ÇÔÉþؽ˾¾Á§¢áíÀ³ž¯ÁÔýÛ«ª§¬É½éÞçؾ¶ÙíÒÕÜðóìzÀkêÅ­¿Ú¼ÄÖíðåùñùíÞÇÛÙǹ¯ÇË–¼Æ»©¸Äÿù'=°ºÕ% 2-ñéöð ùæʱ¨¿ÛÙ¸¸ÀÌÕáîõ8SHþö9:M°Ú_ÿÝÌñÙã%»´½o ÊðÌŸ}x2ñ(Ê×Ѻ´© ±Û½£ÅßÏÎßšÈòû÷Õ¬´ÈÝ -üÕàùäÅÈͼ³©§ª¹Ñß³ÁÝîçáÏÐÑëÎÂØÄж˜´ÞýøýÍÁÁÇ彫•®Á°²ÔÊÌÉèد¬©²ËÐÇÏÜÖ²‰ªÒƾ²ÀôåÁÜàâæ긜žõ93¿§Çñ !õêå¿:¸Fзɳ³ÚæìٻʲÍèïöóéÓÇÈ­£¶»¸¤•µ¼½°»Æà(1©ÑÝ$êôßþ%õýÔÑðýêåíýìDz­·ì.EacD#8>EUñnâÆ/ÙìäÛ†9ÊUY>ºÕ¿©ž|"Ó’¸¬¹¼¼³™¯ÜáÊÐêãȹ¤¨½ÊÁ¦¬ÀçÙÛû ÙÄí ìÝçÔ²¹äó×ÎÒèÏ¿ÐÖÄ“¥¾Âµ·£·Òž˜¿ÆÁçÞçܽ¥åâʽ³¨ž«Ÿ§ªÃ¨žÉÔÕ½¸º´ÊàæþðØÂÉÈ’”м½Û #-¿Ø½§æΤ›©é-Ý«®Âãì÷öÃÏØu -™&Õ½ÛÊœÇûñܬ½Ë½ÈØàÅ°¸Æ¿Ëª¦­´¬²³¸ÝÖÚËÊøB8å2Kuéûüúî 8< ôàÌÈî ùõð浦ð":M[S=$ ?G48™Ü3ëçÝoûþàÊÉʦŒ\yrj(ÄìŒ×¸ØãÑÙÔÇÕèðêÚ¾³ ž·Ð¾¯©ÇÑäóÝÞÑ·êôÜÓïÞÔåð³ºÔû÷òȲ¤–ŒŒ‚š®ÐÒÍÊíÞ»£¡”¡â˶µ»À½é«ªàòÐÍàúýÛÁ µòÚÚâÍÄÊÏÔÈá÷Ó¬ÏèͲ­¹þäÎâÆÁÔçñÀÊêäÛÔ¶ÛÃGç„"¿¼Ò¹©ÎÌÀ£šàÍÝâÚÇœ§ËÚÛÒ󕦨 žÈçØßÄß,(²8°UñÒÕ×1+ üìÓÖõûéèñ÷ñíô÷ïʼÌàò $,#;Tµ#¿Ïͽ6$ 99ièï¾&<6ù½ÐvåÛßßÈÅà×÷ÏÓ¶¦¸Ä¾ÒÕÄéòÊÊÐÔèöíÐÖèßÅÎÕÉ·˜ŠÆÍëïáÓ˜{u–±§´Ä¾ÇæôòÿóöÆÆÅÎÑÛÛîâÍÛðýƯçüü'àÕÀÅûÝ®ÂÍÅÛÀ´ëý̹¾«‡Ñþ!ö×è áõ ìÞæì÷ìäëÞÍÆ­;®Dúʳ©¾¼Ë©•ˆÔôË×Üäðùýôཽ¤¸¾¶ªÂÖÓÆÕ)kÉQæm ìâÔð1#%/âÕÆÚûôàŶÏÖäôòÏÖèÚÝë4&78%,3A>O¹°#âàï×ÜÞëîÅÓÅAÈëàÀ”qä©âÎÆž¹ÕÕº¥¥¶ÁÇÓîéÁ­ÅñêÅ°ÂéÔÂÙº¬»µ›š«Ç¯®¹Åáäɼ•„£ÄÎÖòÙÓÎçàÀÎ÷ ÒðÝÝßñàÒÝûüÙ¿ÓßÛÉéöêÆÕÁÏˤ£©ÂÎÇ–™ÄÜŠŽÍûåúûÿ & ý çßÉÊÚÓðùúá ùÒšéBÛðüÓÖçíą̀¦Óò¡°Ú -j©¥KàÖÔâëÊ°ÌÜ×ÜøV‰á{1ñéúþ!4 ý& õõ ÛÊÕÎÔÑËØìéâæù &C3""*;n^rÞô{ ,Ç™¹ÃËßîãçíwŠ×y›x<V&ÌÕÃÇ×ÏÒÚÞɹ¬ÊáöâÜÉ£›³×äÅÅßé·Ž{™šŒ†¦º¸ÕëüëÒÞèÆËÿ ß¿¿Îà⺣׺•É û¡¦ÑàçãÊØ÷Ýïçá  òÖÛº°±§ž¿­£´•³¸‘¨èáÀ©±š‹½íðÑ«Àá 'äÍóí¿½ÝÚ¶ÉñùÑÀúíº{¼'Üä õè¾Æ¹·”‘»ºÆßûh;Ÿ…uûݼ »ãê¼#t¿K âÜ!*I;ßô  íç çÔûüäÖÌÇÇàãèó"<71%8E2 -46NŠ™µó´L,.ûÞÇÐÍÌæ - õì  []V_Z4‚aõüÿßÆÚèî×¹°½ÊÀ´ÁÑ£qy¾þóÏÀ¿ŸmÄáÌÓëäÕ¯ÄÒÖÝÖÆÔíØÚÍÅʲœ»Ã§šÆܳ¨Ò̽ÊÆÎêîåðîáßõ1ÌʵŸ•ž£½ÁÔéÞÀŸŸ®½µÓпÁÆÀ¾ºÅðáÓÛë&×®ÆÌÒíðùÈÖâìüÓÁ²£›X”ø -+I;Ø«¾ØÄ›¡Îìÿïð¯ÎµO¦)ð̳ª®Ùý 5Úé8±2ú÷<MC1ÔÅÓäúöâäýûöü3KêÐĹÈÎãð*I[YDC=.*!4*/kªÌáÃz7##(A=ø!9#äÊÆéøŸVl[.(0Í™ðÓÃÊÌÊȽ¶Ÿ©œŸªÃð•§ËêÞÛ£ªÈêþ åÈÕô®ÆèÚ·ÄÕÈ·Þç÷ãÕ»ÑÛÌÇ×ĹèîзÀ»ÚÞ×ΰ€•—£·ÀÄÌÑßøÒ­ ¨ÕÛ׺¦Éú׳ÉçåêÛØ÷ÍŽ›¸ÐïçÛóÞÞàð -ïÀ¤–‘š6u%*HTP[f>÷ìôÌ¥Èî xáIHßc!ÿÓ¾Êø Üü„5 %=SaS? Þæ½ßÿõÔîíUWæã¿›ÁîõD__SOEDUbX9OŒœºÓ”U2 " =\@!/<IG越ÄË€‚o=ìàä=¼çêãÖ¶—}›·ÉÆÈ­ž¯– °µµ·Ä¾¦¶ÒéüþÜÀ £¸ÙÙÊź°£ÂÔ”¤ËÉè*$çÉÆÝ÷öÔ´à÷âÆ«ÑßâíÉ¿À¸ðõܧ›—±ÒìèØÏÂÃÒ¦‰§ÜëçòûÔ«×øçÚãýýÏ¡®è™qš£ÉêÑäöðéòûÔžÂÚþØ÷B ;B[—Á©S/áÎÌè"0/56ecL0üHDŽ (pSI42;\tDßßßÛÑåò ûþõ-óëØÄÀ×öý û85:FBKdy^Wbg_}‹O?9!ÿ>>, <W'ݺ•`—hIQXèà÷w=¥»ßîÞÒÓßÑãóß«œ£©³ÉÙÙÐÍ»½ÇÅËÕÑ»¨ž– Èãײ¾Ç¾íóˉ¢ÒÜåäêÔÊÞí³§ÐÞƸª±Ýûè¡ž¨½ÄØãÑ¿ºÉÝêàÙÑÍÏÁÉ´¢¿ÛàçàìÞÔî¼ãÒéïÝ·¶éˆÔû¿¼ÙñüãÚØÖ!% ‰þÑð0¾ÓÑ«‰mFÿÛÔõ2IJüÂÃÏî)T^#Æ#“fƒ—tc}‹k-ûêîõõìǺÒû&MßãíäËÂÒÓæþÿû (8BB,9b€wdeZYTG%8>ÿ÷üàö%õ ÿ§‡íèFB^EMTg^'÷Ïè†1šÜúøäÖö¦Íòâ¼ÀÎÖÜÑÉòô¼ª–­¡·ÁÐìüÚ°¹Á¶àïáÛïôྺæøõðääãäßòêÂÔëÌ °âÝããź»äÿȤ´²ÖþÜ×àÞÈØòèͺçû×¹ÛßÞô -ý܆¡ ÖãéûîÛÂÄÐÀÝå“ïVö°¿7žÙ麰³­’5üîÜô+¹˜¤Âäðð FT%ÅÞ‚Zn»Ü¿ÃÃؾÎãö úȦ©ë%5QYæÏÜÑÂØçòòðú ?VkI*P™pRNF.!!L2 ëôî;²‚ÁŽî_GHQ<6GP ã©ÍT‹ÀÖÜæäÜ·Àãûý âÈ­ºåÜ¿ÎöåÔ¥~q•×ÝÏâÞÎÚ½¸ÅÑçíû⶜©ÏïäŵÏÜâÿæ·©éìÉÃíÒsoÁÓȹ¹ÔÚµ¦¾Ö ìò÷dzâð멤Ȱ§éýàÓ½Åÿ É›³ÜÞßöðϱ¥Ôêôø·Ž³°ðméñ»ª··¿ª2ÝÇÊØäÙ¸§£™¶äò]FÍoüubh’JR6ÏSõ˱›¼î Ù»°×:mrL%äϹÓæøýíé/LlnlW:c¶¼x`H- -JJ .WN éßêÖ®“š$3‡VyS<DGD24Ù¹­Ý*µcÂÐÌÁÆáö/îâðãÑÓÂÑ츽ÂÇÑ­ŽÊßƵ²ºÆ÷ãÄÖåàÛàÂÏéí·¤œ¨¶èðçêûØÓÑäèäÙÇÊÑÜèÚß Æ´ßéß!òÍùøЮ¸»™‰©º˜Á   áÀÈÚñ÷ÒìñÖ»ëäìز¼éíöê¼nÉHô§žÁà[ÐÇ´¾¥ ÑÝhÕ¨®¶ÂÉ̵–—¿ããþrÒ‰’^z‘ÌWÁÔŠüc&ÿвºõ&Á´ºè,E6 ÿæîå¾´âþôÝò &=^|„nI4}ðË„9 - -$,2gš5 öä×Χ™Ê¥ø`aT7AGG)ßɹ¸¾þ—'c¯ÂÆÿáººÔ -ç´ž£¦ž«Èäöõ½ÏÑàåå!ðƨœÈÖÑØôóʱºèéÌ¿õ'/ ü ͨ•²Öêý˧Ѵ­ðïøî·Êò³‘ÈÒ­¶ÕÌÍëþþÐÈÂÛñòõÛ½ÆÓÓèʵÉÖæöäæé¤WàvB-çÖÇéW™´·eg£*®˜Š“žÀÉÙЊíe$ýµ‰rtÄÌ&oþ; ʹÞøðíèÐÌ××´¬ì!ÒÉê&eyfr[‡sz$¯B -úB¼ ¤B. ìÀ°µáx°>X^pcO7.6ßÃÛ¿»ºÀß0²!‡ÂÜññïßÇÏÇæ༱½¦Ž¬Ã»ØÖÎäÙÖÊÖêìÜÙ¾¬‘œÜâàÒâðˬ¶éôîâéãõÅå;‹³ÀÕ𼜕Ìúûþè¼ÃÔ ÞØÜÚàúâ©®ÝÓÇìãèðåÜÒëïÞëس­¿èüÚÖÛWÑO)77ÛÁ´µé?l9$'ÿÍ‹Ž…žµ«•¨ÕþÐ[ÇOA&Öž…wyà— &ä'8Ðõ&89b|$ßÐÙÚÝÀÃËÊÀÁÊÇÏ^IùÓý3Y‰^L_ÁJù$È™4þø8͉×s¤(pN?? ÖÈìYUbKi…›’jJIW<ñ§µ»Çº·¿R·-X™µÚù ô»ÌéïòâÊÃʪ®ÆÈÖôéÃÀÒÑÁœ…Œ³ÍÜüÚÑõäÒàîòóôÛ¾•€†¤È×ÒÔÞáÁÐè -ôëàÝÁ±àõÜãÛÃÔãÙผ£–x|µô긪¶¼â  -ôÉ·°Ö - Ķ®ámúöͦ¡• ±ÐýäÝÑ»·¤Œ›£¸± ‘³÷-å*y2]†<¾”}“Îh÷êóÄ÷ Ìè9r¥mÔ³«ÀÇ»ÂÖÌÂßî n±Œ"7TcxmOhΞvÍQˆÉ^B8 0Æ¢ZYtyN<IlV] 'Ú4^u…~daw]÷§Ž™Œ„¦ÊÑÈÜ7nªúmÖ þÒàÿ ðÚçû¿¦ÞûñîýçϦœ˜—ºóêâÚÓïõá»÷çر½Á®ÎßììðÂßúíÇÉÝöîÉÕïôÒ–¦¥’É75üãǶ§Áì¯jgYIÙã<„“š’ž«´Ò #ëËáÇÁÍäó­˜—ûX!ðÔ¼¨ˆx¯¼ÁÚßÑÁ•££˜ŸªàÍ¡ã.RE”¤(Eƒ^à“²µñVÙôð¾!côýùC•u Ê·½ÓÝÜßÚÕòþø=åJåJ<dobip{ââñwì¶Ìb65FIE©‚xå]%G -@>Evž¨û§ò5<:Qt}}y”s'Ï•m\h…ÁÜëäÂÀçG“ûg¹ãü  ãÈÑëöçàÑÖøðËÁ¸ÌÂÈÝêÜõËÓáøØ¿×áɼ§…­îýñ -úɬÊéáðõæåôãÙÐäèèåÂÀí+,êÐÕðÜfå­ÀÍ—k^gq¡÷ Rsˆ®¢¹½ˆ£·¡°„]?C0Â/ã˺¬–—w ¬ ³¤¢¸ª µ©š½ÉÀØ×c‡•€¼ãm9¶r°Eˆ·ãêÈgÊLâÝÿQ‰Sõ¿ÑðúëëãÜ÷öÏ)&Üi‚Bb}^g‹L¨,Ú</Q][[„8`3'åœôq”°ËöJ³ƒÊç$1IZivs’Ÿ@ó¾œwdiÍ÷àÎÆ¿½Þ _ÈTáõñÙÄÈåæí -åθ¶Ô;ÚâðåîóɽÅì߸¶¡™«°¶ÆÆáóîàÖÚöìÞѪ“» ëùÝâßâü9< -é§7¶mH8&"68?*EkŸË¯ÀÓÚí?b/'ѵ¶Ã·±³‰‡ˆ„|ª±Šƒ‹¢š¡ ž±Àôÿé)ÿè.IÃ*¶6£kªé<„¯ï/*ôÑ™tMÚn1ø1ƒ›Z÷Ùóú! -üÔ¹&QZïºMkzˆàØ7UcÙ 6OŽx[©Ä™Ó;2å܆½ HuÇ<„¥“ ß#N~mydN*öÖ¾‰–²àþÞäâ°«×ü2„ÏôB™¿Í''âÕ¤”¸ÞïúóôíØÊ¿ÈáÔÄ®´±¬ÓØì#ùäòõýÞÚÒ°~Šï  ôÇ×ÕÁÚ.8 ò -ö”û´‡c,ìß ø<=4DCEKU msciY=è´™©°¬™‡wgt ¤ls™œž¬¤°ÔìºC¢hµæŠ÷ŸšÀï6u£)s-Ü¢yL³y]j‰z\Z°Ûž7 CÉ¢Hçë{¦Æ=äskf€«T„®*V†; U”¾À~Zê>QNõŠûÓ¾t´|ËìÙeÙA„‡lkdIH]VJ%ýÚ·¿Íé,"òðèæ‹ vºðú×¦Æ ÿîéôÒÀàûëÛúüÛ¿ÍÏæýí"ø¿ßêð,øÓÛíõßÑã  ÝöÎñ#ëÄØ Ó•£qS)üüðþùþþÞ¸Þ -íñéô -ø¸ˆ–µ®|¯®uShŠ…o”¸«ºÆÂâ)4Z¡o ê/ddíÌ«¾ zðgqëÍ#澈œ|v8?BØfEbë¦ÑL@äÓß`IEN ™­=Ùªw([¼)ž³±Úk«áÕÌU_^®*œMùÊç\Ô)9II=19IL9JJÌ¿ë5QA1VKÊ­­­×"kØ-P†ËúûöãÕ͹§Ôÿþöúúþ63ÈôѧâóÃÇþÒ·ÍãøíÉÂáÉõÌ%ò²µº¸P&â›q/&ãæ÷ääýí¯©ÈÒÌÊËÓ®µ±¿ÞǾ¦Œ}¤Á¢z’µ§§˜ˆ“›ƒ¸Óàíñÿ&bpö zOVf‚ÕFH/êËÐü|ÿdTöíë…ý¼•ŸÇ5+ €ÀŒ50^³˜ E™‘Ûv¡#ÿ1ΦS„ >á›–'™§bLF×ììï*5QzÚ.)ËcK˜iVñ3A-JRK]f`$Õ¿â*95EAßÌÇÇÖ 'Gy¥dÆôòÛÞðÌÕççзÈ× Ë²×ú 0+üкɿ··ÛèÂjBd§Å©¤µ›€‡s_v©Ãàßµ‰ÐÝŽ*Ö¯©ŒAü -ùê÷ÔÔÜÿåÂÔÆÐéÑÍËè—ž–§°¨œœ}š·¢¢ÒѺ»¸Åíâ 1šÔä©ÇÇw;DwÐ8T? üÿübócÄÅÇO✄¸Qè5Rk  DZþÑ#Ïò€H¤›·Ø¤I^l]ÒS w> 1=¿O{âФüâæø2T„±í å˜aW´mFÚ -A  OSOgtZ5ÎÅò  -(.2;C)íÐÕóùúR–¡Å2{•²ÄÂÕáï Ý»Ô÷âì屴ź{G,!ª…›™ˆ‹¼ýéÅëéâ 8y{Ž…›n9Ô…csxMø -æèíËæÿãÛÊìêÞßÓèòÒÄ¢—½ÀÌßÞÆ«ŸËÁ´ãëÕô·ç#R*úIÎ$TšnËòúW0‰òQi4)7)0gÒ®|®¡:ÆŒ’î]Œ±"‡îKHÇšn¦ Â…4¾£‚„¨™m?4K¢+·2åÉæBÇØÈ'O€^ú8<vñ LƒÐ1np?ÿ‹§'ÖsÕQXRN: 4X<üÈ× $9D=3:CíåèãÜäéìãÉ žëìS‚°Ý 0L/+ úçðßÛï—ZÉiLM+>C(NzfubYeŠ…¤Ê±˜”½Õšwlp…\4;+ôùî÷ Ú¯»ÖöÿöýÊ·Ñ,Ö©˜«°´Ê¿ÊÈÊÇÊÏïùæнŸ´ñ?B `Ä1|Çá¾… Ĥbúe†O(`sfdhžÎƒRu[ö•}³1c;"‘4³R†SÇ–ëÛfD5ÇźÅçãŸss„¶ØµQûéêüI#‰u»Å”b“öu  - kÌF¬ÛµMæé0±k\€Š}i],9MYVCþõ1 -/$'BYUA4 ðËêË 4*YÅÿ G|‰‘¬¥­¡«™b<6íÉ«Y-$(.ÿãÕ½ÓKA2>738(9Teif[dB" $01èììßûå´t¥Ù ó«¼°»Î¸ž¶ÔÜÎáôóúѹ¾ç6b#é"‰ùgµÎÁ½¿Ÿ¸c³úv€\iÄÁm[T£Óz# ÿ¿Œ‹¾#["ÎÒ\Ú3Ùjƒ«Á¢€lîÝÝÊè âʾ²¶£O:D!0°Õ*Îá„êf°êwGý¿<¨ÞÈz ìü;£Mż¾Í¨nH94B^p€‘uQåÖ5J7<ITZ]?>UtR'&/ýêáí #6./1Js‡ƒ„¼Ð±uy£†VM/ÿìâÛð÷S>"0ÇÍàËš´ 1 ù. <SlgT]W*9C%8JM@(þéÝÇÐü ÔÀÆÐäöéɾ«´îö% .!8->|Sâ!w¨Ì­ÀÉ™‘k£J® VhxÊ1/Õã! ž:(쬔“è^"–¿¨r߉շìèsÝʦ–²­§Ï*84Ó˜r<%]{aJ¡e{bƃ›®4èyí×å  v¼Æ‹Q-8åËpÓÝÕÍÝÅžcQLW€sU\[A¸J›~ˆ¢Ô¡G( "+-6.*6I1äß+ 9ùäãìóòÛß秲Þ%<kH01#ñéØõýù!*IE*N‰lom\SYn_X]AOUN;ôåï"$ùÎÝãÝà 462è %:W_W-5J9F[T»‡®5ª¯±ÕÓ±š{ù¢ã 9fÄE¼"!79¿r/ú­—Ç(åo¡ŠˆÁÞBt¸gÇdPc_u•˜‰¹HZT6ò¨‰‚†›´ë5ÄOÓ5-|Q¦™f(ë¾Æä °ºµ¦€G%Wÿ僾ÓÚÒÔç²lb[^kU3,!û—«“É»î( -Ú¦Tó¿Üü -FdB@3/AP'æÔ)4 '9 -  *øªÈCRT]N3(YxqM!%$,&û.-÷ MF1HJ?ntXKY|ypU*9nple+ý -ý²”Âîáò?TkTIaL?w„a6;M€¥_.ña•¦†¾ÆÍ™“«˜Es<Z,JŸ_%·*RaB=aT#}Ú<ÎÁÆ‘~£TX¡®Ò²©qH*b‘Ÿ™æG]E3 ?•ýsûG$ÖGEsCjybHÞæéýÙ¡j%çä$|ãK–³¯ËëèΑ_<H`‚m.Æ4nÑ^H,íön_2 -Õ† ëÔô@e}mL?OUdtG $20' ';%(?i`41TQØÄ#lK?=9^V9?PXG$d„a89)ñ+<.'I766=EH>ID."e”‘j@0-+6)üÀ²½ÄÜö)uwŒ±{C}™z\b^Y—ºˆ+¶} ìÖt·¿µ¸Ë¶ÊÒwcËçæ…èå·ÈÑÒ¿,ÝIQ\ã˜}‰ª'–`¬Ÿ|d; ^zªýHW-?‚—¾Ó„ëH¡«N—”›! :[^íø-)˜?ݾ½"c›©À³¦«SäSÔ+×Ú®Ú|`:(ÊRv‚u€k/øš+æå 9J<C0>A5,5J3Ûç éêéäFR6HoX0$57Kj[6-gu`Dg€[Yƒ–_2,('5LVlk2'87), -/\_B)âëbHXgNCXuU&7#ïƶ¹Üñáø*\=Qd6*P=(FUAVzž+ñãí:‡!ýð‹êÿúëÔë Õ¯®A[;ÔÛæûåÌ·¿½®W|p_ºhŠÐLu#˜ðpZ`Z0:nØMn-F°îêÒù-Bl¬/Á½)# -Sñäí 8F-ýù -æ„(éÖ˯4»:[‡˜Œ…š¡Dòƒp×ÕöOz?Q¿Ork†¢¥}.Æ>Ñ¡’“{x…{ƒˆlVRft”SV¹Qi\[xR.g„\P`]U{˜¬¾Ôø ûÝêîÝ´¦”]EH}k+1_MC(øR#7þ¶Ä\i]L ð:n8ôÙÓÐÔÍÄGC1èî5<ó .35D‚©—NCN05,l ÉÜàò Ðô•ÐéšyÍÙÜÁÇúüä×ÙÜϧ3dW€pëGc»hHWdC7@Pu¸äÿ/ 'J÷ õøwñ-9Vb¬9 -ðóó !ÿöãň=çÑÎåN÷ˆð.KKQNZ]‚”Š>ÌŸßÃøæÈyWbʉ­ØºR¯é̲›cêE–éyZQ>9/&(IaZ+\{„V>ŸŒÇŽ\Z‚icƒ…Š“rŒÞý /ŽÆ³¾­‰](/Y\c`û›sr7n–o -&//ú>V#×ļøKj<RB ôüèÐÆã@XK;1:ãö7HU|†“•E¸jBùã -ŠÐúûÄéŠéúƒaÅççͬµÍÝÞàÐÊ´X¬Øfn¢.À[ONakL4LQBE`ŽÂ:ÞFCø²‹{ˆ˜Áìôÿësà}>.1ìèõúøùÿñ̆="ö -TÞmÞ9ai[@âöD©BCä@gfé «/ý¯c&¾Úµ‹{Wã*DJ‘UH8,Cpyh_aSK>F•Ê½´þt![é{Pu£ºÛÛõ@†‘¬š1¢ øû ·§Ú''Ý›Kå‚Odw> Aj3%D<EJ064/KUR9'?jS#üñÿ #2;G_cB-:>ä +8WfORn•nâ9û»¼ùÿ1.±Âºƒ£täí w_5ŸõòŒ"$…ÒÓÇÀ¯ØÖŽ%ηP‹É´.‰H_g3 &n¤ÜfÛ -Ý‚79RJ Ù„Uq‘˜[íäëõëâã–pRK:,ZÇ\År“~m7úÑõ8hJÎô_©3=߬,ضüÎté\Ã$JaiM°ëÁÅJ!#(%[‰iD>@I&2ã 4•9õI(â¾½ {x$5f¥ãÄ’´‰o¿Ø%a\B:9%/.óÑ4MR%3bG-<I'!0Juzh_JGVOd~p* -ÿù.QF 6`F7,+B8$#E95v†`\‡®³jÖ™=uƇW¤T‚“JˆpÕìA®n{·Ù°‚‹ô|´³´ÝóÓÅ¢ˆˆPíCŒòŽ —Y:HP*òÝö0†¹^mI!ìÉÌdXµ¬ ‹pLaÁ!Oþ‹=úèÚ [=<=1N´:Ì6y®ÓÏ«k+k‰ Rå+ÃfÛwÿPx {Ûî"2I;ù•¡Žã“kddˆ‹ZDUquh>@tãgšÎ9õ‘ògòÿÝô¦$1<J°·~]Wg%Úÿs¡Ê:LÍ—Îõÿ€²H*(<P9"6IM*1>h†aP4!6B^R"ùõ)K%)YFJe~b/PW=Tw„˜}³à¯JÊ-Ž„kµÁElG©‰?z½"•ú]a)¢ï•B¯â ûúéÀN„¡ÐJô¢}QBK)ÿøþ5h»×àζ«·}¨UÙ|U5,U¥ªîµ:¾`)ëÙòú'2UÚ«@‡±ÂÖÕÅžxoÒ qŠüM¿0Úyc–ò (¦*flGÞaŠ¼ š¡¿îö¸Œ—‡}tu´Hɽî™lÊ%B>'ï†âT<W`iH#8.ÜÈ63E}˜‘XLC[†«Ã³[½a^\O'Z;3OWvqhB5'8N3"æé - /Wl~|rpy}’œrXgWPQ<P}Šž¾Âµlªó«@¶‘öẠ-Ò•RuŽóÉ,I®ÅdNLÒæ%⃔„šÕpJUP; Gprnˆ•œœ¹ÍÒþ‚Úªˆ=!Aµ”ôçsÒXúþ!£ŸÏ>n„Ù†¼´Ÿ·ÇÏÃÁau Uø¥Wã?Aÿ ùÅwÁ<¡t3‹ýeûµùLoOƨv]Z_Š -´ì±ê¹,ÀÍ—Š6.%ÖoJE@>÷ѤÊèìéìïòÙ–¦|j­ß“ñƒbK+îÍø&0OjdoŒn/--FH*÷ûö e£Ø#+MIüÝÝÙݦf 5e¡¸­œ¹ˆ‚ºQÖ®ÃE'ÝqßØ|ß;­œ Ýíòx¡•íŠ`jU½éüèÒX4ò¦¡‰ae|½Áf<^™‘ŠzmypˆÊ 6²h®9'bˆ¾ e¬ùýy«ó )1JÄU¨a( Î°¢¨¹ÐâÕ½Þ)¬Ïgöhu€†—²–1ÍÅg¬ÉÃ]€ÍK;V–¤h𨤮{j_ŽÒMÒÿpD*ô¬a²PTɾ’I!'%ÝÕöòßÖÝßÕ¾ÑéÙvo\-!iÃõi¾~cJüʬ®ÒG12L"øøçÕð2=]¢Q‚›°¯º×˨‹\v¬úû{ÈŽ~Œ˜ˆ‡¾©K²Âɨ¯å6ÂǛȕëC¥|î֌ڦÕÆò»³âmEA|«Ô཮x£Gl`aP;5ŒþðŠQd¥¹ybNO”ÞE|ŧåA(Uhr†–Ÿ÷˜øC†Ñ×η›®‰Æĵ¤«—±ëë×±¡£Î¶x«"‡¯¾ºÇÏÒÄe:}«ÀÌÒŸTàùXœ± BôʼÌ×èçú#…åRÇ~Oëa-S¨® [ÿhß#0US)øåðîÑËÌÎŽ¶ÊÑÒÅí4ÔÝ{áj^=í¢œ¿ïùÜâõíó -º–Í úS´LÐåÐÇ´ÉíäçѬŽËEäêZ’ïǶœ~‚ªšÄQ–Œ¡·ÏSQ ]GéK—WÚÏ~™;6"¨¹¿“ßÌc¿ü'ሎX‡CCL<97]ÀЇJWyœœge–ÁîA[wÀô¿#ˆ..3DafXƒ°ô¥h ÊÏÅÆn¢å°ÃÁ´œŠŽ®ÒÖ¶xF&/W‰êU£ÅÈÁ»¼ØÍ­˜“·ÐÕ¿†3™£Ç7çö+[wwF-ó:I#éŽò)lÙh ñZ­N-F€†PÕŸ¼ú6[[iX- ÿ4ðáÝÒ«¥½§‹¹PƒÓ9ßïdB?¶ÍÈ´±°¡¡Íâ̇™ä05d¸F™°ïà­”®ÃÇ¿âÿ¿¤­ú”3‰ÛÒ!Ï›…ys„+ -ëm:_·ßÕ Xô'Y~Q×¾Odç×øº«³žƒ}åpòh¡ÂÄ¢;`ªF>CIV_VSw‘iOSoyvzç3äëâ××$™»xñY$8GDG%°×3ÇßëîlªÊÒǵ¡«³¤Ž¨«‘w^(jâUªÁ³³½ÃÌ×âÕ²Áäá¥jÕð‰<9LF5ƧÒbÓ=ìYí ÂÐNïñòøD=/\m€dG?IO]E4î¹·¾¥Ÿ¾× +mTÇâQN9ûäÛÁÁ²•–ªÍ5MŒâ8²¹ÁÓ¹¯ž ­œ´Æ«°¼3µ-²ÕÁ„Š£„ˆ‰±LxEwú×Ù&½™==§êÃ9Í1/–½ù¬£°Àpy¨è/J?5J>ІL*<=YsE6`ti[KO_^p»6t+Ý°‡ti¶Vö}±D6=JPULS¯[åÆûKèÈì!![¥ËîáÔÍÑ¡‚r—¸Ë¹’M/J—t«®ÊàÞÜíÝɬÅéÞ£@H~@@$ïëþYÏÊkôäÁülÔjñ3.½æ"DâÐß9_82`eO_fskWK/Q~vV#çÅÁ¿«›¢½ß8“ ÁJQ^. òéèÍ¢™˜£ºî(L…åa³¾¸ÄÇÀ¶Ã¨±Û𮓔¤ëþ6“ º—}—³shyÐ¡ßœÍ ëõ{yMhR¯$œ!ÔÊṲ́“†kyŸª¬´ÝûÕŒO@0DrsG1IQ^[g][Te¬2÷©O65G–.„r\w}hROiàa`Ë4çÐDO‡Ã.íý éÙ­€‘¿ÎÒãÛYL`VvçlºÒôñÔÛ΢ËðןH{z¤%1#3/<àvNÍu'ÞÅkây-!—œºhåà㿼àüô&HtlI=Yk^G@L]sxB"àÁàܯŸÓþ -AìO=’n„cíÓÀ®™®Ü;yÏ<¡ÞÏ´ÉÞÆž‹¨¼º¼ÑÁ»ÔðßåÐsÕ›bIls;+Åo,*Esw*w]>YÄæ& QŸ«ê‰!ƳŽ†p‡Ÿš¡³Ïí¿qACKZm^^LCIAC_nX?8lœ¹À[# 4w±—Åv{Žš}U@T‡ÒáaûäÂû=¼Šùôë¿‘¬ÌÚÊÙéí˃K)üéœ)Œ¿±™”µåû©BÔ`§ïUG\âæý›@Kçªc-Ez®VÀ/±œ 7ýæÌ¡Î(8adzlYTll`Zi^8-+ÖŸã ýõíø UôJ~ëy‚¯¢*л¢“¥îHy«k‹ºÇÓÞÖ¾“lŒž¾ÕÏз®ÊÏÁͪƒ?Ób=K2! -ïröȺÞôsUñdY4"[ú„%&XŽñ´£‰‡„®¬˜ ¢Óí¢abwfI.0L\aP@KU_N&No”¢b801;aöÇ›Ò@ªs~YH>=Z~tåÉ´Õy«<˜°èÔº¨¬ÃÍĸÃÊéöÁC µÏ> ”»ãø&PqGÇaꀔ-;±¶vX‚Öb|O/H˜èͪÜ`Ä/¸œÁ+ÚöõºÜ-0'W…Žxehz…gXp„O ô Ù«­ãÿ÷÷ÝÞè O¦Ç•Xæha±Óp³Œ‡’«Ó7xŽÎU ¼çâÓËƪÇáÞèäÎ׳ µ¾ÓÄœ€Uíd5\G=I=*¾+%PÀÞŸkQxF-f ‚•GÝ®ýD¯>¿›¶éôáÍÁ£…˜ e3+L}‹eSU]kX?%:T§ïÇiE=<>Wž:^ë‚Ï º–wWB>$ èìßèð’@IbëåØàĪœˆ¬Û×Öðå czÓ³&hÝ8'öÉ]ýÊv:kòÞtVßÓž)èë-Šæä~b—êRDZ±-ÉÂÓÚ -ñä?|€zš¯›vB?N8òíàͳÂÊÁºÊÀîíÁÊ -?T9ëk>n›e%׿”˜Æ^‡±-«ØÜËÖÁºÊ¢·âýîãÌÞáÞδ»ŸŠojEÖ„qXJS90&ÎJK³D÷pv?ÎÀEôóNœM_¦½j&Ë+†ÿšìOp5Ñ•—Áδ{QMNm«˜hLIRYJ8O9WÅ6ÓA'?GeJQÞy%Ôœ{dAíí2YúÆ´'êÕøÆñèÓµ§ŽŠ°ÏμÃàÇ0Q7h ÐìÜë6OÔ±žt>GŽ¾‹ãt¢Ú "á+˜îè]+ƒÐYÀ‘6lǤÂöòæïýZ•«˜§²t4(+ëæ& ⻾µª¼àêü󡉽HŽ4”9:XM9þÈ¥©é&O‹ù‰ôþã×ϼ®œžÏòíãöæßóåÛ¼‰~¬°¥L»N!/óó2‡§XiE,ºðÝËéž3‚¥ò>•6‹ -Úa¿½ÉI’VéúÝ—SCGTlŽTC@BBGPG)YØt4QnK>’\,`ÇQ8 ïý¼V2/95!1f𽯶þ6L¿²´Â¶£–‰£®ÄÊlMu**a€†Œ¶˜ßÉqBUx40I9ù‹]µï)0â q‘eVŸÖMÀ e§ö#ó´°žz­þ  QŠ»©}G*ʬËòæØå3TÞ¿½ÍÓàÜØýÇÃU¿Ÿ)~BacG×ÌÒð X³"’ÎÍÔ׺«¼¯ÈåçæÞóõïòåͺ²®¤Áçô~­%-+R‘lï|ÊñÈXES}ÓD(Yåýa³6i®Oaä wc´â‰ÇƒXE$ä²lBPZIN[whis[H:C;$sõÔV4?UhuSIee.5L™¿G³œ©¦˜`:C×÷ÅØÛMR]5Ug~‹’ª»½ÊÚ¿rÀŠƒ"Cx†pD-‰öTPù(`VÑÞø¯vpš:-^®¡Ë +f–ÓCÃt·'!ß¡maœ¾àèÓMq6Ü­Šwy†£ ´×-ÖÏÛ¼Öäɦ²áèÀ¸æSs'›IVtlD1DÛâðyÝN£¤— ‘Œ¢ÁÝü鳟ÃÒÀ«Ž“¢ ¬âôØu͆qU01R{{g¼'VùHâ5°Â)±îeƒÔº;™3á}Ö—þIÓ͇Q Å‹œ£‰msg_WZz¡ÇFð›þ¦P@)AcXUR_¢Iî÷Pì•A,ïÄŽWÃÃÓçùFœ5Ó3czŸÉ•ÉÆÐæÙÇŠÚ¶¨Tu–†qhWCm˜ºÊí :!Ü½Õ ê¹”©áþ’RRi—Áî7pƒµBâVšèêÛÐÒÈÁ¯›—ÇÊ­Èóà´›ƒ•²­¥{‘ÀÆÂÃíæп¹¥˜¤¾»Ïò+aàP,IT=.btDûöú fÐy¿¯Ÿ§À¸ÊóæØÕº¸ÙÆŠoŸ­ž„–Ããôܱ¡Z,qž¢»vvT“n@ë´0\$÷]¶ÓsóÜ;¤wÉORvK!ÜŸlt¤Î¶‰„‡„[O}ÙµKîúRãÝrEB3@HH2K‡»çߨ¶„¡b@B1çŸr1ïºØñ9`Sg¯ö0LYyÿë¨ßÐǸ½¦ýkl»µ‰‡Z05^p Ü( Ö³Ô)zzD$÷£g<5<XmŸÍò5u~±:ÚF«ï妺æíÄœž“˜ž²½Ã¶—¤º–›¬’‡¤¿Öß´ ±˜eq•¾ÒÉñ@òuïE|^J, QÎy±¬ÊßÖÅÉÝÉ´Á×ÔæݯŸž³¸ÀÀÈìóÇÁ²ÅaÉxX7Ari‚ÛZ««I†“¦W2CˆÇ -ýsap_¢H<fk œKÜ—`Tk£È¦˜œš’dL=aÅí”V! ·PUCN]H$ "b†ª® ¤ÆÚéëò½~XæÒè+/!$(JZ[j›á¹íÁ××ÃÀŠ%C5‹ú â—oTHU_s¯åùûÔ·p‡‹ŠQÓgWk¿°¹Æ×D­›¬(£ßݺ¦§´Åµ¡|xŒ’z˜©¢Žr¢§x`gˆ•†gq“”¬ÒÚ˲¦|u‰ÀÝÞ?=ºXØö3K6@IQKFhÚW›¯ç缶àÚ¤¶ÕÞÙ»”¦¢®ßëëòìÉ´Ûõx×w= HG*/—¸É9)|KXÇ;{dìƒr»?šù‹îf=ðm×zL6Eb¨‡ƒt}\WI9>u= /šñ»a28OR5 ø+Fd—¼Á¿¾·›~¬!˜e?úèïûü$0+DVeÑî®ÒϽoã9ÉÌPIÇZ7Mjk`QqÎ|Ÿ½×0~1¾’ž¢³Ïí:€Ì¤sñ—ÿ‰õòÊï–«¸¤|vzy‡·Ä©iPxvyul|ƒv^Y—¦°ËæŨ®…w¢Öì>V ƒ ó7gepq]M\N‘'©×ÜêÔ»µÏÍÇíͦ˜‹™š¢ºåòèÚ·¯»ÚÙlâyïñ )¼f•©«ÎžWµç/e›º|ã7Ùö³Güª+ï'C´ýx+$8J€ŒzjQHHQ9)#ôù!N±ì N%+5 ûóø3dxŸÆÓÍ¿¥jK¦=“X/.ææòýñ"ùû$Vfq™Ý§HO ‘ä.DZ´e¤2†DYrygB(£'x£h¤Wʶ­“’¸óY¬·¡ˆæ§ôøÖέŠ™š”‡|dh•Ç¸„]Rpv|ƒš˜ŠeOp•¯Â²ˆ»’tp©Îÿ9y?©ž–‰e4<N¤2»ÛàæÒ½Á¾ÑÞÆ•už®¯¨µÌξ®ÄÕñóáرVëj2",à’áÛ}R)• qÚî‰%?€¶ÉÊ”Uøx+X^i´SA<@vyaH3ATPK*÷óP£À>--" -`‡´Ûâѯq5S¹Ry7(-1ÊÊÑå 7*$8]q ÌÑ€MXL -¨+¾{•ß^´Q¹`ULaG/om¤…ŠºÞ㙀|ŒérŠ…”©­#»‚ÿúμ§…‹Œ‡—­ª½›iX^q{†¢½¡€h`TbmuƒŒ“Ÿ”p{£ªºû%@ôyIt ¬¡“m?=Knšø~µÀнÆëÜÛê³—«µ½ÅÄâõèǾÇï;"Þ©XÔI-LF 8+ÏìÜ9Íݸ*Q¨ñªV2N˜»¿È¸Ÿ‰6ÎœŠgÎ~UK3HypI/+OE'$+íí5m¥<49887:91=Cm§ÙòÙ§b>\ÏD3­_D>N¿Ç¿Ìö3^WB??bÌc“<ã¶æ,UQ9Ò{Y›iq¦X7. Fc~¯ xtn…µKجór}ÖE…`lzÎOÇósùüɦ”~ˆ’³Á¤›xjje„‚˜·µžoWO9OUTNYŽlWij•·Ð!F4Úi=G4Qɸ{meSbÌdÐøÞÌåçÜéß±ªäâÞÕÍðèÏÉÚõß×ÞæÆÍpÛ_/GRÏw½¶nöEÇTw—Èúå¦M<j’¸¼¹ÅÑ”2ĦyýO¶X(,]M+2=/1: þ 0'WžƒK//MlU+".8_Ïöé’SQˆÚ/?ÞbakãÙ˾ÄÞöAfW52j'cóêJZ Á±¤o>J‡‡Š)Ήi?+ DFCFEr~]L\ìÓ±›¬²zfxÉ:’›o•H´àQÛùÂ’”’Ž§—‰ž±¤ Ž€rn~‰wˆ˜z<%4joiOG^s~{HMxÆì*¾P"êÂïkÞÀT,žHãùÝåÞÄ»ÔÛæÊÌâîÊÕز´ÄÓÑ®§¿Ã±Ãß{2#wÈ'†®ž<¶?/ϵ©ÁÓÚÄŠF;x©ÇÍÆÁɯ5¾‡Q•È8  -, *)&AM65HniO8J£õf 0b“ÍæË^$Du•ÐìÄxZyŸùðàÞÓÔã *7*!;¦¢»<ŸÈ­d,#WÖ¯o:g»“ˆF=BYUB;Ti?'Só,;S7î[?6OÔoŸgeí€Û?¦ðÁ©‰z¯‰bk„Œš£™fIWk]v“ƒH/7lƒw[Ctƒf—raš·äà÷#×a»³×tØê•%áóL Áت´àáÂÜ "ñºÕëØÍ»µÆÚòÌ‹ª¨¥­®`ªC(;{¿òF¦´¹f¹ˆÂèáÒ«…nU1Ù¢Â;–ÊìïÙõ›FÂX -ô­ãT&ñèþ-*;A9@WvZ1)8[dIN… -y:áì0^¡Òî¤-"3:@j‡zfby¸'D9áο¾Ïìðõ 5ÊCeÈV…•~\BWÖ äɱȘ p2156EiP69E@GA+§¿à É/;2O¯$[%0çiö…äÖ¹Žyzˆhajv†‚†ŒŒ\MKY‘§œ–|zŒ©–h\MQ¡À¥rv‘¨Ý5xáÔÊÓlpPôÄã9Ø~®¯ÚêÐÚáççÙÝòëÞÐÑØÜÛèõ¬µÛ¶£•n5L‰ÁÕ•ÊÈ·#~k¶ÝáÞÅF¨0Îi;¸ hÍòøßéå­;šÛì"GBA þô1^plOhŠX,+ASb?<†Rñ3ë5Av¯îð…$/CSjªJedÞßßÝòèàÕâý]“Å€Ù÷Hz]>¥îÒŠ{ª¡ˆdlxmgP0;KEFpƒUTÝ™Ù'm-BT{êì3””ÐsØêÕ©¬x‘“ƒ •r¤©‘‰ƒx™ š‰{‰‚s]fe{¾¢€‰¨Âë< %ûÚÄÕè5Ýä+sï\µõì×ÞÙÅÔͯ±ÃÛàëÆÌËÚÇ£´Ù¬D£USi¸ÀÀ ¾Á‰ÙXRŠºÔë¤{_ßcwïÍÈ_™¿Å®JÃLáðæÔyiS*þ 0Yuo_W€È³N6QPY^ELŸmQ·gYev—»£H#÷ñìñ0z³½-=0þôü:AïÕËØ&$ìû-\`E(àÌ{ƒöÍÄ°™ ŠzaORMNxŸ£`Ah±¾b^pˆ‡“ ?Y1¡Ã úÿÜ¿§’‘¥¢ªÀ¬wv¢¦•›™ «™{™˜“bPZB2=q£¤‰‹nÍÐÆ9@ãl˨°Âæ úé 0wßÖûðèêÓÈ«ºÇÛéÛÍÕåÚµ§Û÷ ñ™ l6?¯ªŽÞàl¤ õ? ¤t•+Q-wªRÁṳ́^ê¬¥Ú /Æ5É„a0 .XWF2ZµëTIQZq‡Š¸–çÓˆJ) -0GQ#ªOú÷#h¶ìkQäöý÷WwJûÚØèA‚T°4&0s‚†tÕÆɵ·ÌŲ”€^JNÁÈz/+LY…ˆ“«¸¤¹0_K‚0šÔ!šõ󮊤¦“” ‘|uy„š©–qzˆTLqŸ•O5TZ[[£Æ®Žzo åßÙ -. ŸO -³¤¦Äô -äëþE´.ŠÇæôùðëãäööèúï¾ÎêÙÀÑý Ì4¥]\hœÄ¢¿‹ÃÍV~Ÿ<e·¯OóÙÞë6‚ã¬l< ÔÌO ˆè‹S'øü,5DUICx˶L7MVt~Ø!¯2;0145(öÒ´.ƒ3,EVu¹ã9ü¡ÆÖáèÎÁí?RêÙî!…ãüÉXùæàóý%ÎÂË*¸§¦xSÕìåÓ tX>h’tJ79JhqŠ·Ó©ÇMRŸTªÂôfÚÙv—¯«Ž{]m{ss‰©…_kgHD]}‚|ƒŸ’~u›Å³»£–¯½·Òüþ ÂYÙÖãåúú×ÄÇçõc»#Ca—¼ ; öö첟Áò #š ¨a_‡˜­¨ý_¥¸˜ì×¾ sWñrñçµ²Þi®B½q<A—ÔI1¢ÿ m&#8BYu}œ¨¨b!LzwoyÊì¤+9?KU°èã¡P,öD•T=Qm’á1ٚɩ¯º­ŸªÔáÍ×ùD±æªFùíÛ¿¼ÐîûÚÅσqqM7i¾ÚÎ…e;?IW_ia^TNc{·×ËÎ#O÷•½É…Þ伌„“›’Œ€r{grt€†mTT;Ad…ªºª¡•~ Ñ³ ¨¾³¬œ¡Ãéûí£TæÛããÔÁÃÀÖÍÏÈüEm¥ÊYˆù7 ãâéß´Ÿ¤ç ø€÷‰SZp–¯ÁÇîI’¡”(&ϹFuÎðçͦ¸ì Jg—©|X6ú×ç#…_$Ã?ó·]&^•¥½ª—ˆ<<qŽ†©¨ªáz汦ÉU_%éÔ‰ê|]Rf… ü¯€Ë­¸®««®ÇÜæìálÛßmýÞÔÀ¾ÆÔèôðüüö!z’‘…b=A…È™cYU>;TNb„Œq`j’ÃÆñ-`-Åëé‡üÏ’_SWgxorfuš|k~ž~pQBWm€´¬©¿ªx«‘~›À©¢¦ É÷çïºt*ÝÞüÙÉ×ãŲÆô%Hy»í4€˜¼åñùïÍÚßßäìæÐ}ý„3,e˜±±ÇÖ -=k{8†GüI";…àè™2ñÆÂê!F`pR(üÑÌìs0ï9£C°c:,KÓ»—zqPOj‹”ƒ„’„s¼Vʦ7Õ=M3)CGý¥gNm€šãi=ÃË˨Êùæ×Îç" -rÔô¨1çǼ¿Êßïðêè  *i“¦^#,N‚Ÿ’nEG;'&WVOb‘ªˆe\ƒ´þo‰t•UèèðiÍÛªrTmm`dht|©­iiŽ³ ‘Š„sfqž¥™·êÖ’‰‹Œž¿£††£±ÁîôîÄh-û. -ÑÀ˺á ñß¿ÇÿImÌø ,k¤Ã½Ìº©›s= ¼p>2`«Éθ²ÆÖ De øu,#S™e!óÚÝò &A:.(ßÈ -µc€‘@¶0Í“Ž²ëë¸laup‚‘ƒ‰zjj\Pn»d Ì“µÏ¸Š•×÷¼~^i‹™¼H °ÛÐЕéSm0àÅô#_Íû™Û¾¶ÀãíÙéúöíëõ0]w|‡‚X3Fxž †}z|XEQ|xnqˆ‹…ƒ³þc¼¨sÄ…Á·Ìx«Í·’„ˆvp|}u¥¨…i—­¿«­¿r~•˜¨Éûµ”‹¿ûÑŠw¯éýÆ‚B -ÇŒ¾ãáýÛ­ž¡¶ØöDy´ºÂÓÍÔ, ¶kgDN‘ÒåÔÀÃ{E…ý4œ%êt^G3;P?% èçþÿ '! -6´5Ÿ.Í’áLà··ØÁ€y{ ´¥ŽiYg\{°ÏJÕ¢«¹‹fk¬Å°™‡«Ïå=ä|ÓÜɵ¼ä 'źÍö2€Õ ´:ÊÁÖïáÖùøéßûA`ijYPE=I€­³¢ }n\Qt‰—Œ•Š©µüUŒ·Žpû“¥·(ËâßϦp²¤Žž…”¥š¬¸²ÊÀ“”•¡¿À×åÖ¯—–Éè¦}’Ž€Áöä{7ÿÓ³ªßñࢪ½ËÖƼÚ.Qh`YYb^^WL- "K<F’ã×6æ…àQ(b2Šx~kE$!é ü#517 ,j¼ùG'ö2¹Ú)ÐÃÒü À®¢¸Ð¼™pjvˆ¨òû Ÿû¥¬¶¨‰¢©¬½ÜûKÎP¸Ç°ÈÀàÔØØж¸Ðû(RŒ¼ÒÐ0þý÷óÿü  7MLFHMI@C\z™¬®pŽ…¬º¼£˜™²¯µáWª¿¯D®ÊËÿM¥äùÜÀ‘[t’¦¢ž‡ŠÚ⻶¹Â¼¹œ˜©™§¯µÃȽ¯¹Ê¢eŒÇ±¢½ó()Út;-Æ×óíÙÏÓµµß×Ìɹ«¢¬Âë ',ÿ 1" *>.1QgëtµlƒºØÇ‘s!8ZcJ$ýò&Hú7GVZ3;bQOcêè -¡µÄæô½ÈÕí¥Š~‡‡¥ªÑA•špáðÍ­˜˜³¨¬ë/'£1§Õ´›ÂÛ¼©·ÂÆÁÇôM~‹ŒˆmK,    (B;&6.*8RWI0)Noˆ†l“âÖÈòû³§ÁÊ´ˆ¦CÆÏÁ#¾ÿ -#N–ÙòúÌŠbDKf•³Ä³»ý´ª´¶´ž••…Œš’¤ºË½À­y¤É³°¹øÅ€Zúñ÷츛ÀÖåðÞŵ œš¨²ºÞÿáÙìúûøïAeyV¬äŽp3×¹ãJ¥Y" 479C1û   3? ý0IJSBDEE"ï& qj {‚¦ÕàÆØö¸~evŠ¦ ‘…—¸ÝB'"á”}£¹ÃÍfñwȨ̂¬Ö팴ÇÎÜô*Š¿¤kU5;;305 ý -"Is—h"($õüz¤†x”ë6 ø25õÁ­¹g4Ù{W\\ÈþÿìÀd:Ear™ÉÔÙà°š²ŸŽÀ¹•ƒ—¥©‰¨·»´À¾·¾»À³©Åí®y‰`ðÛö õû%ýЦ–”—¯ÌÚá÷úòÉÈíóéîP„€0…pÇÓê¢yŒª–ZT`B-&(<J:" 59 3;÷ï*:8AUnmJþå" |xš>KVœUXˆã,+"AP2à‹\Pgš–~VGAT‹C"øñä­|µÃñò°iÐݶÃÙê \ No newline at end of file diff --git a/build/lib/WORC/exampledata/elastix/parAslice.txt b/build/lib/WORC/exampledata/elastix/parAslice.txt deleted file mode 100644 index 27495d8f..00000000 --- a/build/lib/WORC/exampledata/elastix/parAslice.txt +++ /dev/null @@ -1,117 +0,0 @@ -// Affine Tranformation - -//ImageTypes -(FixedInternalImagePixelType "float") -(MovingInternalImagePixelType "float") -(FixedImageDimension 2) -(MovingImageDimension 2) - -//Components -(Registration "MultiResolutionRegistration") -(FixedImagePyramid "FixedRecursiveImagePyramid") -(MovingImagePyramid "MovingRecursiveImagePyramid") -(Interpolator "BSplineInterpolator") -(ResampleInterpolator "FinalBSplineInterpolator") -(Resampler "DefaultResampler") -(Transform "AffineTransform") -(Optimizer "AdaptiveStochasticGradientDescent") -(Metric "AdvancedMattesMutualInformation") - -// Scales the rotations compared to the translations, to make -// sure they are in the same range. The higher this parameter, -// the smaller the changes in rotation angle in each iteration. -// If you have the feeling that rotations are not found by elastix, -// decrease it; if elastix crashes after a few iterations, with -// the message that all samples map outside the moving image -// buffer, you may have to increase this parameter. -//(Scales 50000.0) -// Better use automatic scales estimation -(AutomaticScalesEstimation "true") -// Automatically guess an initial translation. -(AutomaticTransformInitialization "true") - -// The number of resolutions. -// 1 Is only enough if the expected deformations are small. 3 or 4 mostly works fine. -// Less smoothing in Z-direction -(NumberOfResolutions 3) -(ImagePyramidSchedule 4 4 2 2 1 1 ) - -// If you use a mask, this option is important. You can -// set it for each resolution differently. -// If the mask serves as region of interest, set it to false. -// If the mask indicates which pixels are valid, then set it to true. -// If you do not use a mask, the option doesn't matter. -(ErodeMask "false" ) - -// Whether transforms are combined by composition or by addition. -// In generally, Compose is the best option in most cases. -// It does not influence the results very much. -(HowToCombineTransforms "Compose") - -// Number of spatial samples used -(ImageSampler "RandomCoordinate") -(FixedImageBSplineInterpolationOrder 3 ) -(UseRandomSampleRegion "false") -(NewSamplesEveryIteration "true") -(CheckNumberOfSamples "false") -(MaximumNumberOfSamplingAttempts 10) -(NumberOfSpatialSamples 256 ) - - -//Number of grey level bins in each resolution level, -// for the mutual information. 16 or 32 usually works fine. -(NumberOfHistogramBins 32 ) -(FixedLimitRangeRatio 0.0) -(MovingLimitRangeRatio 0.0) -(FixedKernelBSplineOrder 3) -(MovingKernelBSplineOrder 3) - -//Order of B-Spline interpolation used in each resolution level: -// It may improve accuracy if you set this to 3. Never use 0. -(BSplineInterpolationOrder 1) - -//Order of B-Spline interpolation used for applying the final -// deformation. -// 3 gives good accuracy. -// 1 gives worse accuracy (linear interpolation) -// 0 gives worst accuracy, but may be appropriate for -// binary images; this would be equivalent to nearest neighbor -// interpolation. -(FinalBSplineInterpolationOrder 3) - -//Default pixel value for pixels that come from outside the picture: -(DefaultPixelValue 0) - - -// The following parameters are for the StandardGradientDescent -// optimizer. They determine the step size. -// Especially SP_a needs to be tuned for each specific application. -// The number of iterations is also important. - -//Maximum step size of the RSGD optimizer for each resolution level. -// The higher you set this, the more aggressive steps are taken. -(MaximumStepLength 0.7 ) - -(WriteTransformParametersEachIteration "false") -(WriteResultImage "false") -(CompressResultImage "true") -(WriteResultImageAfterEachResolution "false") -(ShowExactMetricValue "false") - -//Maximum number of iterations in each resolution level: -// 100-500 works usually fine. -(MaximumNumberOfIterations 512 ) - -//SP: Param_a in each resolution level. a_k = a/(A+k+1)^alpha -// For MI, NC, NMI, you could start around a = 1000.0 -//(SP_a 1000.0 ) - -//SP: Param_A in each resolution level. a_k = a/(A+k+1)^alpha -(SP_A 20.0 ) - -//SP: Param_alpha in each resolution level. a_k = a/(A+k+1)^alpha -(SP_alpha 1.0 ) - - - - diff --git a/build/lib/WORC/exampledata/elastix/parBslice.txt b/build/lib/WORC/exampledata/elastix/parBslice.txt deleted file mode 100644 index 30d19190..00000000 --- a/build/lib/WORC/exampledata/elastix/parBslice.txt +++ /dev/null @@ -1,122 +0,0 @@ -// B-Spline transformation - -//ImageTypes -(FixedInternalImagePixelType "float") -(FixedImageDimension 2) -(MovingInternalImagePixelType "float") -(MovingImageDimension 2) - -//Components -(Registration "MultiResolutionRegistration") -(FixedImagePyramid "FixedRecursiveImagePyramid") -(MovingImagePyramid "MovingRecursiveImagePyramid") -(Transform "BSplineTransform") -(Interpolator "BSplineInterpolator") -(Optimizer "AdaptiveStochasticGradientDescent") -(ResampleInterpolator "FinalBSplineInterpolator") -(Resampler "DefaultResampler") -(Metric "AdvancedMattesMutualInformation") - -// ::::::::::::::::::::::::::::: Parameters to tune ::::::::::::::::::::::::::::::::::::::: - -// :::: Pyramid -(NumberOfResolutions 3) -(ImagePyramidSchedule 4 4 2 2 1 1) - - -// :::: Optimizer - StandardGradientDescent :::: - -// Maximum number of iterations -(MaximumNumberOfIterations 2048) - -//SP: Param_a in each resolution level. a_k = a/(A+k+1)^alpha -// MI around 1000.0 -(SP_a 10000.0 ) - - -// :::: ImageSampler :::: - -// Number of sample (2000 - 5000) -(NumberOfSpatialSamples 256 ) - -// If UseRandomSampleRegion is set to "false", the sampler draws samples from the entire image domain. -// When set to "true", the sampler randomly selects one voxel, and then selects the remaining -// samples in a square neighbourhood (in mm) around that voxel (localized similarity measure). -(UseRandomSampleRegion "true") -(SampleRegionSize 50.0 50.0) - - -// :::: Transform :::: -// Grid of control points -// This grid is defined by the spacing between the grid nodes, in voxel size -// For each resolution level you can define a different grid spacing. This is what we call multi-grid. -// The GridSpacingSchedule defines the multiplication factors for all resolution levels. -(FinalGridSpacingInPhysicalUnits 10.0 10.0) -(GridSpacingSchedule 4.0 4.0 2.0 2.0 1.0 1.0) - - -// :::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::: - - -// :::: Transform :::: -// Whether transforms are combined by composition or by addition. -// In generally, Compose is the best option in most cases. -// It does not influence the results very much. -(HowToCombineTransforms "Compose") - - -// :::: Several :::: -(ErodeMask "false" ) -(WriteTransformParametersEachIteration "false") -(WriteResultImage "false") -(ResultImageFormat "nii.gz") -(CompressResultImage "true") -(WriteResultImageAfterEachResolution "false") -(ShowExactMetricValue "false") -(ResultImagePixelType "float") - - -// :::: Metric :::: -//Number of grey level bins in each resolution level: -(NumberOfHistogramBins 32 ) -(FixedLimitRangeRatio 0.0) -(MovingLimitRangeRatio 0.0) -(FixedKernelBSplineOrder 3) -(MovingKernelBSplineOrder 3) -(UseFastAndLowMemoryVersion "true") - - -// :::: ImageSampler :::: -(ImageSampler "RandomCoordinate") -(FixedImageBSplineInterpolationOrder 1 ) -(NewSamplesEveryIteration "true") -(CheckNumberOfSamples "false") -(MaximumNumberOfSamplingAttempts 10) - - -// :::: Optimizer - StandardGradientDescent :::: -//SP: Param_A in each resolution level. a_k = a/(A+k+1)^alpha -(SP_A 100.0 ) -//SP: Param_alpha in each resolution level. a_k = a/(A+k+1)^alpha -(SP_alpha 0.6 ) - - -// :::: Interpolator and Resampler :::: -//Order of B-Spline interpolation used in each resolution level: -// It may improve accuracy if you set this to 3. Never use 0. -(BSplineInterpolationOrder 1) - -//Order of B-Spline interpolation used for applying the final -// deformation. -// 3 gives good accuracy. -// 1 gives worse accuracy (linear interpolation) -// 0 gives worst accuracy, but may be appropriate for -// binary images; this would be equivalent to nearest neighbor -// interpolation. -(FinalBSplineInterpolationOrder 3) - -//Default pixel value for pixels that come from outside the picture: -(DefaultPixelValue 0) - -(MaximumStepLength 0.7) - diff --git a/build/lib/WORC/fastrconfig/WORC_config.py b/build/lib/WORC/fastrconfig/WORC_config.py deleted file mode 100644 index 0445195e..00000000 --- a/build/lib/WORC/fastrconfig/WORC_config.py +++ /dev/null @@ -1,46 +0,0 @@ -#!/usr/bin/env python - -# Copyright 2016-2019 Biomedical Imaging Group Rotterdam, Departments of -# Medical Informatics and Radiology, Erasmus MC, Rotterdam, The Netherlands -# -# 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 site -import os -import sys - - -# Get directory in which packages are installed -try: - packagedir = site.getsitepackages()[0] -except AttributeError: - # Inside virtualenvironment, so getsitepackages doesnt work. - paths = sys.path - for p in paths: - if os.path.isdir(p) and os.path.basename(p) == 'site-packages': - packagedir = p - -# Add the WORC FASTR tools and type paths -tools_path = [os.path.join(packagedir, 'WORC', 'resources', 'fastr_tools')] + tools_path -types_path = [os.path.join(packagedir, 'WORC', 'resources', 'fastr_types')] + types_path - -# Mounts accessible to fastr virtual file system -mounts['worc_example_data'] = os.path.join(packagedir, 'WORC', 'exampledata') -mounts['apps'] = os.path.expanduser(os.path.join('~', 'apps')) -mounts['output'] = os.path.expanduser(os.path.join('~', 'WORC', 'output')) -mounts['test'] = os.path.join(packagedir, 'WORC', 'resources', 'fastr_tests') - -# The ITKFile type requires a preferred type when no specification is given. -# We will set it to Nifti, but you may change this. -preferred_types += ["NiftiImageFileCompressed"] diff --git a/build/lib/WORC/featureprocessing/Imputer.py b/build/lib/WORC/featureprocessing/Imputer.py deleted file mode 100644 index 9e4e9042..00000000 --- a/build/lib/WORC/featureprocessing/Imputer.py +++ /dev/null @@ -1,84 +0,0 @@ -#!/usr/bin/env python - -# Copyright 2016-2019 Biomedical Imaging Group Rotterdam, Departments of -# Medical Informatics and Radiology, Erasmus MC, Rotterdam, The Netherlands -# -# 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. - -from sklearn.impute import SimpleImputer -from missingpy import KNNImputer - - -class Imputer(object): - """Module for feature imputation.""" - - def __init__(self, missing_values='nan', strategy='mean', - n_neighbors=5): - ''' - Imputation of feature values using either sklearn, missingpy or - (WIP) fancyimpute approaches. - - Parameters - ---------- - missing_values : number, string, np.nan (default) or None - The placeholder for the missing values. All occurrences of - `missing_values` will be imputed. - - - strategy : string, optional (default="mean") - The imputation strategy. - - Supported using sklearn: - - If "mean", then replace missing values using the mean along - each column. Can only be used with numeric data. - - If "median", then replace missing values using the median along - each column. Can only be used with numeric data. - - If "most_frequent", then replace missing using the most frequent - value along each column. Can be used with strings or numeric data. - - If "constant", then replace missing values with fill_value. Can be - used with strings or numeric data. - - Supported using missingpy: - - If 'knn', then use a nearest neighbor search. Can be - used with strings or numeric data. - - WIP: More strategies using fancyimpute - - n_neighbors : int, optional (default = 5) - Number of neighboring samples to use for imputation if method - is knn. - - ''' - - # Set parameters to objects - self.missing_values = missing_values - self.strategy = strategy - self.n_neighbors = n_neighbors - - # Depending on the imputations strategy, use a specific toolbox - if strategy in ['mean', 'median', 'most_frequent', 'constant']: - self.Imputer =\ - SimpleImputer(missing_values=self.missing_values, - strategy=self.strategy) - elif strategy == 'knn': - if missing_values == 'nan': - # Slightly different API for missingpy - self.missing_values = 'NaN' - self.Imputer = KNNImputer(missing_values=self.missing_values, - n_neighbors=self.n_neighbors) - - def fit(self, X, y=None): - self.Imputer.fit(X, y) - - def transform(self, X): - return self.Imputer.transform(X) diff --git a/build/lib/WORC/featureprocessing/Relief.py b/build/lib/WORC/featureprocessing/Relief.py deleted file mode 100644 index c332fd58..00000000 --- a/build/lib/WORC/featureprocessing/Relief.py +++ /dev/null @@ -1,232 +0,0 @@ -#!/usr/bin/env python - -# Copyright 2016-2019 Biomedical Imaging Group Rotterdam, Departments of -# Medical Informatics and Radiology, Erasmus MC, Rotterdam, The Netherlands -# -# 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. - -from sklearn.base import BaseEstimator -from sklearn.feature_selection.base import SelectorMixin -import numpy as np -import sklearn.neighbors as nn -# from skrebate import ReliefF - - -class SelectMulticlassRelief(BaseEstimator, SelectorMixin): - ''' - Object to fit feature selection based on the type group the feature belongs - to. The label for the feature is used for this procedure. - ''' - def __init__(self, n_neighbours=3, sample_size=1, distance_p=2, numf=None): - ''' - Parameters - ---------- - n_neightbors: integer - Number of nearest neighbours used. - - sample_size: float - Percentage of samples used to calculate score - - distance_p: integer - Parameter in minkov distance usde for nearest neighbour calculation - - numf: integer, default None - Number of important features to be selected with respect to their - ranking. If None, all are used. - - ''' - self.no_neighbours = n_neighbours - self.sample_size = sample_size - self.distance_p = distance_p - self.numf = numf - - def fit(self, X, y): - ''' - Select only features specificed by parameters per patient. - - Parameters - ---------- - feature_values: numpy array, mandatory - Array containing feature values used for model_selection. - Number of objects on first axis, features on second axis. - - feature_labels: list, mandatory - Contains the labels of all features used. The index in this - list will be used in the transform funtion to select features. - ''' - # Multiclass relief function - if len(y.shape) > 1: - indices, _ = self.multi_class_relief(X, y, - nb=self.no_neighbours, - sample_size=self.sample_size, - distance_p=self.distance_p, - numf=self.numf) - else: - indices, _ = self.single_class_relief(X, y, - nb=self.no_neighbours, - sample_size=self.sample_size, - distance_p=self.distance_p, - numf=self.numf) - - self.selectrows = indices - - def transform(self, inputarray): - ''' - Transform the inputarray to select only the features based on the - result from the fit function. - - Parameters - ---------- - inputarray: numpy array, mandatory - Array containing the items to use selection on. The type of - item in this list does not matter, e.g. floats, strings etc. - ''' - return np.asarray([np.asarray(x)[self.selectrows].tolist() for x in inputarray]) - # return self.ReliefF.transform(inputarray) - - def _get_support_mask(self): - # NOTE: Method is required for the Selector class, but can be empty - pass - - def multi_class_relief(self, feature_set, label_set, nb=3, sample_size=1, - distance_p=2, numf=None): - - nrow, ncol = feature_set.shape - nlabel = label_set.shape[1] - sample_list = np.random.choice(range(nrow), int(nrow * sample_size), replace=False) - - feature_score = np.zeros((1, ncol)) - - prob = label_set.mean(axis=0) - n_sample = dict() - pair_score = dict() - - # find positive and negative samples for each label - for label in range(nlabel): - n_sample[label, 0] = [] - n_sample[label, 1] = [] - for row in sample_list: - if label_set[row, label] == 0: - n_sample[label, 0].append(row) - else: - n_sample[label, 1].append(row) - - for label1 in range(nlabel - 1): - for label2 in range(label1 + 1, nlabel): - pair_score[label1, label2] = np.zeros((1, ncol)) - if n_sample[label1, 0].__len__() >= nb and n_sample[label1, 1].__len__() >= nb: - # find near miss for label1 - n_neighbor_finder = nn.NearestNeighbors(n_neighbors=nb, p=distance_p) - n_neighbor_finder.fit(np.asarray(feature_set[n_sample[label1, 0], :])) - near_miss = n_neighbor_finder.kneighbors(np.asarray(feature_set[n_sample[label1, 0], :]), return_distance=False) - - # find near hit for label1 - p_neighbor_finder = nn.NearestNeighbors(n_neighbors=nb, p=distance_p) - p_neighbor_finder.fit(np.asarray(feature_set[n_sample[label1, 1], :])) - near_hit = p_neighbor_finder.kneighbors(np.asarray(feature_set[n_sample[label1, 1], :]), return_distance=False) - - for label2 in range(label1 + 1, nlabel): - for r in range(near_miss.__len__()): - for c in range(nb): - if label_set[near_miss[r, c], label2] == 1: - pair_score[label1, label2] += 1.0 * (prob[label2] / (1 - prob[label1])) *\ - np.abs(feature_set[n_sample[label1, 0][r], :] - - feature_set[near_miss[r, c], :]) / nb - for r in range(n_sample[label1, 1].__len__()): - for c in range(nb): - if label_set[near_hit[r, c], label2] == 1: - pair_score[label1, label2] -= (prob[label2] /(1 - prob[label1])) *\ - np.abs(feature_set[n_sample[label1, 1][r], :] - - feature_set[near_hit[r, c], :]) / nb - - for label1 in range(nlabel - 1): - for label2 in range(label1 + 1, nlabel): - feature_score += pair_score[label1, label2] - - feature_score = feature_score[0] - sorted_index = feature_score.argsort().tolist() - sorted_index.reverse() - sorted_index = np.array(sorted_index) - feature_score = feature_score[sorted_index] - - if numf is None: - numf = len(sorted_index) - - # Make sure we select at maximum all features - numf = min(numf, len(sorted_index)) - sorted_index = sorted_index[0:numf] - - return sorted_index, feature_score - - def single_class_relief(self, feature_set, label_set, nb=3, sample_size=1, - distance_p=2, numf=None): - - nrow, ncol = feature_set.shape - sample_list = np.random.choice(range(nrow), int(nrow * sample_size), replace=False) - - feature_score = np.zeros((1, ncol)) - - n_sample = dict() - - # find positive and negative samples for each label - n_sample[0] = [] - n_sample[1] = [] - for row in sample_list: - if label_set[row] == 0: - n_sample[0].append(row) - else: - n_sample[1].append(row) - - if n_sample[0].__len__() >= nb and n_sample[1].__len__() >= nb: - # find near miss for label1 - n_neighbor_finder = nn.NearestNeighbors(n_neighbors=nb, p=distance_p) - n_neighbor_finder.fit(np.asarray(feature_set[n_sample[0], :])) - near_miss = n_neighbor_finder.kneighbors(np.asarray(feature_set[n_sample[0], :]), return_distance=False) - - # find near hit for label1 - p_neighbor_finder = nn.NearestNeighbors(n_neighbors=nb, p=distance_p) - p_neighbor_finder.fit(np.asarray(feature_set[n_sample[1], :])) - near_hit = p_neighbor_finder.kneighbors(np.asarray(feature_set[n_sample[1], :]), return_distance=False) - - for r in range(near_miss.__len__()): - for c in range(nb): - if label_set[near_miss[r, c]] == 1: - feature_score += 1.0 * np.abs(feature_set[n_sample[0][r], :] - - feature_set[near_miss[r, c], :]) / nb - for r in range(n_sample[1].__len__()): - for c in range(nb): - if label_set[near_hit[r, c]] == 1: - feature_score -= 1.0 * np.abs(feature_set[n_sample[1][r], :] - - feature_set[near_hit[r, c], :]) / nb - - feature_score = feature_score[0] - sorted_index = feature_score.argsort().tolist() - sorted_index.reverse() - sorted_index = np.array(sorted_index) - feature_score = feature_score[sorted_index] - - if numf is None: - numf = len(sorted_index) - - # Make sure we select at maximum all features - numf = min(numf, len(sorted_index)) - sorted_index = sorted_index[0:numf] - - return sorted_index, feature_score - - - # def single_class_relief_skrebate(self, feature_set, label_set, nb=3, sample_size=1, - # distance_p=2, numf=None): - # self.ReliefF = ReliefF(n_features_to_select=numf, n_neighbors=nb, n_jobs=1) - # self.ReliefF.fit(feature_set, label_set) - # return None, None diff --git a/build/lib/WORC/featureprocessing/SelectGroups.py b/build/lib/WORC/featureprocessing/SelectGroups.py deleted file mode 100644 index d1086d49..00000000 --- a/build/lib/WORC/featureprocessing/SelectGroups.py +++ /dev/null @@ -1,133 +0,0 @@ -#!/usr/bin/env python - -# Copyright 2016-2019 Biomedical Imaging Group Rotterdam, Departments of -# Medical Informatics and Radiology, Erasmus MC, Rotterdam, The Netherlands -# -# 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. - -from sklearn.base import BaseEstimator -from sklearn.feature_selection.base import SelectorMixin -import numpy as np - - -class SelectGroups(BaseEstimator, SelectorMixin): - ''' - Object to fit feature selection based on the type group the feature belongs - to. The label for the feature is used for this procedure. - ''' - def __init__(self, parameters): - ''' - Parameters - ---------- - parameters: dict, mandatory - Contains the settings for the groups to be selected. Should - contain the settings for the following groups: - - histogram_features - - shape_features - - orientation_features - - semantic_features - - patient_features - - coliage_features - - phase_features - - vessel_features - - log_features - - texture_Gabor_features - - texture_GLCM_features - - texture_GLCMMS_features - - texture_GLRLM_features - - texture_GLSZM_features - - texture_NGTDM_features - - texture_LBP_features - - ''' - params = list() - if parameters['histogram_features'] == 'True': - params.append('hf_') - if parameters['shape_features'] == 'True': - params.append('sf_') - if parameters['orientation_features'] == 'True': - params.append('of_') - if parameters['semantic_features'] == 'True': - params.append('semf_') - if parameters['patient_features'] == 'True': - params.append('pf_') - if parameters['coliage_features'] == 'True': - params.append('cf_') - if parameters['phase_features'] == 'True': - params.append('phasef_') - if parameters['vessel_features'] == 'True': - params.append('vf_') - if parameters['log_features'] == 'True': - params.append('logf_') - - if 'texture_features' in parameters.keys(): - # Backwards compatability - if parameters['texture_features'] == 'True': - params.append('tf_') - elif parameters['texture_features'] == 'False': - pass - else: - params.append('tf_' + parameters['texture_features']) - else: - # Hyperparameter per feature group - if parameters['texture_gabor_features'] == 'True': - params.append('tf_Gabor') - if parameters['texture_glcm_features'] == 'True': - params.append('tf_GLCM_') - if parameters['texture_glcmms_features'] == 'True': - params.append('tf_GLCMMS') - if parameters['texture_glrlm_features'] == 'True': - params.append('tf_GLRLM') - if parameters['texture_glszm_features'] == 'True': - params.append('tf_GLSZM') - if parameters['texture_ngtdm_features'] == 'True': - params.append('tf_NGTDM') - if parameters['texture_lbp_features'] == 'True': - params.append('tf_LBP') - - self.parameters = params - - def fit(self, feature_labels): - ''' - Select only features specificed by parameters per patient. - - Parameters - ---------- - feature_labels: list, optional - Contains the labels of all features used. The index in this - list will be used in the transform funtion to select features. - ''' - # Remove NAN - selectrows = list() - for num, l in enumerate(feature_labels): - if any(x in l for x in self.parameters): - selectrows.append(num) - - self.selectrows = selectrows - - def transform(self, inputarray): - ''' - Transform the inputarray to select only the features based on the - result from the fit function. - - Parameters - ---------- - inputarray: numpy array, mandatory - Array containing the items to use selection on. The type of - item in this list does not matter, e.g. floats, strings etc. - ''' - return np.asarray([np.asarray(x)[self.selectrows].tolist() for x in inputarray]) - - def _get_support_mask(self): - # NOTE: Method is required for the Selector class, but can be empty - pass diff --git a/build/lib/WORC/featureprocessing/SelectIndividuals.py b/build/lib/WORC/featureprocessing/SelectIndividuals.py deleted file mode 100644 index d66748bf..00000000 --- a/build/lib/WORC/featureprocessing/SelectIndividuals.py +++ /dev/null @@ -1,82 +0,0 @@ -#!/usr/bin/env python - -# Copyright 2016-2019 Biomedical Imaging Group Rotterdam, Departments of -# Medical Informatics and Radiology, Erasmus MC, Rotterdam, The Netherlands -# -# 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. - -from sklearn.base import BaseEstimator -from sklearn.feature_selection.base import SelectorMixin -import numpy as np - - -class SelectIndividuals(BaseEstimator, SelectorMixin): - ''' - Object to fit feature selection based on the type group the feature belongs - to. The label for the feature is used for this procedure. - ''' - def __init__(self, parameters=['hf_mean', 'sf_compactness']): - ''' - Parameters - ---------- - parameters: dict, mandatory - Contains the settings for the groups to be selected. Should - contain the settings for the following groups: - - histogram_features - - shape_features - - orientation_features - - semantic_features - - patient_features - - coliage_features - - phase_features - - vessel_features - - log_features - - texture_features - - ''' - self.parameters = parameters - - def fit(self, feature_labels): - ''' - Select only features specificed by parameters per patient. - - Parameters - ---------- - feature_labels: list, optional - Contains the labels of all features used. The index in this - list will be used in the transform funtion to select features. - ''' - # Remove NAN - selectrows = list() - for num, l in enumerate(feature_labels): - if any(x in l for x in self.parameters): - selectrows.append(num) - - self.selectrows = selectrows - - def transform(self, inputarray): - ''' - Transform the inputarray to select only the features based on the - result from the fit function. - - Parameters - ---------- - inputarray: numpy array, mandatory - Array containing the items to use selection on. The type of - item in this list does not matter, e.g. floats, strings etc. - ''' - return np.asarray([np.asarray(x)[self.selectrows].tolist() for x in inputarray]) - - def _get_support_mask(self): - # NOTE: Method is required for the Selector class, but can be empty - pass diff --git a/build/lib/WORC/featureprocessing/StatisticalTestFeatures.py b/build/lib/WORC/featureprocessing/StatisticalTestFeatures.py deleted file mode 100644 index 72437bef..00000000 --- a/build/lib/WORC/featureprocessing/StatisticalTestFeatures.py +++ /dev/null @@ -1,173 +0,0 @@ -#!/usr/bin/env python - -# Copyright 2016-2019 Biomedical Imaging Group Rotterdam, Departments of -# Medical Informatics and Radiology, Erasmus MC, Rotterdam, The Netherlands -# -# 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 numpy as np -import PREDICT.IOparser.config_io_classifier as config_io -import os -from scipy.stats import ttest_ind, ranksums, mannwhitneyu -import csv -from PREDICT.trainclassifier import load_features - - -def StatisticalTestFeatures(features, patientinfo, config, output=None, - verbose=True): - ''' - Perform several statistical tests on features, such as a student t-test. - Useage is similar to trainclassifier. - - Parameters - ---------- - features: string, mandatory - contains the paths to all .hdf5 feature files used. - modalityname1=file1,file2,file3,... modalityname2=file1,... - Thus, modalities names are always between a space and a equal - sign, files are split by commas. We assume that the lists of - files for each modality has the same length. Files on the - same position on each list should belong to the same patient. - - patientinfo: string, mandatory - Contains the path referring to a .txt file containing the - patient label(s) and value(s) to be used for learning. See - the Github Wiki for the format. - - config: string, mandatory - path referring to a .ini file containing the parameters - used for feature extraction. See the Github Wiki for the possible - fields and their description. - - # TODO: outputs - - verbose: boolean, default True - print final feature values and labels to command line or not. - - ''' - # Load variables from the config file - config = config_io.load_config(config) - - if type(patientinfo) is list: - patientinfo = ''.join(patientinfo) - - if type(config) is list: - config = ''.join(config) - - if type(output) is list: - output = ''.join(output) - - # Create output folder if required - if not os.path.exists(os.path.dirname(output)): - os.makedirs(os.path.dirname(output)) - - label_type = config['Genetics']['label_names'] - - # Read the features and classification data - print("Reading features and label data.") - label_data, image_features =\ - load_features(features, patientinfo, label_type) - - # Extract feature labels and put values in an array - feature_labels = image_features[0][1] - feature_values = np.zeros([len(image_features), len(feature_labels)]) - for num, x in enumerate(image_features): - feature_values[num, :] = x[0] - - # ----------------------------------------------------------------------- - # Perform statistical tests - print("Performing statistical tests.") - label_value = label_data['mutation_label'] - label_name = label_data['mutation_name'] - - header = list() - subheader = list() - for i_name in label_name: - header.append(str(i_name[0])) - header.append('') - header.append('') - header.append('') - header.append('') - header.append('') - - subheader.append('Label') - subheader.append('Ttest') - subheader.append('Welch') - subheader.append('Wilcoxon') - subheader.append('Mann-Whitney') - subheader.append('') - - # Open the output file - if output is not None: - myfile = open(output, 'wb') - wr = csv.writer(myfile, quoting=csv.QUOTE_ALL) - wr.writerow(header) - wr.writerow(subheader) - - savedict = dict() - for i_class, i_name in zip(label_value, label_name): - savedict[i_name[0]] = dict() - pvalues = list() - pvalueswelch = list() - pvalueswil = list() - pvaluesmw = list() - - for num, fl in enumerate(feature_labels): - fv = feature_values[:, num] - classlabels = i_class.ravel() - - class1 = [i for j, i in enumerate(fv) if classlabels[j] == 1] - class2 = [i for j, i in enumerate(fv) if classlabels[j] == 0] - - pvalues.append(ttest_ind(class1, class2)[1]) - pvalueswelch.append(ttest_ind(class1, class2, equal_var=False)[1]) - pvalueswil.append(ranksums(class1, class2)[1]) - try: - pvaluesmw.append(mannwhitneyu(class1, class2)[1]) - except ValueError as e: - print("[PREDICT Warning] " + str(e) + '. Replacing metric value by 1.') - pvaluesmw.append(1) - - # Sort based on p-values: - pvalues = np.asarray(pvalues) - indices = np.argsort(pvalues) - pvalues = pvalues[indices].tolist() - feature_labels_o = np.asarray(feature_labels)[indices].tolist() - pvalueswelch = np.asarray(pvalueswelch)[indices].tolist() - pvalueswil = np.asarray(pvalueswil)[indices].tolist() - pvaluesmw = np.asarray(pvaluesmw)[indices].tolist() - - savedict[i_name[0]]['ttest'] = pvalues - savedict[i_name[0]]['welch'] = pvalueswelch - savedict[i_name[0]]['wil'] = pvalueswil - savedict[i_name[0]]['mw'] = pvaluesmw - savedict[i_name[0]]['labels'] = feature_labels_o - - if output is not None: - for num in range(0, len(savedict[i_name[0]]['ttest'])): - writelist = list() - for i_name in savedict.keys(): - labeldict = savedict[i_name] - writelist.append(labeldict['labels'][num]) - writelist.append(labeldict['ttest'][num]) - writelist.append(labeldict['welch'][num]) - writelist.append(labeldict['wil'][num]) - writelist.append(labeldict['mw'][num]) - writelist.append('') - - wr.writerow(writelist) - - print("Saved data!") - - return savedict diff --git a/build/lib/WORC/featureprocessing/StatisticalTestThreshold.py b/build/lib/WORC/featureprocessing/StatisticalTestThreshold.py deleted file mode 100644 index db551fc0..00000000 --- a/build/lib/WORC/featureprocessing/StatisticalTestThreshold.py +++ /dev/null @@ -1,105 +0,0 @@ -#!/usr/bin/env python - -# Copyright 2016-2019 Biomedical Imaging Group Rotterdam, Departments of -# Medical Informatics and Radiology, Erasmus MC, Rotterdam, The Netherlands -# -# 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. - -from sklearn.base import BaseEstimator -from sklearn.feature_selection.base import SelectorMixin -import numpy as np -from scipy.stats import ttest_ind, ranksums, mannwhitneyu - - -class StatisticalTestThreshold(BaseEstimator, SelectorMixin): - ''' - Object to fit feature selection based on statistical tests. - ''' - def __init__(self, metric='ttest', threshold=0.05): - ''' - Parameters - ---------- - metric: string, default 'ttest' - Statistical test used for selection. Options are ttest, - Welch, Wilcoxon, MannWhitneyU - threshold: float, default 0.05 - Threshold for p-value in order for feature to be selected - - ''' - self.metric = metric - self.threshold = threshold - - def fit(self, X_train, Y_train): - ''' - Select only features specificed by the metric and threshold per patient. - - Parameters - ---------- - X_train: numpy array, mandatory - Array containing feature values used for model_selection. - Number of objects on first axis, features on second axis. - - Y_train: numpy array, mandatory - Array containing the binary labels for each object in X_train. - ''' - - self.selectrows = list() - self.metric_values = list() - - # Set the metric function - if self.metric == 'ttest': - self.metric_function = ttest_ind - self.parameters = {'equal_var': True} - elif self.metric == 'Welch': - self.metric_function = ttest_ind - self.parameters = {'equal_var': False} - elif self.metric == 'Wilcoxon': - self.metric_function = ranksums - self.parameters = {} - elif self.metric == 'MannWhitneyU': - self.metric_function = mannwhitneyu - self.parameters = {} - - # Perform the statistical test for each feature - for n_feat in range(0, X_train.shape[1]): - fv = X_train[:, n_feat] - - class1 = [i for j, i in enumerate(fv) if Y_train[j] == 1] - class2 = [i for j, i in enumerate(fv) if Y_train[j] == 0] - - try: - metric_value = self.metric_function(class1, class2, **self.parameters)[1] - except ValueError as e: - print("[PREDICT Warning] " + str(e) + '. Replacing metric value by 1.') - metric_value = 1 - - self.metric_values.append(metric_value) - if metric_value < self.threshold: - self.selectrows.append(n_feat) - - def transform(self, inputarray): - ''' - Transform the inputarray to select only the features based on the - result from the fit function. - - Parameters - ---------- - inputarray: numpy array, mandatory - Array containing the items to use selection on. The type of - item in this list does not matter, e.g. floats, strings etc. - ''' - return np.asarray([np.asarray(x)[self.selectrows].tolist() for x in inputarray]) - - def _get_support_mask(self): - # NOTE: metric is required for the Selector class, but can be empty - pass diff --git a/build/lib/WORC/featureprocessing/VarianceThreshold.py b/build/lib/WORC/featureprocessing/VarianceThreshold.py deleted file mode 100644 index 9d43f5c9..00000000 --- a/build/lib/WORC/featureprocessing/VarianceThreshold.py +++ /dev/null @@ -1,113 +0,0 @@ -#!/usr/bin/env python - -# Copyright 2016-2019 Biomedical Imaging Group Rotterdam, Departments of -# Medical Informatics and Radiology, Erasmus MC, Rotterdam, The Netherlands -# -# 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. - -from sklearn.feature_selection import VarianceThreshold -from sklearn.base import BaseEstimator -from sklearn.feature_selection.base import SelectorMixin -import numpy as np -import PREDICT.addexceptions as ae - - -class VarianceThresholdMean(BaseEstimator, SelectorMixin): - ''' - Select features based on variance among objects. Similar to VarianceThreshold - from sklearn, but does take the mean of the feature into account. - ''' - def __init__(self, threshold): - self.threshold = threshold - - def fit(self, image_features): - selectrows = list() - means = np.mean(image_features, axis=0) - variances = np.var(image_features, axis=0) - - for i in range(image_features.shape[1]): - if variances[i] > self.threshold*(1-self.threshold)*means[i]: - selectrows.append(i) - - self.selectrows = selectrows - return self - - def transform(self, inputarray): - ''' - Transform the inputarray to select only the features based on the - result from the fit function. - Parameters - ---------- - inputarray: numpy array, mandatory - Array containing the items to use selection on. The type of - item in this list does not matter, e.g. floats, strings etc. - ''' - return np.asarray([np.asarray(x)[self.selectrows].tolist() for x in inputarray]) - - def _get_support_mask(self): - # NOTE: Method is required for the Selector class, but can be empty - pass - - -def selfeat_variance(image_features, labels=None, thresh=0.99, - method='nomean'): - ''' - Select features using a variance threshold. - - Parameters - ---------- - image_features: numpy array, mandatory - Array containing the feature values to apply the variance threshold - selection on. The rows correspond to the patients, the column to the - features. - - labels: numpy array, optional - Array containing the labels of the corresponding features. Array - should therefore have the same shape as the image_features array. - - thresh: float, default 0.99 - Threshold to be used as lower boundary for feature variance among - patients. - method: string, default nomean. - Method to use for selection. Default: do not use the mean of the - features. Other valid option is 'mean'. - - Returns - ---------- - image_features: numpy array - Transformed features array. - - labels: list or None - When labels are given, returns the transformed labels. That object - contains a list of all label names kept. - - sel: VarianceThreshold object - The fitted variance threshold object. - - ''' - if method == 'nomean': - sel = VarianceThreshold(threshold=thresh*(1 - thresh)) - elif method == 'mean': - sel = VarianceThresholdMean(threshold=thresh*(1 - thresh)) - else: - raise ae.PREDICTKeyError(('Invalid method {} given for ' + - 'VarianceThreshold feature selection. ' + - 'Should be "mean" or ' + - '"nomean".').format(str(method))) - - sel = sel.fit(image_features) - image_features = sel.transform(image_features) - if labels is not None: - labels = sel.transform(labels) - - return image_features, labels, sel diff --git a/build/lib/WORC/featureprocessing/__init__.py b/build/lib/WORC/featureprocessing/__init__.py deleted file mode 100644 index 632a8112..00000000 --- a/build/lib/WORC/featureprocessing/__init__.py +++ /dev/null @@ -1 +0,0 @@ -from .SelectGroups import SelectGroups diff --git a/build/lib/WORC/index.rst b/build/lib/WORC/index.rst deleted file mode 100644 index 155c3206..00000000 --- a/build/lib/WORC/index.rst +++ /dev/null @@ -1,95 +0,0 @@ -***** -WORC -***** - -Workflow for Optimal Radiomics Classification ---------------------------------------------- - -WORC is an open-source python package for the easy execution of end-to-end -radiomics pipelines. - -We aim to establish a general radiomics platform supporting easy -integration of other tools. With our modular build and support of -different software languages (Python, MATLAB, R, executables etc.), we want -to facilitate and stimulate collaboration, standardisation and -comparison of different radiomics approaches. By combining this in a -single framework, we hope to find an universal radiomics strategy that -can address various problems. - -WORC is open-source (licensed under the Apache 2.0 license) and hosted on Github at `https://github.com/MStarmans91/WORC `_ - -For support, go to the issues on the Gibhub page: `https://github.com/MStarmans91/WORC/issues `_ - -To get yourself a copy, see the :ref:`installation-chapter` - -The official documentation can be found at `WORC.readthedocs.io `_ - -For Tutorials on WORC, both for beginner and advanced WORCflows, please - -see our Tutorial repository https://github.com/MStarmans91/WORCTutorial. - - -The article on WORC is currently in press. WORC has been presented in the following: - - `M. P. A. Starmans, S. R. van der Voort, M. Vos, F. Incekara, J. J. Visser, M. Smits, M. G. Thomeer, W. J. Niessen and S. Klein. "Fully automatic construction of optimal radiomics workflows." European Conference of Radiology (ECR) 2019. `_ - - `Martijn P. A. Starmans, Sebastian R. van der Voort, Razvan L. Miclea, Melissa Vos, Fatih Incekara, Milea J.M. Timbergen, Maarten M.J. Wijnenga, Guillaume A. Padmos, G.H.J. van Leenders, George Kapsas, Martin J. van den Bent, Arnaud J.P.E. Vincent, Dirk J. Grünhagen, Cornelis Verhoef, Stefan Sleijfer, Jacob J. Visser, Marion Smits, Maarten, G. Thomeer, Wiro J. Niessen, and Stefan Klein. "Harmonizing radiomics among applications through adaptive workflow optimization." European Society of Medical Imaging Informatics (EuSoMII) Annual Meeting 2019. `_ - -WORC has been used in the following studies: - - `M. P. A. Starmans, R. Miclea, S. R. van der Voort, W. J. Niessen, M. G. Thomeer and S. Klein. "Classification of malignant and benign liver tumors using a radiomics approach." Proceedings Volume 10574, Medical Imaging 2018: Image Processing; 105741D (2018) . `_ - - `Milea J.M. Timbergen*, Martijn P. A. Starmans*, Melissa Vos, Sebastian R. van der Voort, Guillaume A. Padmos, Wouter Kessels, Wiro J. Niessen, Geert J.L.H. van Leenders, Dirk J. Grünhagen, Stefan Sleijfer, Cornelis Verhoef, Stefan Klein and Jacob J. Visser. "Mutation stratification of desmoid-type fibromatosis using a Radiomics approach." Desmoid Tumor Research Foundation (DTRF) 2018. `_ - - `Melissa Vos*, Martijn P. A. Starmans*, Milea J.M. Timbergen, Sebastian R. van der Voort, Guillaume A. Padmos, Wouter Kessels, Wiro J. Niessen, Geert J.L.H. van Leenders, Dirk J. Grünhagen, Stefan Sleijfer, Cornelis Verhoef, Stefan Klein and Jacob J. Visser. "Differentiating well-differentiated liposarcomas from lipomas using a Radiomics approach." ConnectiveTissueOncologySociety (CTOS) 2018.`_ - - `Milea J.M. Timbergen*, Martijn P. A. Starmans*, Melissa Vos, Sebastian R. van der Voort, Guillaume A. Padmos, Wouter Kessels, Wiro J. Niessen, Geert J.L.H. van Leenders, Dirk J. Grünhagen, Stefan Sleijfer, Cornelis Verhoef, Stefan Klein and Jacob J. Visser. "Mutation stratification of desmoid-type fibromatosis using a Radiomics approach." ConnectiveTissueOncologySociety (CTOS) 2018.`_ - - `Martijn P. A. Starmans, Sebastian R. van der Voort, Razvan L. Miclea, Melissa Vos, Fatih Incekara, Milea J.M. Timbergen, Maarten M.J. Wijnenga, Guillaume A. Padmos, Wouter Kessels, G.H.J. van Leenders, George Kapsas, Martin J. van den Bent, Arnaud J.P.E. Vincent, Dirk J. Grünhagen, Cornelis Verhoef, Stefan Sleijfer, Jacob J. Visser, Marion Smits, Maarten, G. Thomeer, Wiro J. Niessen, and Stefan Klein. "Fully Automatic Construction of Optimal Radiomics Workflows ." Bio-Medical Engineering (BME) Conference 2019. `_ - - `M. P. A. Starmans, R. Miclea, S. R. van der Voort, W. J. Niessen, S. Klein and M. G. Thomeer. "Classification of malignant and benign liver tumours using a radiomics approach." European Conference of Radiology (ECR) 2019. `_ - - `M. P. A. Starmans, A. Blazevic, S. R. van der Voort, T. Brabander, J. Hofland, W. J. Niessen, W. W. de Herder and S. Klein. "Prediction of surgery requirement in mesenteric fibrosis on CT using a radiomics approach." European Conference of Radiology (ECR) 2019. `_ - - `Jose M. Castillo T., Martijn P. A. Starmans, Ivo Schoots, Wiro J. Niessen, Stefan Klein, Jifke F. Veenland. "CLASSIFICATION OF PROSTATE CANCER: HIGH GRADE VERSUS LOW GRADE USING A RADIOMICS APPROACH." IEEE International Symposium on Biomedical Imaging (ISBI) 2019. `_ - -WORC is made possible by contributions from the following people: Martijn Starmans, and Stefan Klein - - -WORC Documentation -=================== -.. toctree:: - :maxdepth: 3 - :glob: - - static/introduction.rst - static/quick_start.rst - static/user_manual.rst - static/configuration.rst - static/file_description.rst - static/changelog.rst - -WORC User reference -==================== - -.. toctree:: - :maxdepth: 3 - :glob: - - user_reference/* - -WORC Developer Module reference -================================ -.. toctree:: - :maxdepth: 4 - - autogen/WORC - - - -Indices and tables -================== - -* :ref:`genindex` -* :ref:`modindex` -* :ref:`search` diff --git a/build/lib/WORC/plotting/compute_CI.py b/build/lib/WORC/plotting/compute_CI.py deleted file mode 100644 index 49253538..00000000 --- a/build/lib/WORC/plotting/compute_CI.py +++ /dev/null @@ -1,91 +0,0 @@ -#!/usr/bin/env python - -# Copyright 2016-2019 Biomedical Imaging Group Rotterdam, Departments of -# Medical Informatics and Radiology, Erasmus MC, Rotterdam, The Netherlands -# -# 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 numpy as np -import scipy.stats as st -from scipy.special import logit, expit - - -def compute_confidence(metric, N_train, N_test, alpha=0.95): - """ - Function to calculate the adjusted confidence interval - metric: numpy array containing the result for a metric for the different cross validations - (e.g. If 20 cross-validations are performed it is a list of length 20 with the calculated accuracy for - each cross validation) - N_train: Integer, number of training samples - N_test: Integer, number of test_samples - alpha: float ranging from 0 to 1 to calculate the alpha*100% CI, default 95% - """ - - # Convert to floats, as python 2 rounds the divisions if we have integers - N_train = float(N_train) - N_test = float(N_test) - N_iterations = float(len(metric)) - - if N_iterations == 1.0: - print('[WORC Warning] Cannot compute a confidence interval for a single iteration.') - print('[WORC Warning] CI will be set to value of single iteration.') - metric_average = np.mean(metric) - CI = (metric_average, metric_average) - else: - metric_average = np.mean(metric) - S_uj = 1.0 / (N_iterations - 1) * np.sum((metric_average - metric)**2.0) - - metric_std = np.sqrt((1.0/N_iterations + N_test/N_train)*S_uj) - - CI = st.t.interval(alpha, N_iterations-1, loc=metric_average, scale=metric_std) - - if np.isnan(CI[0]) and np.isnan(CI[1]): - # When we cannot compute a CI, just give the averages - CI = (metric_average, metric_average) - return CI - - -def compute_confidence_logit(metric, N_train, N_test, alpha=0.95): - """ - Function to calculate the adjusted confidence interval - metric: numpy array containing the result for a metric for the different cross validations - (e.g. If 20 cross-validations are performed it is a list of length 20 with the calculated accuracy for - each cross validation) - N_train: Integer, number of training samples - N_test: Integer, number of test_samples - alpha: float ranging from 0 to 1 to calculate the alpha*100% CI, default 95% - """ - N_iterations = len(metric) - - # Compute average of logit function - # metric_logit = [logit(x) for x in metric] - logit_average = logit(np.mean(metric)) - - # Compute metric average and corrected resampled t-test metric std - metric_average = np.mean(metric) - S_uj = 1.0 / (N_iterations - 1) * np.sum((metric_average - metric)**2.0) - metric_std = np.sqrt((1.0/N_iterations + N_test/N_train)*S_uj) - - # Compute z(1-alpha/2) quantile - q1 = 1.0-(1-alpha)/2 - z = st.t.ppf(q1, N_iterations - 1) - - # Compute logit confidence intervals according to Barbiero - theta_L = logit_average - z * metric_std/(metric_average*(1 - metric_average)) - theta_U = logit_average + z * metric_std/(metric_average*(1 - metric_average)) - - # Transform back - CI = (expit(theta_L), expit(theta_U)) - - return CI diff --git a/build/lib/WORC/plotting/linstretch.py b/build/lib/WORC/plotting/linstretch.py deleted file mode 100644 index 67c20dc2..00000000 --- a/build/lib/WORC/plotting/linstretch.py +++ /dev/null @@ -1,31 +0,0 @@ -#!/usr/bin/env python - -# Copyright 2016-2019 Biomedical Imaging Group Rotterdam, Departments of -# Medical Informatics and Radiology, Erasmus MC, Rotterdam, The Netherlands -# -# 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 numpy as np - - -def linstretch(i, i_max=255, i_min=0): - ''' - Stretch the input image i pixel values from i_min to i_max - ''' - rmin = np.min(i.flatten()) # find the min. value of pixel in the image - rmax = np.max(i.flatten()) # find the max. value of pixel in the image - m = (i_max - i_min)/(rmax - rmin) # find the slope of line joining point (0, 255) to (rmin,rmax) - c = i_max - m*rmax # find the intercept of the straight line with the axis - i_stretch = m*i + c # transform the image according to new slope - - return i_stretch diff --git a/build/lib/WORC/plotting/plot_ROC.py b/build/lib/WORC/plotting/plot_ROC.py deleted file mode 100644 index 8591d0a1..00000000 --- a/build/lib/WORC/plotting/plot_ROC.py +++ /dev/null @@ -1,388 +0,0 @@ -#!/usr/bin/env python - -# Copyright 2016-2019 Biomedical Imaging Group Rotterdam, Departments of -# Medical Informatics and Radiology, Erasmus MC, Rotterdam, The Netherlands -# -# 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 matplotlib -matplotlib.use('agg') -import matplotlib.pyplot as plt - -from matplotlib2tikz import save as tikz_save -import pandas as pd -import argparse -from WORC.plotting.compute_CI import compute_confidence as CI -import numpy as np -from sklearn.metrics import roc_auc_score, auc -import csv -from WORC.plotting.plot_SVM import plot_SVM - - -def plot_single_ROC(y_truth, y_score, verbose=False): - ''' - Get the False Positive Ratio (FPR) and True Positive Ratio (TPR) - for the ground truth and score of a single estimator. These ratios - can be used to plot a Receiver Operator Characteristic (ROC) curve. - ''' - # Sort both lists based on the scores - y_truth = np.asarray(y_truth) - y_truth = np.int_(y_truth) - y_score = np.asarray(y_score) - inds = y_score.argsort() - y_truth_sorted = y_truth[inds] - y_score = y_score[inds] - - # Compute the TPR and FPR for all possible thresholds - FP = 0 - TP = 0 - fpr = list() - tpr = list() - thresholds = list() - fprev = -np.inf - i = 0 - N = float(np.bincount(y_truth)[0]) - P = float(np.bincount(y_truth)[1]) - while i < len(y_truth_sorted): - if y_score[i] != fprev: - fpr.append(1 - FP/N) - tpr.append(1 - TP/P) - thresholds.append(y_score[i]) - fprev = y_score[i] - - if y_truth_sorted[i] == 1: - TP += 1 - else: - FP += 1 - - i += 1 - - if verbose: - roc_auc = auc(fpr, tpr) - plt.figure() - lw = 2 - plt.plot(fpr, tpr, color='darkorange', - lw=lw, label='ROC curve (area = %0.2f)' % roc_auc) - plt.plot([0, 1], [0, 1], color='navy', lw=lw, linestyle='--') - plt.xlim([0.0, 1.0]) - plt.ylim([0.0, 1.05]) - plt.xlabel('False Positive Rate') - plt.ylabel('True Positive Rate') - plt.title('Receiver operating characteristic example') - plt.legend(loc="lower right") - - return fpr[::-1], tpr[::-1], thresholds[::-1] - - -def ROC_thresholding(fprt, tprt, thresholds, nsamples=20): - ''' - Construct FPR and TPR ratios at different thresholds for the scores of an - estimator. - ''' - # Combine all found thresholds in a list and create samples - T = list() - for t in thresholds: - T.extend(t) - T = sorted(T) - tsamples = np.linspace(0, len(T) - 1, nsamples) - - # Compute the fprs and tprs at the sample points - nrocs = len(fprt) - fpr = np.zeros((nsamples, nrocs)) - tpr = np.zeros((nsamples, nrocs)) - - th = list() - for n_sample, tidx in enumerate(tsamples): - tidx = int(tidx) - th.append(T[tidx]) - for i_roc in range(0, nrocs): - idx = 0 - while float(thresholds[i_roc][idx]) > float(T[tidx]) and idx < (len(thresholds[i_roc]) - 1): - idx += 1 - fpr[n_sample, i_roc] = fprt[i_roc][idx] - tpr[n_sample, i_roc] = tprt[i_roc][idx] - - return fpr, tpr, th - - -def plot_ROC_CIc(y_truth, y_score, N_1, N_2, plot='default', alpha=0.95, - verbose=False, DEBUG=False, tsamples=20): - ''' - Plot a Receiver Operator Characteristic (ROC) curve with confidence intervals. - - tsamples: number of sample points on which to determine the confidence intervals. - The sample pointsare used on the thresholds for y_score. - ''' - # Compute ROC curve and ROC area for each class - fprt = list() - tprt = list() - roc_auc = list() - thresholds = list() - for yt, ys in zip(y_truth, y_score): - fpr_temp, tpr_temp, thresholds_temp = plot_single_ROC(yt, ys) - roc_auc.append(roc_auc_score(yt, ys)) - fprt.append(fpr_temp) - tprt.append(tpr_temp) - thresholds.append(thresholds_temp) - - # Sample FPR and TPR at numerous points - fpr, tpr, th = ROC_thresholding(fprt, tprt, thresholds, tsamples) - - # Compute the confidence intervals for the ROC - CIs_tpr = list() - CIs_fpr = list() - for i in range(0, tsamples): - if i == 0: - # Point (1, 1) is always in there, but shows as (nan, nan) - CIs_fpr.append([1, 1]) - CIs_tpr.append([1, 1]) - else: - cit_fpr = CI(fpr[i, :], N_1, N_2, alpha) - CIs_fpr.append([cit_fpr[0], cit_fpr[1]]) - cit_tpr = CI(tpr[i, :], N_1, N_2, alpha) - CIs_tpr.append([cit_tpr[0], cit_tpr[1]]) - - # The point (0, 0) is also always there but not computed - CIs_fpr.append([0, 0]) - CIs_tpr.append([0, 0]) - - # Calculate also means of CIs after converting to array - CIs_tpr = np.asarray(CIs_tpr) - CIs_fpr = np.asarray(CIs_fpr) - CIs_tpr_means = np.mean(CIs_tpr, axis=1).tolist() - CIs_fpr_means = np.mean(CIs_fpr, axis=1).tolist() - - # compute AUC CI - roc_auc = CI(roc_auc, N_1, N_2, alpha) - - f = plt.figure() - lw = 2 - subplot = f.add_subplot(111) - subplot.plot(CIs_fpr_means, CIs_tpr_means, color='orange', - lw=lw, label='ROC curve (AUC = (%0.2f, %0.2f))' % (roc_auc[0], roc_auc[1])) - - for i in range(0, len(CIs_fpr_means)): - if CIs_tpr[i, 1] <= 1: - ymax = CIs_tpr[i, 1] - else: - ymax = 1 - - if CIs_tpr[i, 0] <= 0: - ymin = 0 - else: - ymin = CIs_tpr[i, 0] - - if CIs_tpr_means[i] <= 1: - ymean = CIs_tpr_means[i] - else: - ymean = 1 - - if CIs_fpr[i, 1] <= 1: - xmax = CIs_fpr[i, 1] - else: - xmax = 1 - - if CIs_fpr[i, 0] <= 0: - xmin = 0 - else: - xmin = CIs_fpr[i, 0] - - if CIs_fpr_means[i] <= 1: - xmean = CIs_fpr_means[i] - else: - xmean = 1 - - if DEBUG: - print(xmin, xmax, ymean) - print(ymin, ymax, xmean) - - subplot.plot([xmin, xmax], - [ymean, ymean], - color='black', alpha=0.15) - subplot.plot([xmean, xmean], - [ymin, ymax], - color='black', alpha=0.15) - - subplot.plot([0, 1], [0, 1], color='navy', lw=lw, linestyle='--') - plt.xlim([0.0, 1.0]) - plt.ylim([0.0, 1.05]) - plt.xlabel('False Positive Rate (1 - Specificity)') - plt.ylabel('True Positive Rate (Sensitivity)') - plt.title('Receiver operating characteristic') - plt.legend(loc="lower right") - - if verbose: - plt.show() - - f = plt.figure() - lw = 2 - subplot = f.add_subplot(111) - subplot.plot(CIs_fpr_means, CIs_tpr_means, color='darkorange', - lw=lw, label='ROC curve (AUC = (%0.2f, %0.2f))' % (roc_auc[0], roc_auc[1])) - - for i in range(0, len(CIs_fpr_means)): - if CIs_tpr[i, 1] <= 1: - ymax = CIs_tpr[i, 1] - else: - ymax = 1 - - if CIs_tpr[i, 0] <= 0: - ymin = 0 - else: - ymin = CIs_tpr[i, 0] - - if CIs_tpr_means[i] <= 1: - ymean = CIs_tpr_means[i] - else: - ymean = 1 - - if CIs_fpr[i, 1] <= 1: - xmax = CIs_fpr[i, 1] - else: - xmax = 1 - - if CIs_fpr[i, 0] <= 0: - xmin = 0 - else: - xmin = CIs_fpr[i, 0] - - if CIs_fpr_means[i] <= 1: - xmean = CIs_fpr_means[i] - else: - xmean = 1 - - subplot.plot([xmin, xmax], - [ymean, ymean], - color='black', alpha=0.15) - subplot.plot([xmean, xmean], - [ymin, ymax], - color='black', alpha=0.15) - - subplot.plot([0, 1], [0, 1], color='navy', lw=lw, linestyle='--') - plt.xlim([0.0, 1.0]) - plt.ylim([0.0, 1.05]) - plt.xlabel('False Positive Rate (1 - Specificity)') - plt.ylabel('True Positive Rate (Sensitivity)') - plt.title('Receiver operating characteristic') - plt.legend(loc="lower right") - - return f, CIs_fpr, CIs_tpr - - -def main(): - parser = argparse.ArgumentParser(description='Plot the ROC Curve of an estimator') - parser.add_argument('-prediction', '--prediction', metavar='prediction', - nargs='+', dest='prediction', type=str, required=True, - help='Prediction file (HDF)') - parser.add_argument('-pinfo', '--pinfo', metavar='pinfo', - nargs='+', dest='pinfo', type=str, required=True, - help='Patient Info File (txt)') - parser.add_argument('-ensemble', '--ensemble', metavar='ensemble', - nargs='+', dest='ensemble', type=str, required=True, - help='Length of ensemble (int)') - parser.add_argument('-label_type', '--label_type', metavar='label_type', - nargs='+', dest='label_type', type=str, required=True, - help='Label name that is predicted (string)') - parser.add_argument('-output_png', '--output_png', metavar='output_png', - nargs='+', dest='output_png', type=str, required=False, - help='File to write output to (PNG)') - parser.add_argument('-output_csv', '--output_csv', metavar='output_csv', - nargs='+', dest='output_csv', type=str, required=False, - help='File to write output to (csv)') - parser.add_argument('-output_tex', '--output_tex', metavar='output_tex', - nargs='+', dest='output_tex', type=str, required=False, - help='File to write output to (tex)') - args = parser.parse_args() - - plot_ROC(prediction=args.prediction, - pinfo=args.pinfo, - ensemble=args.ensemble, - label_type=args.label_type, - output_png=args.output_png, - output_tex=args.output_tex, - output_csv=args.output_csv) - - -def plot_ROC(prediction, pinfo, ensemble=1, label_type=None, - output_png=None, output_tex=None, output_csv=None): - # Convert the inputs to the correct format - if type(prediction) is list: - prediction = ''.join(prediction) - - if type(pinfo) is list: - pinfo = ''.join(pinfo) - - if type(ensemble) is list: - ensemble = int(ensemble[0]) - # ensemble = ''.join(ensemble) - - if type(output_png) is list: - output_png = ''.join(output_png) - - if type(output_csv) is list: - output_csv = ''.join(output_csv) - - if type(output_tex) is list: - output_tex = ''.join(output_tex) - - if type(label_type) is list: - label_type = ''.join(label_type) - - # Read the inputs - prediction = pd.read_hdf(prediction) - if label_type is None: - # Assume we want to have the first key - label_type = prediction.keys()[0] - N_1 = len(prediction[label_type].Y_train[0]) - N_2 = len(prediction[label_type].Y_test[0]) - - # Determine the predicted score per patient - print('Determining score per patient.') - y_truths, y_scores, _, _ = plot_SVM(prediction, pinfo, label_type, - show_plots=False, - alpha=0.95, ensemble=ensemble, - output='decision') - - # Plot the ROC with confidence intervals - print("Plotting the ROC with confidence intervals.") - plot = 'default' - f, fpr, tpr = plot_ROC_CIc(y_truths, y_scores, N_1, N_2) - - if plot == 'default': - plot = '' - - # Save the outputs - if output_png is not None: - f.savefig(output_png) - print(("ROC saved as {} !").format(output_png)) - - if output_tex is not None: - tikz_save(output_tex) - print(("ROC saved as {} !").format(output_tex)) - - # Save ROC values as JSON - if output_csv is not None: - with open(output_csv, 'wb') as csv_file: - writer = csv.writer(csv_file) - writer.writerow(['FPR', 'TPR']) - for i in range(0, len(fpr)): - data = [str(fpr[i]), str(tpr[i])] - writer.writerow(data) - - print(("ROC saved as {} !").format(output_csv)) - - return f, fpr, tpr - - -if __name__ == '__main__': - main() diff --git a/build/lib/WORC/plotting/plot_SVM.py b/build/lib/WORC/plotting/plot_SVM.py deleted file mode 100644 index 32c6593b..00000000 --- a/build/lib/WORC/plotting/plot_SVM.py +++ /dev/null @@ -1,438 +0,0 @@ -#!/usr/bin/env python - -# Copyright 2016-2019 Biomedical Imaging Group Rotterdam, Departments of -# Medical Informatics and Radiology, Erasmus MC, Rotterdam, The Netherlands -# -# 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 numpy as np -import sys -import WORC.plotting.compute_CI as compute_CI -import pandas as pd -import os -import WORC.processing.label_processing as lp -from WORC.classification import metrics -import WORC.addexceptions as ae -from sklearn.base import is_regressor - - -def plot_SVM(prediction, label_data, label_type, show_plots=False, - alpha=0.95, ensemble=False, verbose=True, - ensemble_scoring=None, output='stats', - modus='singlelabel'): - ''' - Plot the output of a single binary estimator, e.g. a SVM. - - Parameters - ---------- - prediction: pandas dataframe or string, mandatory - output of trainclassifier function, either a pandas dataframe - or a HDF5 file - - label_data: string, mandatory - Contains the path referring to a .txt file containing the - patient label(s) and value(s) to be used for learning. See - the Github Wiki for the format. - - label_type: string, mandatory - Name of the label to extract from the label data to test the - estimator on. - - show_plots: Boolean, default False - Determine whether matplotlib performance plots are made. - - alpha: float, default 0.95 - Significance of confidence intervals. - - ensemble: False, integer or 'Caruana' - Determine whether an ensemble will be created. If so, - either provide an integer to determine how many of the - top performing classifiers should be in the ensemble, or use - the string "Caruana" to use smart ensembling based on - Caruana et al. 2004. - - verbose: boolean, default True - Plot intermedate messages. - - ensemble_scoring: string, default None - Metric to be used for evaluating the ensemble. If None, - the option set in the prediction object will be used. - - output: string, default stats - Determine which results are put out. If stats, the statistics of the - estimator will be returned. If scores, the scores will be returned. - - Returns - ---------- - Depending on the output parameters, the following outputs are returned: - - If output == 'stats': - stats: dictionary - Contains the confidence intervals of the performance metrics - and the number of times each patient was classifier correctly - or incorrectly. - - If output == 'scores': - y_truths: list - Contains the true label for each object. - - y_scores: list - Contains the score (e.g. posterior) for each object. - - y_predictions: list - Contains the predicted label for each object. - - PIDs: list - Contains the patient ID/name for each object. - ''' - - # Load the prediction object if it's a hdf5 file - if type(prediction) is not pd.core.frame.DataFrame: - if os.path.isfile(prediction): - prediction = pd.read_hdf(prediction) - else: - raise ae.WORCIOError(('{} is not an existing file!').format(str(prediction))) - - # Select the estimator from the pandas dataframe to use - keys = prediction.keys() - SVMs = list() - if label_type is None: - label_type = keys[0] - - # Load the label data - if type(label_data) is not dict: - if os.path.isfile(label_data): - if type(label_type) is not list: - # Singlelabel: convert to list - label_type = [[label_type]] - label_data = lp.load_labels(label_data, label_type) - - patient_IDs = label_data['patient_IDs'] - labels = label_data['label'] - - if type(label_type) is list: - # FIXME: Support for multiple label types not supported yet. - print('[WORC Warning] Support for multiple label types not supported yet. Taking first label for plot_SVM.') - label_type = keys[0] - - # Extract the estimators, features and labels - SVMs = prediction[label_type]['classifiers'] - regression = is_regressor(SVMs[0].best_estimator_) - Y_test = prediction[label_type]['Y_test'] - X_test = prediction[label_type]['X_test'] - X_train = prediction[label_type]['X_train'] - Y_train = prediction[label_type]['Y_train'] - feature_labels = prediction[label_type]['feature_labels'] - - # Create lists for performance measures - sensitivity = list() - specificity = list() - precision = list() - accuracy = list() - auc = list() - f1_score_list = list() - patient_classification_list = dict() - if output in ['scores', 'decision']: - # Keep track of all groundth truths and scores - y_truths = list() - y_scores = list() - y_predictions = list() - PIDs = list() - - # Loop over the test sets, which probably correspond with cross validation - # iterations - for i in range(0, len(Y_test)): - print("\n") - print(("Cross validation {} / {}.").format(str(i + 1), str(len(Y_test)))) - test_patient_IDs = prediction[label_type]['patient_ID_test'][i] - train_patient_IDs = prediction[label_type]['patient_ID_train'][i] - X_test_temp = X_test[i] - X_train_temp = X_train[i] - Y_train_temp = Y_train[i] - Y_test_temp = Y_test[i] - test_indices = list() - - # Check which patients are in the test set. - for i_ID in test_patient_IDs: - test_indices.append(np.where(patient_IDs == i_ID)[0][0]) - - # Initiate counting how many times a patient is classified correctly - if i_ID not in patient_classification_list: - patient_classification_list[i_ID] = dict() - patient_classification_list[i_ID]['N_test'] = 0 - patient_classification_list[i_ID]['N_correct'] = 0 - patient_classification_list[i_ID]['N_wrong'] = 0 - - patient_classification_list[i_ID]['N_test'] += 1 - - # Extract ground truth - y_truth = Y_test_temp - - # If requested, first let the SearchCV object create an ensemble - if ensemble: - # NOTE: Added for backwards compatability - if not hasattr(SVMs[i], 'cv_iter'): - cv_iter = list(SVMs[i].cv.split(X_train_temp, Y_train_temp)) - SVMs[i].cv_iter = cv_iter - - # Create the ensemble - X_train_temp = [(x, feature_labels) for x in X_train_temp] - SVMs[i].create_ensemble(X_train_temp, Y_train_temp, - method=ensemble, verbose=verbose, - scoring=ensemble_scoring) - - # Create prediction - y_prediction = SVMs[i].predict(X_test_temp) - - if regression: - y_score = y_prediction - else: - y_score = SVMs[i].predict_proba(X_test_temp)[:, 1] - - print("Truth: " + str(y_truth)) - print("Prediction: " + str(y_prediction)) - - # Add if patient was classified correctly or not to counting - for i_truth, i_predict, i_test_ID in zip(y_truth, y_prediction, test_patient_IDs): - if modus == 'multilabel': - success = (i_truth == i_predict).all() - else: - success = i_truth == i_predict - - if success: - patient_classification_list[i_test_ID]['N_correct'] += 1 - else: - patient_classification_list[i_test_ID]['N_wrong'] += 1 - - y_score = SVMs[i].predict_proba(X_test_temp)[:, 1] - - if output == 'decision': - # Output the posteriors - y_scores.append(y_score) - y_truths.append(y_truth) - y_predictions.append(y_prediction) - PIDs.append(test_patient_IDs) - - elif output == 'scores': - # Output the posteriors - y_scores.append(y_score) - y_truths.append(y_truth) - y_predictions.append(y_prediction) - PIDs.append(test_patient_IDs) - - elif output == 'stats': - # Compute statistics - # Compute confusion matrix and use for sensitivity/specificity - if modus == 'singlelabel': - # Compute singlelabel performance metrics - if not regression: - accuracy_temp, sensitivity_temp, specificity_temp,\ - precision_temp, f1_score_temp, auc_temp =\ - metrics.performance_singlelabel(y_truth, - y_prediction, - y_score, - regression) - else: - r2score, MSE, coefICC, PearsonC, PearsonP, SpearmanC,\ - SpearmanP =\ - metrics.performance_singlelabel(y_truth, - y_prediction, - y_score, - regression) - - elif modus == 'multilabel': - # Convert class objects to single label per patient - y_truth_temp = list() - y_prediction_temp = list() - for yt, yp in zip(y_truth, y_prediction): - label = np.where(yt == 1) - if len(label) > 1: - raise ae.WORCNotImplementedError('Multiclass classification evaluation is not supported in WORC.') - - y_truth_temp.append(label[0][0]) - label = np.where(yp == 1) - y_prediction_temp.append(label[0][0]) - - y_truth = y_truth_temp - y_prediction = y_prediction_temp - - # Compute multilabel performance metrics - accuracy_temp, sensitivity_temp, specificity_temp,\ - precision_temp, f1_score_temp, auc_temp =\ - metrics.performance_multilabel(y_truth, - y_prediction, - y_score) - - else: - raise ae.WORCKeyError('{} is not a valid modus!').format(modus) - - # Print AUC to keep you up to date - print('AUC: ' + str(auc_temp)) - - # Append performance to lists for all cross validations - accuracy.append(accuracy_temp) - sensitivity.append(sensitivity_temp) - specificity.append(specificity_temp) - auc.append(auc_temp) - f1_score_list.append(f1_score_temp) - precision.append(precision_temp) - - if output in ['scores', 'decision']: - # Return the scores and true values of all patients - return y_truths, y_scores, y_predictions, PIDs - elif output == 'stats': - # Compute statistics - # Extract sample size - N_1 = float(len(train_patient_IDs)) - N_2 = float(len(test_patient_IDs)) - - # Compute alpha confidence intervallen - stats = dict() - stats["Accuracy 95%:"] = str(compute_CI.compute_confidence(accuracy, N_1, N_2, alpha)) - - stats["AUC 95%:"] = str(compute_CI.compute_confidence(auc, N_1, N_2, alpha)) - - stats["F1-score 95%:"] = str(compute_CI.compute_confidence(f1_score_list, N_1, N_2, alpha)) - - stats["Precision 95%:"] = str(compute_CI.compute_confidence(precision, N_1, N_2, alpha)) - - stats["Sensitivity 95%: "] = str(compute_CI.compute_confidence(sensitivity, N_1, N_2, alpha)) - - stats["Specificity 95%:"] = str(compute_CI.compute_confidence(specificity, N_1, N_2, alpha)) - - print("Accuracy 95%:" + str(compute_CI.compute_confidence(accuracy, N_1, N_2, alpha))) - - print("AUC 95%:" + str(compute_CI.compute_confidence(auc, N_1, N_2, alpha))) - - print("F1-score 95%:" + str(compute_CI.compute_confidence(f1_score_list, N_1, N_2, alpha))) - - print("Precision 95%:" + str(compute_CI.compute_confidence(precision, N_1, N_2, alpha))) - - print("Sensitivity 95%: " + str(compute_CI.compute_confidence(sensitivity, N_1, N_2, alpha))) - - print("Specificity 95%:" + str(compute_CI.compute_confidence(specificity, N_1, N_2, alpha))) - - # Extract statistics on how often patients got classified correctly - alwaysright = dict() - alwayswrong = dict() - percentages = dict() - for i_ID in patient_classification_list: - percentage_right = patient_classification_list[i_ID]['N_correct'] / float(patient_classification_list[i_ID]['N_test']) - - if i_ID in patient_IDs: - label = labels[0][np.where(i_ID == patient_IDs)] - else: - # Multiple instance of one patient - label = labels[0][np.where(i_ID.split('_')[0] == patient_IDs)] - - label = label[0][0] - percentages[i_ID] = str(label) + ': ' + str(round(percentage_right, 2) * 100) + '%' - if percentage_right == 1.0: - alwaysright[i_ID] = label - print(("Always Right: {}, label {}").format(i_ID, label)) - - elif percentage_right == 0: - alwayswrong[i_ID] = label - print(("Always Wrong: {}, label {}").format(i_ID, label)) - - stats["Always right"] = alwaysright - stats["Always wrong"] = alwayswrong - stats['Percentages'] = percentages - - if show_plots: - # Plot some characteristics in boxplots - import matplotlib.pyplot as plt - - plt.figure() - plt.boxplot(accuracy) - plt.ylim([-0.05, 1.05]) - plt.ylabel('Accuracy') - plt.tick_params( - axis='x', # changes apply to the x-axis - which='both', # both major and minor ticks are affected - bottom='off', # ticks along the bottom edge are off - top='off', # ticks along the top edge are off - labelbottom='off') # labels along the bottom edge are off - plt.tight_layout() - plt.show() - - plt.figure() - plt.boxplot(auc) - plt.ylim([-0.05, 1.05]) - plt.ylabel('AUC') - plt.tick_params( - axis='x', # changes apply to the x-axis - which='both', # both major and minor ticks are affected - bottom='off', # ticks along the bottom edge are off - top='off', # ticks along the top edge are off - labelbottom='off') # labels along the bottom edge are off - plt.tight_layout() - plt.show() - - plt.figure() - plt.boxplot(precision) - plt.ylim([-0.05, 1.05]) - plt.ylabel('Precision') - plt.tick_params( - axis='x', # changes apply to the x-axis - which='both', # both major and minor ticks are affected - bottom='off', # ticks along the bottom edge are off - top='off', # ticks along the top edge are off - labelbottom='off') # labels along the bottom edge are off - plt.tight_layout() - plt.show() - - plt.figure() - plt.boxplot(sensitivity) - plt.ylim([-0.05, 1.05]) - plt.ylabel('Sensitivity') - plt.tick_params( - axis='x', # changes apply to the x-axis - which='both', # both major and minor ticks are affected - bottom='off', # ticks along the bottom edge are off - top='off', # ticks along the top edge are off - labelbottom='off') # labels along the bottom edge are off - plt.tight_layout() - plt.show() - - plt.figure() - plt.boxplot(specificity) - plt.ylim([-0.05, 1.05]) - plt.ylabel('Specificity') - plt.tick_params( - axis='x', # changes apply to the x-axis - which='both', # both major and minor ticks are affected - bottom='off', # ticks along the bottom edge are off - top='off', # ticks along the top edge are off - labelbottom='off') # labels along the bottom edge are off - plt.tight_layout() - plt.show() - - return stats - - -def main(): - if len(sys.argv) == 1: - print("TODO: Put in an example") - elif len(sys.argv) != 4: - raise IOError("This function accepts three arguments!") - else: - prediction = sys.argv[1] - patientinfo = sys.argv[2] - label_type = sys.argv[3] - plot_SVM(prediction, patientinfo, label_type) - - -if __name__ == '__main__': - main() diff --git a/build/lib/WORC/plotting/plot_SVR.py b/build/lib/WORC/plotting/plot_SVR.py deleted file mode 100644 index 69ee4500..00000000 --- a/build/lib/WORC/plotting/plot_SVR.py +++ /dev/null @@ -1,226 +0,0 @@ -#!/usr/bin/env python - -# Copyright 2016-2019 Biomedical Imaging Group Rotterdam, Departments of -# Medical Informatics and Radiology, Erasmus MC, Rotterdam, The Netherlands -# -# 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 numpy as np -from sklearn.metrics import r2_score, mean_squared_error -import sys -import WORC.plotting.compute_CI -import pandas as pd -import os -import lifelines as ll -import WORC.processing.label_processing as lp -from scipy.stats import pearsonr, spearmanr -from WORC.classification.metrics import ICC - - -def plot_single_SVR(prediction, label_data, label_type, survival=False, - show_plots=False, alpha=0.95): - if type(prediction) is not pd.core.frame.DataFrame: - if os.path.isfile(prediction): - prediction = pd.read_hdf(prediction) - - keys = prediction.keys() - SVRs = list() - label = keys[0] - SVRs = prediction[label]['classifiers'] - - Y_test = prediction[label]['Y_test'] - X_test = prediction[label]['X_test'] - Y_train = prediction[label]['X_train'] - - if survival: - # Also extract time to event and if event occurs from label data - labels = [[label_type], ['E'], ['T']] - else: - labels = [[label_type]] - - if type(label_data) is not dict: - if os.path.isfile(label_data): - label_data = lp.load_labels(label_data, labels) - - patient_IDs = label_data['patient_IDs'] - labels = label_data['label'] - - # Initialize scoring metrics - r2score = list() - MSE = list() - coefICC = list() - PearsonC = list() - PearsonP = list() - SpearmanC = list() - SpearmanP = list() - - if survival: - cindex = list() - coxp = list() - coxcoef = list() - - patient_MSE = dict() - - for i in range(0, len(Y_test)): - test_patient_IDs = prediction[label]['patient_ID_test'][i] - - # FIXME: Put some wrong patient IDs in test files - for num in range(0, len(test_patient_IDs)): - if 'features_' in test_patient_IDs[num]: - test_patient_IDs[num] = test_patient_IDs[num][9::] - - if '__tpl.hdf5' in test_patient_IDs[num]: - test_patient_IDs[num] = test_patient_IDs[num][0:-10] - - test_patient_IDs = np.asarray(test_patient_IDs) - - X_temp = X_test[i] - - test_indices = list() - for i_ID in test_patient_IDs: - # FIXME: Error in specific study - if i_ID == '112_recurrence-preop': - i_ID = '112_recurrence_preop' - test_indices.append(np.where(patient_IDs == i_ID)[0][0]) - - y_truth = [labels[0][k][0] for k in test_indices] - - if type(SVRs) == list or type(SVRs) == tuple: - estimator = SVRs[i] - else: - estimator = SVRs - - scaler = estimator.best_scaler - try: - y_prediction = estimator.predict(scaler.transform(X_temp)) - except ValueError: - y_prediction = estimator.predict(X_temp) - - y_truth = np.asarray(y_truth) - - # if survival: - # # Normalize the scores - # y_prediction = np.subtract(1.01, np.divide(y_prediction, np.max(y_prediction))) - - print("Truth: " + y_truth) - print("Prediction: " + y_prediction) - - # Compute error per patient - for i_truth, i_predict, i_test_ID in zip(y_truth, y_prediction, test_patient_IDs): - if i_test_ID not in patient_MSE.keys(): - patient_MSE[i_test_ID] = list() - patient_MSE[i_test_ID].append((i_truth - i_predict)**2) - - # Compute evaluation metrics - r2score.append(r2_score(y_truth, y_prediction)) - MSE.append(mean_squared_error(y_truth, y_prediction)) - coefICC.append(ICC(np.column_stack((y_prediction, y_truth)))) - C = pearsonr(y_prediction, y_truth) - PearsonC.append(C[0]) - PearsonP.append(C[1]) - C = spearmanr(y_prediction, y_truth) - SpearmanC.append(C.correlation) - SpearmanP.append(C.pvalue) - - if survival: - # Extract time to event and event from label data - E_truth = np.asarray([labels[1][k][0] for k in test_indices]) - T_truth = np.asarray([labels[2][k][0] for k in test_indices]) - - # Concordance index - cindex.append(1 - ll.utils.concordance_index(T_truth, y_prediction, E_truth)) - - # Fit Cox model using SVR output, time to event and event - data = {'predict': y_prediction, 'E': E_truth, 'T': T_truth} - data = pd.DataFrame(data=data, index=test_patient_IDs) - - cph = ll.CoxPHFitter() - cph.fit(data, duration_col='T', event_col='E') - - coxcoef.append(cph.summary['coef']['predict']) - coxp.append(cph.summary['p']['predict']) - - # Compute confidence intervals for given metrics - N_1 = float(len(Y_train[0])) - N_2 = float(len(Y_test[0])) - - if len(r2score) == 1: - # No confidence intevals, just take the scores - stats = dict() - stats["r2_score:"] = str(r2score[0]) - stats["MSE:"] = str(MSE[0]) - stats["ICC:"] = str(coefICC[0]) - stats["PearsonC:"] = str(PearsonC[0]) - stats["SpearmanC: "] = str(SpearmanC[0]) - stats["PearsonP:"] = str(PearsonP[0]) - stats["SpearmanP: "] = str(SpearmanP[0]) - - if survival: - stats["Concordance:"] = str(cindex[0]) - stats["Cox coef.:"] = str(coxcoef[0]) - stats["Cox p:"] = str(coxp[0]) - else: - # Compute confidence intervals from cross validations - stats = dict() - stats["r2_score 95%:"] = str(compute_CI.compute_confidence(r2score, N_1, N_2, alpha)) - stats["MSE 95%:"] = str(compute_CI.compute_confidence(MSE, N_1, N_2, alpha)) - stats["ICC 95%:"] = str(compute_CI.compute_confidence(coefICC, N_1, N_2, alpha)) - stats["PearsonC 95%:"] = str(compute_CI.compute_confidence(PearsonC, N_1, N_2, alpha)) - stats["SpearmanC 95%: "] = str(compute_CI.compute_confidence(SpearmanC, N_1, N_2, alpha)) - stats["PearsonP 95%:"] = str(compute_CI.compute_confidence(PearsonP, N_1, N_2, alpha)) - stats["SpearmanP 95%: "] = str(compute_CI.compute_confidence(SpearmanP, N_1, N_2, alpha)) - - if survival: - stats["Concordance 95%:"] = str(compute_CI.compute_confidence(cindex, N_1, N_2, alpha)) - stats["Cox coef. 95%:"] = str(compute_CI.compute_confidence(coxcoef, N_1, N_2, alpha)) - stats["Cox p 95%:"] = str(compute_CI.compute_confidence(coxp, N_1, N_2, alpha)) - - for k, v in stats.iteritems(): - print(k, v) - - # Calculate and sort individual patient MSE - patient_MSE = {k: np.mean(v) for k, v in patient_MSE.iteritems()} - order = np.argsort(patient_MSE.values()) - sortedkeys = np.asarray(patient_MSE.keys())[order].tolist() - sortedvalues = np.asarray(patient_MSE.values())[order].tolist() - patient_MSE = [(k, v) for k, v in zip(sortedkeys, sortedvalues)] - - for p in patient_MSE: - print(p[0], p[1]) - - stats["Patient_MSE"] = patient_MSE - - if show_plots: - # TODO: Plot metrics, see also plot_SVM - pass - - return stats - - -def main(): - if len(sys.argv) == 1: - prediction = '/media/martijn/DATA/CLM_MICCAI/Results/classification_all_SVR.hdf5' - label_data = '/home/martijn/git/RadTools/CLM_MICCAI/pinfo_CLM_MICCAI_test_months.txt' - label_type = 'KM' - survival = True - elif len(sys.argv) != 3: - raise IOError("This function accepts two arguments") - else: - prediction = sys.argv[1] - label_data = sys.argv[2] - plot_single_SVR(prediction, label_data, label_type, survival) - - -if __name__ == '__main__': - main() diff --git a/build/lib/WORC/plotting/plot_barchart.py b/build/lib/WORC/plotting/plot_barchart.py deleted file mode 100644 index d277927f..00000000 --- a/build/lib/WORC/plotting/plot_barchart.py +++ /dev/null @@ -1,365 +0,0 @@ -#!/usr/bin/env python - -# Copyright 2016-2019 Biomedical Imaging Group Rotterdam, Departments of -# Medical Informatics and Radiology, Erasmus MC, Rotterdam, The Netherlands -# -# 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 matplotlib -matplotlib.use('agg') -import matplotlib.pyplot as plt - -from matplotlib2tikz import save as tikz_save -import numpy as np -import pandas as pd -from collections import Counter -import argparse - - -def plot_barchart(prediction, estimators=10, label_type=None, output_tex=None, - output_png=None): - ''' - Make a barchart of the top X hyperparameters settings of the ranked - estimators in all cross validation iterations. - - Parameters - ---------- - prediction: filepath, mandatory - Path pointing to the .hdf5 file which was is the output of the - trainclassifier function. - - estimators: integer, default 10 - Number of hyperparameter settings/estimators used in each cross - validation. The settings are ranked, so when supplying e.g. 10, - the best 10 settings in each cross validation setting will be used. - - label_type: string, default None - The name of the label predicted by the estimator. If None, - the first label from the prediction file will be used. - - output_tex: filepath, optional - If given, the barchart will be written to this tex file. - - output_png: filepath, optional - If given, the barchart will be written to this png file. - - Returns - ---------- - fig: matplotlib figure - The figure in which the barchart is plotted. - - ''' - # Load input prediction - prediction = pd.read_hdf(prediction) - - # Determine for which label we extract the estimator - keys = prediction.keys() - if label_type is None: - label_type = keys[0] - - prediction = prediction[label_type] - - # Extract the parameter settings: - parameters = dict() - for n_crossval, est in enumerate(prediction.classifiers): - for n_setting in range(0, estimators): - # Extract parameter settings of nth estimator - parameters_all = est.cv_results_['params_all'][n_setting] - - # Stack settings in parameters dictionary - for k in parameters_all.keys(): - if k not in parameters.keys(): - parameters[k] = list() - parameters[k].append(parameters_all[k]) - - # Count for every parameter how many times a setting occurs - counts = count_parameters(parameters) - - # Normalize the values - normalization_factor = len(prediction.classifiers) * estimators - - # Make the barplot - fig = plot_bars(counts, normalization_factor) - - # Save the output - if output_tex is not None: - print('Saving barchart to {}.').format(output_tex) - tikz_save(output_tex) - - if output_png is not None: - print('Saving barchart to {}.').format(output_png) - fig.savefig(output_png, bbox_inches='tight', pad_inches=0, dpi=50) - - -def plot_bars(params, normalization_factor=None, figwidth=20, fontsize=20): - - # Fixing random state for reproducibility - np.random.seed(19680801) - - # Count how often feature groups are used - if 'texture_features' in params.keys(): - # Old approach: one hyperparameter for all texture featues - groups_temp = ['histogram', 'shape', 'orientation', 'semantic', - 'patient', 'log', 'vessel', 'phase', 'coliage'] - else: - groups_temp = ['histogram', 'shape', 'orientation', 'semantic', - 'patient', 'log', 'vessel', 'phase', 'coliage', - "texture_gabor", "texture_glcm", - "texture_glcmms", "texture_glrlm", - "texture_glszm", "texture_ngtdm", - "texture_lbp"] - ntimes_groups = list() - groups = list() - for key in groups_temp: - key += '_features' - if key in params.keys(): - # only append if the parameter is actually used - if 'True' in params[key].keys(): - ntimes_groups.append(params[key]['True']) - groups.append(key) - - # Count how often feature variance tresholding was used - if 'texture_features' in params.keys(): - # Old approach: one hyperparameter for all texture featues - # For the texture features, we have more options than simply True and False - texture_temp = ['True', 'LBP', 'GLCM', 'GLRLM', 'GLSZM', 'Gabor', 'NGTDM'] - texture = list() - ntimes_texture = list() - for key in texture_temp: - if key in params['texture_features'].keys(): - texture.append(key) - ntimes_texture.append(params['texture_features'][key]) - - # BUG: We did not put a all in the keys but a True, so replace - texture[texture.index('True')] = 'All' - - # # Normalize the values in order to not make figure to large - if normalization_factor is None: - normalization_factor = max(ntimes_groups + ntimes_texture) - normalization_factor = float(normalization_factor) # Needed for percentages - ntimes_groups = [x / normalization_factor for x in ntimes_groups] - if 'texture_features' in params.keys(): - ntimes_texture = [x / normalization_factor for x in ntimes_texture] - - # Create the figure for the barchart - plt.rcdefaults() - fig, ax = plt.subplots() - fig.set_figwidth(figwidth) - fig.set_figheight(figwidth/2) - ax.set_xlim(0, 1) - - # Determine positions of all the labels - y_pos = np.arange(len(groups)) - y_postick = np.arange(len(groups) + 1) - - # Normal features - colors = ['steelblue', 'lightskyblue'] - ax.barh(y_pos, ntimes_groups, align='center', - color=colors[0], ecolor='black') - ax.set_yticks(y_postick) - if 'texture_features' in params.keys(): - ax.set_yticklabels(groups + ['Texture']) - else: - ax.set_yticklabels(groups) - - ax.tick_params(axis='both', labelsize=fontsize) - ax.invert_yaxis() # labels read top-to-bottom - ax.set_xlabel('Percentage', fontsize=fontsize) - - if 'texture_features' in params.keys(): - # Texture features - left = 0 - y_pos = np.max(y_pos) + 1 - - j = 0 - for i in np.arange(len(texture)): - color = colors[j] - if j == 0: - j = 1 - else: - j = 0 - ax.barh(y_pos, ntimes_texture[i], align='center', - color=color, ecolor='black', left=left) - ax.text(left + ntimes_texture[i]/2, y_pos, - texture[i], ha='center', va='center', fontsize=fontsize - 2) - left += ntimes_texture[i] - - return fig - - -def count_parameters(parameters): - # Count for every parameter how many times a setting occurs - output = dict() - for setting, values in parameters.iteritems(): - output[setting] = dict() - c = Counter(values) - for k, v in zip(c.keys(), c.values()): - output[setting][k] = v - - return output - - -def paracheck(parameters): - # NOTE: Deprecated - output = dict() - # print parameters - - f = parameters['semantic_features'] - total = float(len(f)) - count_semantic = sum([i == 'True' for i in f]) - ratio_semantic = count_semantic/total - print("Semantic: " + str(ratio_semantic)) - output['semantic_features'] = ratio_semantic - - f = parameters['patient_features'] - count_patient = sum([i == 'True' for i in f]) - ratio_patient = count_patient/total - print("patient: " + str(ratio_patient)) - output['patient_features'] = ratio_patient - - f = parameters['orientation_features'] - count_orientation = sum([i == 'True' for i in f]) - ratio_orientation = count_orientation/total - print("orientation: " + str(ratio_orientation)) - output['orientation_features'] = ratio_orientation - - f = parameters['histogram_features'] - count_histogram = sum([i == 'True' for i in f]) - ratio_histogram = count_histogram/total - print("histogram: " + str(ratio_histogram)) - output['histogram_features'] = ratio_histogram - - f = parameters['shape_features'] - count_shape = sum([i == 'True' for i in f]) - ratio_shape = count_shape/total - print("shape: " + str(ratio_shape)) - output['shape_features'] = ratio_shape - - if 'coliage_features' in parameters.keys(): - f = parameters['coliage_features'] - count_coliage = sum([i == 'True' for i in f]) - ratio_coliage = count_coliage/total - print("coliage: " + str(ratio_coliage)) - output['coliage_features'] = ratio_coliage - - if 'phase_features' in parameters.keys(): - f = parameters['phase_features'] - count_phase = sum([i == 'True' for i in f]) - ratio_phase = count_phase/total - print("phase: " + str(ratio_phase)) - output['phase_features'] = ratio_phase - - if 'vessel_features' in parameters.keys(): - f = parameters['vessel_features'] - count_vessel = sum([i == 'True' for i in f]) - ratio_vessel = count_vessel/total - print("vessel: " + str(ratio_vessel)) - output['vessel_features'] = ratio_vessel - - if 'log_features' in parameters.keys(): - f = parameters['log_features'] - count_log = sum([i == 'True' for i in f]) - ratio_log = count_log/total - print("log: " + str(ratio_log)) - output['log_features'] = ratio_log - - f = parameters['texture_features'] - count_texture_all = sum([i == 'True' for i in f]) - ratio_texture_all = count_texture_all/total - print("texture_all: " + str(ratio_texture_all)) - output['texture_all_features'] = ratio_texture_all - - count_texture_no = sum([i == 'False' for i in f]) - ratio_texture_no = count_texture_no/total - print("texture_no: " + str(ratio_texture_no)) - output['texture_no_features'] = ratio_texture_no - - count_texture_Gabor = sum([i == 'Gabor' for i in f]) - ratio_texture_Gabor = count_texture_Gabor/total - print("texture_Gabor: " + str(ratio_texture_Gabor)) - output['texture_Gabor_features'] = ratio_texture_Gabor - - count_texture_LBP = sum([i == 'LBP' for i in f]) - ratio_texture_LBP = count_texture_LBP/total - print("texture_LBP: " + str(ratio_texture_LBP)) - output['texture_LBP_features'] = ratio_texture_LBP - - count_texture_GLCM = sum([i == 'GLCM' for i in f]) - ratio_texture_GLCM = count_texture_GLCM/total - print("texture_GLCM: " + str(ratio_texture_GLCM)) - output['texture_GLCM_features'] = ratio_texture_GLCM - - count_texture_GLRLM = sum([i == 'GLRLM' for i in f]) - ratio_texture_GLRLM = count_texture_GLRLM/total - print("texture_GLRLM: " + str(ratio_texture_GLRLM)) - output['texture_GLRLM_features'] = ratio_texture_GLRLM - - count_texture_GLSZM = sum([i == 'GLSZM' for i in f]) - ratio_texture_GLSZM = count_texture_GLSZM/total - print("texture_GLSZM: " + str(ratio_texture_GLSZM)) - output['texture_GLSZM_features'] = ratio_texture_GLSZM - - count_texture_NGTDM = sum([i == 'NGTDM' for i in f]) - ratio_texture_NGTDM = count_texture_NGTDM/total - print("texture_NGTDM: " + str(ratio_texture_NGTDM)) - output['texture_NGTDM_features'] = ratio_texture_NGTDM - - if 'degree' in parameters.keys(): - f = parameters['degree'] - print("Polynomial Degree: " + str(np.mean(f))) - output['polynomial_degree'] = np.mean(f) - - return output - - -def main(): - parser = argparse.ArgumentParser(description='Plot a Barchart.') - parser.add_argument('-prediction', '--prediction', metavar='prediction', - nargs='+', dest='prediction', type=str, required=True, - help='Prediction file (HDF)') - parser.add_argument('-estimators', '--estimators', metavar='estimator', - nargs='+', dest='estimators', type=str, required=False, - help='Number of estimators to evaluate in each cross validation.') - parser.add_argument('-label_type', '--label_type', metavar='label_type', - nargs='+', dest='label_type', type=str, required=False, - help='Key of the label which was predicted.') - parser.add_argument('-output_tex', '--output_tex', metavar='output_tex', - nargs='+', dest='output_tex', type=str, required=True, - help='Output file path (.tex)') - parser.add_argument('-output_png', '--output_png', metavar='output_png', - nargs='+', dest='output_png', type=str, required=True, - help='Output file path (.png)') - args = parser.parse_args() - - # Convert the inputs to the correct format - if type(args.prediction) is list: - args.prediction = ''.join(args.prediction) - - if type(args.output) is list: - args.output = ''.join(args.output) - - if type(args.estimators) is list: - args.estimators = int(args.estimators[0]) - - if type(args.label_type) is list: - args.label_type = ''.join(args.label_type) - - plot_barchart(prediction=args.prediction, - estimators=args.estimators, - label_type=args.label_type, - output_tex=args.output_tex, - output_png=args.output_png) - - -if __name__ == '__main__': - main() diff --git a/build/lib/WORC/plotting/plot_boxplot.py b/build/lib/WORC/plotting/plot_boxplot.py deleted file mode 100644 index a320f447..00000000 --- a/build/lib/WORC/plotting/plot_boxplot.py +++ /dev/null @@ -1,174 +0,0 @@ -#!/usr/bin/env python - -# Copyright 2016-2019 Biomedical Imaging Group Rotterdam, Departments of -# Medical Informatics and Radiology, Erasmus MC, Rotterdam, The Netherlands -# -# 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 matplotlib -matplotlib.use('agg') -import matplotlib.pyplot as plt - -import pandas as pd -import argparse -import WORC.processing.label_processing as lp -import os -import glob -from natsort import natsorted -import numpy as np - - -def main(): - parser = argparse.ArgumentParser(description='Radiomics results') - parser.add_argument('-feat', '--feat', metavar='feat', - nargs='+', dest='feat', type=str, required=True, - help='List of patient feature files (HDF)') - parser.add_argument('-class', '--class', metavar='class', - nargs='+', dest='classs', type=str, required=True, - help='Classification of patients (text)') - parser.add_argument('-label_type', '--label_type', metavar='label_type', - nargs='+', dest='label_type', type=str, required=True, - help='Name of the label that was predicted') - parser.add_argument('-out', '--out', metavar='out', - nargs='+', dest='out', type=str, required=True, - help='Output png file') - args = parser.parse_args() - - if type(args.classs) is list: - args.classs = ''.join(args.classs) - - if type(args.label_type) is list: - args.label_type = ''.join(args.label_type) - - if type(args.out) is list: - args.out = ''.join(args.out) - - if type(args.feat) is list and len(args.feat) == 1: - args.feat = ''.join(args.feat) - - if os.path.isdir(args.feat): - args.feat = glob.glob(args.feat + '/features_*.hdf5') - args.feat = natsorted(args.feat) - - # Read and stack the features - print("Reading features.") - image_features_temp = list() - for i_feat in range(len(args.feat)): - feat_temp = pd.read_hdf(args.feat[i_feat]) - feat_values = feat_temp.feature_values - feat_labels = feat_temp.feature_labels - - feat = {k: v for k, v in zip(feat_labels, feat_values)} - - image_features_temp.append(feat) - - # Get the labels and patient IDs - print("Reading class labels.") - label_type = args.label_type - label_data, image_features = lp.findlabeldata(args.classs, - label_type, - args.feat, - image_features_temp) - - generate_boxplots(image_features, label_data, args.out) - - -def generate_boxplots(image_features, label_data, outputfolder): - ''' - Generate boxplots of the feature values among different objects. - - Parameters - ---------- - features: list, mandatory - List with a dictionary of the feature labels and values for each patient. - - label_data: pandas dataframe, mandatory - Dataframe containing the labels of the objects. - - outputfolder: path, mandatory - Folder to which the output boxplots should be written. - - - ''' - labels = image_features[0].keys() - featvect = dict() - flab = dict() - for l in labels: - featvect[l] = {"all": [], "1": [], "0": []} - flab[l] = {"all": [], "1": [], "0": []} - - # Stack per feature type and class - print("Stacking features.") - label = label_data['label'].tolist()[0] - patient_IDs = label_data['patient_IDs'].tolist() - for imfeat, label, pid in zip(image_features, label, patient_IDs): - for fl in labels: - featvect[fl]['all'].append(imfeat[fl]) - flab[fl]['all'].append(pid) - if label[0] == 0: - featvect[fl]['0'].append(imfeat[fl]) - flab[fl]['0'].append(pid) - else: - featvect[fl]['1'].append(imfeat[fl]) - flab[fl]['1'].append(pid) - - # Create the boxplots - print("Generating boxplots.") - - # Split in 5x5 figures. - nfig = np.ceil(len(labels) / 25.0) - - labels = sorted(labels) - for fi in range(0, int(nfig)): - f = plt.figure() - fignum = 1 - for i in range(fi*25, min((fi+1)*25, len(labels))): - ax = plt.subplot(5, 5, fignum) - lab = labels[i] - plt.subplots_adjust(hspace=0.3, wspace=0.2) - ax.scatter(np.ones(len(featvect[lab]['all'])), - featvect[lab]['all'], - color='blue') - ax.scatter(np.ones(len(featvect[lab]['1']))*2.0, - featvect[lab]['1'], - color='red') - ax.scatter(np.ones(len(featvect[lab]['0']))*3.0, - featvect[lab]['0'], - color='green') - - plt.boxplot([featvect[lab]['all'], featvect[lab]['1'], featvect[lab]['0']]) - - fz = 5 # Works best after saving - ax.set_title(lab, fontsize=fz) - for tick in ax.xaxis.get_major_ticks(): - tick.label.set_fontsize(fz) - - for tick in ax.yaxis.get_major_ticks(): - tick.label.set_fontsize(fz) - - fignum += 1 - - # Maximize figure to get correct spacings - mng = plt.get_current_fig_manager() - mng.resize(*mng.window.maxsize()) - # plt.show() - - # High DTI to make sure we save the maximized image - fname = ('boxplot_{}.png').format(str(fi)) - outputname = os.path.join(outputfolder, fname) - f.savefig(outputname, dpi=600) - print(("Boxplot saved as {} !").format(outputname)) - - -if __name__ == '__main__': - main() diff --git a/build/lib/WORC/plotting/plot_images.py b/build/lib/WORC/plotting/plot_images.py deleted file mode 100644 index 59bd42c6..00000000 --- a/build/lib/WORC/plotting/plot_images.py +++ /dev/null @@ -1,130 +0,0 @@ -#!/usr/bin/env python - -# Copyright 2016-2019 Biomedical Imaging Group Rotterdam, Departments of -# Medical Informatics and Radiology, Erasmus MC, Rotterdam, The Netherlands -# -# 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 matplotlib -matplotlib.use('agg') -import matplotlib.pyplot as plt - -import numpy as np -from matplotlib.ticker import NullLocator -import matplotlib.colors as colors -import SimpleITK as sitk - - -def slicer(image, mask, output_name, output_name_zoom, thresholds=[-240, 160], - zoomfactor=4): - ''' - image and mask should both be arrays - ''' - - # Determine figure size by spacing - spacing = float(image.GetSpacing()[0]) - imsize = [float(image.GetSize()[0]), float(image.GetSize()[1])] - figsize = (imsize[0]*spacing/100.0, imsize[1]*spacing/100.0) - # dpi = int(200/spacing) - dpi = 100.0 - - # Convert images to numpy arrays - image = sitk.GetArrayFromImage(image) - mask = sitk.GetArrayFromImage(mask) - - # Determine which axial slice has the largest area - areas = np.sum(mask, axis=1).tolist() - max_ind = areas.index(max(areas)) - imslice = image[max_ind, :, :] - maskslice = mask[max_ind, :, :] - - # Threshold the image if desired - if thresholds: - imslice[imslice < thresholds[0]] = thresholds[0] - imslice[imslice > thresholds[1]] = thresholds[1] - - # Plot the image and overlay the mask - fig = plot_im_and_overlay(imslice, maskslice, figsize=figsize) - - # Save Output - fig.savefig(output_name, bbox_inches='tight', pad_inches=0, dpi=dpi) - - # Save some memory - del fig - - # Create a bounding box and save zoomed image - imslice, maskslice = bbox_2D(imslice, maskslice, padding=[20, 20]) - imsize = [float(imslice.shape[0]), float(imslice.shape[1])] - - # NOTE: As these zoomed images get small, we double the spacing - spacing = spacing * zoomfactor - figsize = (imsize[0]*spacing/100.0, imsize[1]*spacing/100.0) - fig = plot_im_and_overlay(imslice, maskslice, figsize=figsize) - fig.savefig(output_name_zoom, bbox_inches='tight', pad_inches=0, dpi=dpi) - plt.close('all') - - # Save some memory - del fig, image, mask - return imslice, maskslice - - -def plot_im_and_overlay(image, mask, figsize=(3, 3), alpha=0.15): - ''' - Plot an image in a matplotlib figure and overlay with a mask. - ''' - # Create a normalized colormap for the image and mask - imin = np.min(image) - imax = np.max(image) - norm_im = colors.Normalize(vmin=imin, vmax=imax, clip=False) - - cmap = plt.get_cmap("Reds") - cmap.set_under(color="white", alpha=0) - cmap.set_over(color="r", alpha=1) - normO = colors.Normalize(vmin=0.5, vmax=0.75, clip=False) - - # Plot and save the full image - fig = plt.figure(figsize=figsize) - ax = fig.add_subplot(1, 1, 1) - ax.imshow(image, cmap=plt.cm.gray, norm=norm_im, interpolation="bilinear") - ax.imshow(mask, cmap=cmap, norm=normO, alpha=alpha, interpolation="bilinear") - - # Set locator to zero to make sure padding is removed upon saving - ax.xaxis.set_major_locator(NullLocator()) - ax.yaxis.set_major_locator(NullLocator()) - - # Turn axis grid of - ax.axis('off') - - return fig - - -def bbox_2D(img, mask, padding=[1, 1], img2=None): - rows = np.any(mask, axis=1) - cols = np.any(mask, axis=0) - - rmin, rmax = np.where(rows)[0][[0, -1]] - cmin, cmax = np.where(cols)[0][[0, -1]] - - # print rmin, rmax, cmin, cmax - rmin = max(0, rmin - padding[0]) - rmax = min(img.shape[0], rmax+padding[0]+1) - cmin = max(0, cmin - padding[1]) - cmax = min(img.shape[1], cmax+padding[1]+1) - - img = img[rmin:rmax, cmin:cmax] - mask = mask[rmin:rmax, cmin:cmax] - if img2 is None: - return img, mask - else: - img2 = img2[rmin:rmax, cmin:cmax] - return img, mask, img2 diff --git a/build/lib/WORC/plotting/plot_ranked_scores.py b/build/lib/WORC/plotting/plot_ranked_scores.py deleted file mode 100644 index f32be162..00000000 --- a/build/lib/WORC/plotting/plot_ranked_scores.py +++ /dev/null @@ -1,505 +0,0 @@ -#!/usr/bin/env python - -# Copyright 2016-2019 Biomedical Imaging Group Rotterdam, Departments of -# Medical Informatics and Radiology, Erasmus MC, Rotterdam, The Netherlands -# -# 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 argparse -import pandas as pd -from WORC.plotting.plot_SVM import plot_SVM -import WORC.processing.label_processing as lp -import glob -import numpy as np -import csv -import os -import WORC.plotting.plot_images as pi -import SimpleITK as sitk -from WORC.addexceptions import WORCKeyError -import zipfile - - -# NOTE: Need to add thresholds of plot_ranked_images to arguments - - -def main(): - parser = argparse.ArgumentParser(description='Plot distances to hyperplane') - parser.add_argument('-estimator', '--estimator', metavar='est', - nargs='+', dest='est', type=str, required=True, - help='Path to HDF5 file containing a fitted estimator.') - parser.add_argument('-pinfo', '--pinfo', metavar='pinfo', - nargs='+', dest='pinfo', type=str, required=True, - help='Patient Info File (txt)') - parser.add_argument('-images', '--images', metavar='images', - nargs='+', dest='ims', type=str, required=True, - help='Images of patients (ITK Image files)') - parser.add_argument('-segmentations', '--segmentations', metavar='segmentations', - nargs='+', dest='segs', type=str, required=True, - help='Segmentations of patients (ITK Image files)') - parser.add_argument('-ensemble', '--ensemble', metavar='ensemble', - nargs='+', dest='ens', type=str, required=True, - help='Either length of ensemble (int) or Caruana (string)') - parser.add_argument('-label_type', '--label_type', metavar='label_type', - nargs='+', dest='label_type', type=str, required=True, - help='Label name that is predicted by estimator (string)') - parser.add_argument('-scores', '--scores', metavar='scores', - nargs='+', dest='scores', type=str, required=True, - help='Type of scoring: percentages or posteriors (string)') - parser.add_argument('-output_csv', '--output_csv', metavar='output_csv', - nargs='+', dest='output_csv', type=str, required=True, - help='Output file for scores (CSV).') - parser.add_argument('-output_zip', '--output_zip', metavar='output_zip', - nargs='+', dest='output_zip', type=str, required=True, - help='Output file for images (zip).') - args = parser.parse_args() - - # convert inputs that should be single arguments to lists - pinfo = args.pinfo - if type(pinfo) is list: - pinfo = ''.join(pinfo) - - estimator = args.est - if type(estimator) is list: - estimator = ''.join(estimator) - - ensemble = args.ens - if type(ensemble) is list: - ensemble = ''.join(ensemble) - - label_type = args.label_type - if type(label_type) is list: - label_type = ''.join(label_type) - - scores = args.scores - if type(scores) is list: - scores = ''.join(scores) - - output_csv = args.output_csv - if type(output_csv) is list: - output_csv = ''.join(output_csv) - - output_zip = args.output_zip - if type(output_zip) is list: - output_zip = ''.join(output_zip) - - plot_ranked_scores(estimator=estimator, - pinfo=pinfo, - label_type=label_type, - scores=scores, - images=args.ims, - segmentations=args.segs, - ensemble=ensemble, - output_csv=output_csv, - output_zip=output_zip) - - -def plot_ranked_percentages(estimator, pinfo, label_type=None, - ensemble=50, output_csv=None): - - # Read the inputs - prediction = pd.read_hdf(estimator) - label_type = prediction.keys()[0] # NOTE: Assume we want to have the first key - - # Determine the predicted score per patient - print('Determining score per patient.') - stats = plot_SVM(prediction, - pinfo, - label_type, - show_plots=False, - alpha=0.95, - ensemble=ensemble, - output='stats') - - percentages = stats['Percentages'] - ranking = np.argsort(percentages.values()) - ranked_percentages_temp = [percentages.values()[r] for r in ranking] - ranked_PIDs = [percentages.keys()[r] for r in ranking] - - ranked_percentages = list() - ranked_truths = list() - for r in ranked_percentages_temp: - id = r.index(':') - ranked_truths.append(float(r[0:id])) - ranked_percentages.append(float(r[id+2:-1])) - - # Write output to csv - if output_csv is not None: - print("Writing output scores to CSV.") - header = ['PatientID', 'TrueLabel', 'Percentage'] - with open(output_csv, 'wb') as csv_file: - writer = csv.writer(csv_file) - writer.writerow(header) - - for pid, truth, perc in zip(ranked_PIDs, ranked_truths, ranked_percentages): - towrite = [str(pid), str(truth), str(perc)] - writer.writerow(towrite) - - return ranked_percentages, ranked_truths, ranked_PIDs - - -def plot_ranked_images(pinfo, label_type, images, segmentations, ranked_truths, - ranked_scores, ranked_PIDs, output_zip=None, - output_itk=None, zoomfactor=4): - # Match the images to the label data - print('Matching image and segmentation data to labels.') - print(images) - label_data, images =\ - lp.findlabeldata(pinfo, - [[label_type]], - images, - images) - _, segmentations =\ - lp.findlabeldata(pinfo, - [[label_type]], - segmentations, - segmentations) - - PIDs_images = label_data['patient_IDs'].tolist() - PIDs_images = [i.lower() for i in PIDs_images] - del label_data - - # Order the images and segmentations in the scores ordering - ordering = list() - for pid in ranked_PIDs: - if pid in PIDs_images: - ordering.append(PIDs_images.index(pid)) - else: - print('[WORC Warning] Patient {} not in images list!').format(str(pid)) - - PIDs_images = [PIDs_images[i] for i in ordering] - images = [images[i] for i in ordering] - segmentations = [segmentations[i] for i in ordering] - - # Print the middle segmented slice from each patient based on ranking - print('Print the middle segmented slice from each patient based on ranking.') - if output_zip is not None: - zipf = zipfile.ZipFile(output_zip, - 'w', zipfile.ZIP_DEFLATED, allowZip64=True) - - if output_itk is not None: - # Determine spacing factor - print("Determining spacings factor.") - spacings_x = list() - spacings_y = list() - for idx, im in enumerate(images): - print(('Processing patient {} / {}: {}.').format(str(idx + 1), str(len(images)), PIDs_images[idx])) - im = sitk.ReadImage(im) - spacings_x.append(im.GetSpacing()[0]) - spacings_y.append(im.GetSpacing()[1]) - # NOTE: Used in future feature - resample = [min(spacings_x), min(spacings_y)] - - for idx in range(0, len(images)): - print(('Processing patient {} / {}: {}.').format(str(idx + 1), str(len(images)), PIDs_images[idx])) - im = sitk.ReadImage(images[idx]) - seg = sitk.ReadImage(segmentations[idx]) - pid = PIDs_images[idx] - fname = str(int(ranked_scores[idx])) + '_' + pid + '_TrueLabel_' + str(ranked_truths[idx]) + '_slice.png' - - if output_zip is not None: - output_name = os.path.join(os.path.dirname(output_zip), fname) - output_name_zoom = os.path.join(os.path.dirname(output_zip), 'zoom' + str(zoomfactor) + '_' + fname) - else: - output_name = None - output_name_zoom = None - - imslice, maskslice = pi.slicer(im, seg, output_name, - output_name_zoom, output_itk) - - if output_zip is not None: - # Print PNGs and comine in ZIP - zipf.write(output_name, fname) - zipf.write(output_name_zoom, 'zoom_' + fname) - os.remove(output_name) - os.remove(output_name_zoom) - - if output_itk is not None: - # Combine slices in 3D image - print('WIP') - - del im, seg, imslice, maskslice - - -def plot_ranked_posteriors(estimator, pinfo, label_type=None, - ensemble=50, output_csv=None): - # Read the inputs - prediction = pd.read_hdf(estimator) - if label_type is None: - # Assume we want to have the first key - label_type = prediction.keys()[0] - - # Determine the predicted score per patient - print('Determining posterior per patient.') - y_truths, y_scores, y_predictions, PIDs_scores =\ - plot_SVM(prediction, - pinfo, - label_type, - show_plots=False, - alpha=0.95, - ensemble=ensemble, - output='scores') - - # Extract all scores for each patient - print('Aggregating scores per patient over all crossval iterations.') - scores = dict() - truths = dict() - y_truths_flat = [item for sublist in y_truths for item in sublist] - y_scores_flat = [item for sublist in y_scores for item in sublist] - PIDs_scores_flat = [item for sublist in PIDs_scores for item in sublist] - for yt, ys, pid in zip(y_truths_flat, y_scores_flat, PIDs_scores_flat): - if pid not in scores.keys(): - # No scores yet for patient, create list - scores[pid] = list() - truths[pid] = yt - scores[pid].append(ys) - - # Take the mean for each patient and rank them - scores_means = dict() - maxlen = 0 - for pid in scores.keys(): - scores_means[pid] = np.mean(scores[pid]) - if len(scores[pid]) > maxlen: - maxlen = len(scores[pid]) - - ranking = np.argsort(scores_means.values()) - ranked_PIDs = [scores_means.keys()[r] for r in ranking] - - ranked_mean_scores = [scores_means[r] for r in ranked_PIDs] - ranked_scores = [scores[r] for r in ranked_PIDs] - ranked_truths = [truths[r] for r in ranked_PIDs] - - # Write output to csv - if output_csv is not None: - print("Writing output scores to CSV.") - header = ['PatientID', 'TrueLabel', 'Probability'] - for i in range(0, maxlen): - header.append('Score' + str(i+1)) - - with open(output_csv, 'wb') as csv_file: - writer = csv.writer(csv_file) - writer.writerow(header) - - for pid, truth, smean, scores in zip(ranked_PIDs, ranked_truths, ranked_mean_scores, ranked_scores): - towrite = [str(pid), str(truth), str(smean)] - for s in scores: - towrite.append(str(s)) - - writer.writerow(towrite) - - return ranked_mean_scores, ranked_truths, ranked_PIDs - - -def plot_ranked_scores(estimator, pinfo, label_type, scores='percentages', - images=[], segmentations=[], ensemble=50, - output_csv=None, output_zip=None, output_itk=None): - ''' - Rank the patients according to their average score. The score can either - be the average posterior or the percentage of times the patient was - classified correctly in the cross validations. Additionally, - the middle slice of each patient is plot and saved according to the ranking. - - Parameters - ---------- - estimator: filepath, mandatory - Path pointing to the .hdf5 file which was is the output of the - trainclassifier function. - - pinfo: filepath, mandatory - Path pointint to the .txt file which contains the patient label - information. - - label_type: string, default None - The name of the label predicted by the estimator. If None, - the first label from the prediction file will be used. - - scores: string, default percentages - Type of scoring to be used. Either 'posteriors' or 'percentages'. - - images: list, optional - List containing the filepaths to the ITKImage image files of the - patients. - - segmentations: list, optional - List containing the filepaths to the ITKImage segmentation files of - the patients. - - ensemble: integer or string, optional - Method to be used for ensembling. Either an integer for a fixed size - or 'Caruana' for the Caruana method, see the SearchCV function for more - details. - - output_csv: filepath, optional - If given, the scores will be written to this csv file. - - output_zip: filepath, optional - If given, the images will be plotted and the pngs saved to this - zip file. - - output_itk: filepath, optional - WIP - - ''' - prediction = pd.read_hdf(estimator) - if label_type is None: - # Assume we want to have the first key - label_type = prediction.keys()[0] - - if scores == 'posteriors': - ranked_scores, ranked_truths, ranked_PIDs =\ - plot_ranked_posteriors(estimator=estimator, - pinfo=pinfo, - label_type=label_type, - ensemble=ensemble, - output_csv=output_csv) - elif scores == 'percentages': - ranked_scores, ranked_truths, ranked_PIDs =\ - plot_ranked_percentages(estimator=estimator, - pinfo=pinfo, - label_type=label_type, - ensemble=ensemble, - output_csv=output_csv) - else: - message = ('{} is not a valid scoring method!').format(str(scores)) - raise WORCKeyError(message) - - if output_zip is not None or output_itk is not None: - # Rerank the scores split per ground truth class: negative for 0, positive for 1 - ranked_scores_temp = list() - for l, p in zip(ranked_truths, ranked_scores): - if l == 0: - ranked_scores_temp.append(-p) - else: - ranked_scores_temp.append(p) - - ranked_scores = ranked_scores_temp - ranking = np.argsort(ranked_scores) - ranked_scores = [ranked_scores[r] for r in ranking] - ranked_truths = [ranked_truths[r] for r in ranking] - ranked_PIDs = [ranked_PIDs[r] for r in ranking] - - # Convert to lower to later on overcome matching errors - ranked_PIDs = [i.lower() for i in ranked_PIDs] - - plot_ranked_images(pinfo=pinfo, - label_type=label_type, - images=images, - segmentations=segmentations, - ranked_truths=ranked_truths, - ranked_scores=ranked_scores, - ranked_PIDs=ranked_PIDs, - output_zip=output_zip, - output_itk=output_itk) - - -def example(): - case = 'MESFIB' - if case == 'CLM': - label_type = None - estimator = '/media/martijn/DATA/tmp/classification_0_nonewfeat.hdf5' - ensemble = 50 - scores = 'percentages' - pinfo = '/home/martijn/git/RadTools/CLM/pinfo_CLM_KM.txt' - images_temp = glob.glob('/media/martijn/DATA/CLM/*/*/*/image.nii.gz') - segmentations = list() - images = list() - for i in images_temp: - segs = glob.glob(os.path.dirname(i) + '/seg_*session2*.nii.gz') - if len(segs) == 1: - segmentations.append(segs[0]) - images.append(i) - elif len(segs) > 1: - segmentations.append(segs[0]) - images.append(i) - else: - segs = glob.glob(os.path.dirname(i) + '/seg_*session1*.nii.gz') - if len(segs) == 1: - segmentations.append(segs[0]) - images.append(i) - elif len(segs) > 1: - segmentations.append(segs[0]) - images.append(i) - else: - print(i) - - output_csv = '/media/martijn/DATA/tmp/classification_0_nonewfeat_percentages.csv' - output_zip = '/media/martijn/DATA/tmp/classification_0_nonewfeat_percentages.zip' - elif case == 'MESFIB': - label_type = None - estimator = '/media/martijn/DATA/MESFIB/Results_0704/classification_100crossval_nonewfeat.hdf5' - ensemble = 50 - scores = 'percentages' - pinfo = '/home/martijn/git/RadTools/MESFIB/pinfo_MESFIB.txt' - images_temp = glob.glob('/media/martijn/DATA/MESFIB/*/*/*/image.nii.gz') - segmentations = list() - images = list() - for i in images_temp: - segs = glob.glob(os.path.dirname(i) + '/seg*Mass*.nii.gz') - if len(segs) == 1: - segmentations.append(segs[0]) - images.append(i) - elif len(segs) > 1: - segmentations.append(segs[0]) - images.append(i) - else: - segs = glob.glob(os.path.dirname(i) + '/seg_*mass*.nii.gz') - if len(segs) == 1: - segmentations.append(segs[0]) - images.append(i) - elif len(segs) > 1: - segmentations.append(segs[0]) - images.append(i) - else: - print(i) - - output_csv = '/media/martijn/DATA/MESFIB/Results_0704/classification_100crossval_nonewfeat_percentages.csv' - output_zip = '/media/martijn/DATA/MESFIB/Results_0704/classification_100crossval_nonewfeat_percentages.zip' - - prediction = pd.read_hdf(estimator) - if label_type is None: - # Assume we want to have the first key - label_type = prediction.keys()[0] - - if scores == 'posteriors': - ranked_scores, ranked_truths, ranked_PIDs =\ - plot_ranked_posteriors(estimator=estimator, - pinfo=pinfo, - label_type=label_type, - ensemble=ensemble, - output_csv=output_csv) - elif scores == 'percentages': - ranked_scores, ranked_truths, ranked_PIDs =\ - plot_ranked_percentages(estimator=estimator, - pinfo=pinfo, - label_type=label_type, - ensemble=ensemble, - output_csv=output_csv) - else: - message = ('{} is not a valid scoring method!').format(str(scores)) - raise WORCKeyError(message) - - if output_zip is not None: - # Convert to lower to later on overcome matching errors - ranked_PIDs = [i.lower() for i in ranked_PIDs] - - plot_ranked_images(pinfo=pinfo, - label_type=label_type, - images=images, - segmentations=segmentations, - ranked_truths=ranked_truths, - ranked_scores=ranked_scores, - ranked_PIDs=ranked_PIDs, - output_zip=output_zip) - - -if __name__ == '__main__': - main() diff --git a/build/lib/WORC/plotting/plotminmaxresponse.py b/build/lib/WORC/plotting/plotminmaxresponse.py deleted file mode 100644 index 3eef97f9..00000000 --- a/build/lib/WORC/plotting/plotminmaxresponse.py +++ /dev/null @@ -1,247 +0,0 @@ -#!/usr/bin/env python - -# Copyright 2016-2019 Biomedical Imaging Group Rotterdam, Departments of -# Medical Informatics and Radiology, Erasmus MC, Rotterdam, The Netherlands -# -# 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 pandas as pd -import argparse -import WORC.labels.label_processing as lp -import os -import glob -from natsort import natsorted -import numpy as np -from PREDICT.plotting.getfeatureimages import getfeatureimages -import scipy - - -def main(): - parser = argparse.ArgumentParser(description='Radiomics results') - parser.add_argument('-im', '--im', metavar='im', - nargs='+', dest='im', type=str, required=False, - help='List of patient image files (nii)') - parser.add_argument('-seg', '--seg', metavar='seg', - nargs='+', dest='seg', type=str, required=False, - help='List of patient segmentation files (nii)') - parser.add_argument('-imtest', '--imtest', metavar='imtest', - nargs='+', dest='imtest', type=str, required=False, - help='List of patient image files of test database (nii)') - parser.add_argument('-segtest', '--segtest', metavar='segtest', - nargs='+', dest='segtest', type=str, required=False, - help='List of patient segmentation files of test database (nii)') - parser.add_argument('-feat', '--feat', metavar='feat', - nargs='+', dest='feat', type=str, required=True, - help='List of patient feature files (HDF)') - parser.add_argument('-class', '--class', metavar='class', - nargs='+', dest='classs', type=str, required=True, - help='Classification of patients (text)') - parser.add_argument('-label_type', '--label_type', metavar='label_type', - nargs='+', dest='label_type', type=str, required=True, - help='Name of the label that was predicted') - parser.add_argument('-out', '--out', metavar='out', - nargs='+', dest='out', type=str, required=False, - help='Output folder') - args = parser.parse_args() - - if type(args.classs) is list: - args.classs = ''.join(args.classs) - - if type(args.label_type) is list: - args.label_type = ''.join(args.label_type) - - if type(args.out) is list: - args.out = ''.join(args.out) - - if type(args.feat) is list and len(args.feat) == 1: - args.feat = ''.join(args.feat) - - if os.path.isdir(args.feat): - args.feat = glob.glob(args.feat + '/features_*.hdf5') - args.feat = natsorted(args.feat) - - if type(args.im) is list: - args.im = ''.join(args.im) - - if type(args.seg) is list: - args.seg = ''.join(args.seg) - - if type(args.imtest) is list: - args.imtest = ''.join(args.imtest) - - if type(args.segtest) is list: - args.segtest = ''.join(args.segtest) - - # Read and stack the features - print("Reading features.") - image_features_temp = list() - for i_feat in range(len(args.feat)): - feat_temp = pd.read_hdf(args.feat[i_feat]) - feat_values = feat_temp.feature_values - feat_labels = feat_temp.feature_labels - - feat = {k: v for k, v in zip(feat_labels, feat_values)} - - image_features_temp.append(feat) - - # Get the labels and patient IDs - print("Reading class labels.") - label_type = args.label_type - label_data, image_features = lp.findlabeldata(args.classs, - label_type, - args.feat, - image_features_temp) - - labels = image_features[0].keys() - featvect = dict() - flab = dict() - for l in labels: - featvect[l] = {"all": [], "1": [], "0": []} - flab[l] = {"all": [], "1": [], "0": []} - - # Stack per feature type and class - print("Stacking features.") - label = label_data['label'].tolist()[0] - patient_IDs = label_data['patient_IDs'].tolist() - for imfeat, label, pid in zip(image_features, label, patient_IDs): - for fl in labels: - featvect[fl]['all'].append(imfeat[fl]) - flab[fl]['all'].append(pid) - if label[0] == 0: - featvect[fl]['0'].append(imfeat[fl]) - flab[fl]['0'].append(pid) - else: - featvect[fl]['1'].append(imfeat[fl]) - flab[fl]['1'].append(pid) - - # Save image of min and max response per feature - image_type = 'CT' - # imname = '/*/*/image.nii.gz' - # segname = '/*/*/seg*.nii.gz' - imname = '/*preop_Tumor.nii.gz' - segname = '/*Tumor_mask.nii.gz' - for fl in labels: - if 'cf_' not in fl: - features = featvect[fl]['all'] - maxind = np.argmax(features) - minind = np.argmin(features) - print fl, 'min', patient_IDs[minind] - print fl, 'max', patient_IDs[maxind] - - if args.im is not None: - im_min = glob.glob(os.path.join(args.im, patient_IDs[minind]) + imname) - if len(im_min) == 0: - # Search in testing folder - im_min = glob.glob(os.path.join(args.imtest, patient_IDs[minind]) + imname)[0] - else: - im_min = im_min[0] - - seg_min = glob.glob(os.path.join(args.seg, patient_IDs[minind]) + segname) - if len(seg_min) == 0: - # Search in testing folder - seg_min = glob.glob(os.path.join(args.segtest, patient_IDs[minind]) + segname)[0] - else: - seg_min = seg_min[0] - - im_max = glob.glob(os.path.join(args.im, patient_IDs[maxind]) + imname) - if len(im_max) == 0: - # Search in testing folder - im_max = glob.glob(os.path.join(args.imtest, patient_IDs[maxind]) + imname)[0] - else: - im_max = im_max[0] - - seg_max = glob.glob(os.path.join(args.seg, patient_IDs[maxind]) + segname) - if len(seg_max) == 0: - # Search in testing folder - seg_max = glob.glob(os.path.join(args.segtest, patient_IDs[maxind]) + segname)[0] - else: - seg_max = seg_max[0] - - if 'LBP' in fl: - # Save LBP image - LBPim = getfeatureimages(im_min, seg_min, - image_type=image_type, - types=['LBP'])[0] - filename = fl + '_min_' + patient_IDs[minind] + '.png' - savename = os.path.join(args.out, filename) - scipy.misc.imsave(savename, np.fliplr(np.rot90(LBPim, 3))) - - LBPim = getfeatureimages(im_max, seg_max, - image_type=image_type, - types=['LBP'])[0] - filename = fl + '_max_' + patient_IDs[maxind] + '.png' - savename = os.path.join(args.out, filename) - scipy.misc.imsave(savename, np.fliplr(np.rot90(LBPim, 3))) - elif 'Gabor' in fl: - # Save Gabor image - Gind = fl.index('Gabor') - Aind = fl.index('A') - gabor_settings = dict() - gabor_settings['gabor_frequencies'] = [float(fl[Gind + 6:Aind])] - try: - gabor_settings['gabor_angles'] = [float(fl[Aind + 1:Aind +1 + 4])] - except ValueError: - # 0.0: two numbers - gabor_settings['gabor_angles'] = [float(fl[Aind + 1:Aind +1 + 3])] - - Gaborim = getfeatureimages(im_min, seg_min, - image_type=image_type, - gabor_settings=gabor_settings, - types=['Gabor'])[0] - filename = fl + '_min_' + patient_IDs[minind] + '.png' - savename = os.path.join(args.out, filename) - scipy.misc.imsave(savename, np.fliplr(np.rot90(Gaborim, 3))) - - Gaborim = getfeatureimages(im_max, seg_max, - image_type=image_type, - gabor_settings=gabor_settings, - types=['Gabor'])[0] - filename = fl + '_max_' + patient_IDs[maxind] + '.png' - savename = os.path.join(args.out, filename) - scipy.misc.imsave(savename, np.fliplr(np.rot90(Gaborim, 3))) - elif 'sf_' in fl or 'hf_' in fl or 'tf_GL' in fl: - # Save segmentation - Shapeim = getfeatureimages(im_min, seg_min, - image_type=image_type, - types=['Shape'])[0] - filename = fl + '_min_' + patient_IDs[minind] + '_seg.png' - savename = os.path.join(args.out, filename) - scipy.misc.imsave(savename, np.fliplr(np.rot90(Shapeim, 3))) - - Shapeim = getfeatureimages(im_max, seg_max, - image_type=image_type, - types=['Shape'])[0] - filename = fl + '_max_' + patient_IDs[maxind] + '_seg.png' - savename = os.path.join(args.out, filename) - scipy.misc.imsave(savename, np.fliplr(np.rot90(Shapeim, 3))) - - # Save images - Histogramim = getfeatureimages(im_min, seg_min, - image_type=image_type, - types=['Histogram'])[0] - Histogramim[Histogramim == -1000] = 0 - filename = fl + '_min_' + patient_IDs[minind] + '_im.png' - savename = os.path.join(args.out, filename) - scipy.misc.imsave(savename, np.fliplr(np.rot90(Histogramim, 3))) - - Histogramim = getfeatureimages(im_max, seg_max, - image_type=image_type, - types=['Histogram'])[0] - Histogramim[Histogramim == -1000] = 0 - filename = fl + '_max_' + patient_IDs[maxind] + '_im.png' - savename = os.path.join(args.out, filename) - scipy.misc.imsave(savename, np.fliplr(np.rot90(Histogramim, 3))) - - -if __name__ == '__main__': - main() diff --git a/build/lib/WORC/plotting/scatterplot.py b/build/lib/WORC/plotting/scatterplot.py deleted file mode 100644 index 27b6e18d..00000000 --- a/build/lib/WORC/plotting/scatterplot.py +++ /dev/null @@ -1,120 +0,0 @@ -#!/usr/bin/env python - -# Copyright 2016-2019 Biomedical Imaging Group Rotterdam, Departments of -# Medical Informatics and Radiology, Erasmus MC, Rotterdam, The Netherlands -# -# 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. - -try: - import matplotlib.pyplot as plt -except ImportError: - print("[PREDICT Warning] Cannot use scatterplot function, as _tkinter is not installed") - -import pandas as pd -import argparse -import genetics.genetic_processing as gp -import os -import glob -from natsort import natsorted - - -def main(): - parser = argparse.ArgumentParser(description='Radiomics results') - parser.add_argument('-feat', '--feat', metavar='feat', - nargs='+', dest='feat', type=str, required=True, - help='List of patient feature files (HDF)') - parser.add_argument('-class', '--class', metavar='class', - nargs='+', dest='classs', type=str, required=True, - help='Classification of patients (text)') - parser.add_argument('-lab', '--lab', metavar='lab', - nargs='+', dest='lab', type=str, required=True, - help='Label of two features to plot') - parser.add_argument('-out', '--out', metavar='out', - nargs='+', dest='out', type=str, required=True, - help='Output png file') - args = parser.parse_args() - - if type(args.classs) is list: - args.classs = ''.join(args.classs) - - if type(args.out) is list: - args.out = ''.join(args.out) - - if type(args.feat) is list and len(args.feat) == 1: - args.feat = ''.join(args.feat) - - if os.path.isdir(args.feat): - args.feat = glob.glob(args.feat + '/features_*.hdf5') - args.feat = natsorted(args.feat) - - # Read and stack the features - image_features_temp = list() - for i_feat in range(len(args.feat)): - feat = dict() - feat_temp = pd.read_hdf(args.feat[i_feat]) - feat_temp = feat_temp.image_features - - for feattype in feat_temp.keys(): - feat_type = feat_temp[feattype] - for subtype in feat_type.keys(): - subfeat = feat_type[subtype] - for k in subfeat.keys(): - feat[k] = subfeat[k] - - image_features_temp.append(feat) - - # Get the mutation labels and patient IDs - mutation_type = [['GP']] - mutation_data, image_features = gp.findmutationdata(args.classs, - mutation_type, - args.feat, - image_features_temp) - - image_features = image_features.tolist() - # Select the two relevant features - feat1_c0 = list() - feat2_c0 = list() - feat1_c1 = list() - feat2_c1 = list() - mutation_label = mutation_data['mutation_label'].tolist()[0] - patient_IDs = mutation_data['patient_IDs'].tolist() - - for imfeat, label, pid in zip(image_features, mutation_label, patient_IDs): - print imfeat[args.lab[0]], pid - if label[0] == 0: - feat1_c0.append(imfeat[args.lab[0]]) - feat2_c0.append(imfeat[args.lab[1]]) - else: - feat1_c1.append(imfeat[args.lab[0]]) - feat2_c1.append(imfeat[args.lab[1]]) - - # Make a scatter plot - f = plt.figure() - subplot = f.add_subplot(111) - subplot.plot(feat1_c0, feat2_c0, linestyle='', ms=12, marker='o', color='navy') - subplot.plot(feat1_c1, feat2_c1, linestyle='', ms=12, marker='x', color='red') - # NOTE: arbitrary limits! - plt.xlim([0, 10]) - plt.ylim([0, 10]) - plt.xlabel(args.lab[0]) - plt.ylabel(args.lab[1]) - plt.title('Feature scatter plot') - plt.legend() - plt.show() - - f.savefig(args.out) - print(("Snapshot saved as {} !").format(args.out)) - - -if __name__ == '__main__': - main() diff --git a/build/lib/WORC/processing/ExtractNLargestBlobsn.py b/build/lib/WORC/processing/ExtractNLargestBlobsn.py deleted file mode 100644 index 61cedbfb..00000000 --- a/build/lib/WORC/processing/ExtractNLargestBlobsn.py +++ /dev/null @@ -1,70 +0,0 @@ -#!/usr/bin/env python - -# Copyright 2016-2019 Biomedical Imaging Group Rotterdam, Departments of -# Medical Informatics and Radiology, Erasmus MC, Rotterdam, The Netherlands -# -# 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. - - -from skimage.measure import label, regionprops -import numpy as np - - -def ExtractNLargestBlobsn(binaryImage, numberToExtract=1): - """Extract N largest blobs from binary image. - - Arguments: - binaryImage: boolean numpy array one or several contours. - numberToExtract: number of blobs to extract (integer). - - Returns: - binaryImage: boolean numpy are containing only the N - extracted blobs. - """ - - # Get all the blob properties. - labeledImage = label(binaryImage, connectivity=3) - blobMeasurements = regionprops(labeledImage) - - if len(blobMeasurements) == 1: - # Single blob, return input - binaryImage = binaryImage - else: - # Get all the areas - allAreas = list() - allCoords = list() - for blob in blobMeasurements: - allAreas.append(blob.area) - allCoords.append(blob.coords) - - allAreas = np.asarray(allAreas) - if numberToExtract > 0: - # For positive numbers, sort in order of largest to smallest. - # Sort them. - indices = np.argsort(-allAreas) - elif numberToExtract < 0: - # For negative numbers, sort in order of smallest to largest. - # Sort them. - indices = np.argsort(allAreas) - else: - raise ValueError("Number of blobs to extract should not be zero!") - - binaryImage = np.zeros(binaryImage.shape) - # NOTE: There must be a more efficient way to do this - for nblob in range(0, numberToExtract): - nblob = abs(nblob) - coords = allCoords[indices[nblob]] - for coord in coords: - binaryImage[coord[0], coord[1], coord[2]] = 1 - - return binaryImage diff --git a/build/lib/WORC/processing/RTStructReader.py b/build/lib/WORC/processing/RTStructReader.py deleted file mode 100644 index 0c31444e..00000000 --- a/build/lib/WORC/processing/RTStructReader.py +++ /dev/null @@ -1,215 +0,0 @@ -#!/usr/bin/env python - -# Copyright 2016-2019 Biomedical Imaging Group Rotterdam, Departments of -# Medical Informatics and Radiology, Erasmus MC, Rotterdam, The Netherlands -# -# 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. - - - -""" -@author: Zhenwei.Shi, Maastro - -usage: - - paste this file in same directory as your main script file - and use the following lines - - import DCM_ImgRT_Reader_ZW - - path1=r'c:\ABC\FolderContainingDicomOfimageCTscan' - path2=r'c:\ABC\FolderContainingDicomOfRTstruct' - DCM_ImgRT_Reader_ZW.Img_Bimask(image_path=path1,rtstruct_path=path2,ROI_name) - -""" - -import dicom as pydicom -import os -import numpy as np -from skimage import draw -import SimpleITK as sitk -import re -import glob -import natsort - - -def get_dicoms(input_dir, logfile=None): - dicom_files = glob(input_dir + '/*.dcm') - dicom_files = natsort.natsorted(dicom_files, alg=ns.IGNORECASE) - - dicoms = list() - for i_dicom in dicom_files: - dicoms.append(pydicom.read_file(i_dicom)) - - return dicoms - - -def load_dicom(dicom_folder): - dicom_reader = sitk.ImageSeriesReader() - dicom_file_names = dicom_reader.GetGDCMSeriesFileNames(dicom_folder) - dicom_reader.SetFileNames(dicom_file_names) - dicom_image = dicom_reader.Execute() - - return dicom_image - - -def poly2mask(vertex_row_coords, vertex_col_coords, shape): - fill_row_coords, fill_col_coords = draw.polygon(vertex_row_coords, vertex_col_coords, shape) - mask = np.zeros(shape, dtype=np.bool) - mask[fill_row_coords, fill_col_coords] = True - return mask - - -def get_pixels(scan): - image = np.stack([s.pixel_array for s in scan]) - image = image.astype(np.int16) -# image[image == -2000] = 0 - intercept = scan[0].RescaleIntercept - slope = scan[0].RescaleSlope - if slope != 1: - image = slope * image.astype(np.float64) - image = image.astype(np.int16) - image += np.int16(intercept) - return np.array(image, dtype=np.int16) - - -def ROI_ref(rtstruct_path, ROI_name): - mask_vol = load_dicom(rtstruct_path) - M = mask_vol[0] - for i in range(len(M.StructureSetROISequence)): - if str(ROI_name) == M.StructureSetROISequence[i].ROIName: - ROI_number = M.StructureSetROISequence[i].ROINumber - break - return int(ROI_number) - - -def match_ROIid(rtstruct_path, ROI_number): - mask_vol = load_dicom(rtstruct_path) - M = mask_vol[0] - for j in range(len(M.StructureSetROISequence)): - if ROI_number == M.ROIContourSequence[j].RefdROINumber: - break - return j - - -def RTStructReader(RTStructFile, ROI_name, image_folder): - ''' - Input: - image_path is directory containing dicom files - rtstruct_path is directory containing RTstruct files - ROI_name is the ROI stored in RTstructure - - Output: - mask file written in current directory - image volume file written in current directory - - ''' - # Volume of DICOM files and RTstruct files - image_vol = load_dicom(image_folder) - L = pydicom.read_file(glob.glob(image_folder + '/*.dcm')[0]) - mask_vol = pydicom.read_file(RTStructFile) - print dir(mask_vol) - - # Slices all have the same basic information including slice size, patient position, etc. - # L = image_vol[0] - print image_vol - # LP = get_pixels(image_vol) - LP = image_vol - num_slice = LP.GetSize()[2] - - mask = np.zeros([num_slice, L.Rows, L.Columns],dtype=np.uint8) - - xres=np.array(L.PixelSpacing[0]) - yres=np.array(L.PixelSpacing[1]) - - # ROI_number = ROI_ref(rtstruct_path,ROI_name) - # Check the number of the ROI corresponding to the ROI name to extract - for i in range(len(mask_vol.StructureSetROISequence)): - if str(ROI_name) == mask_vol.StructureSetROISequence[i].ROIName: - ROI_number = mask_vol.StructureSetROISequence[i].ROINumber - break - - ROI_id = match_ROIid(rtstruct_path,ROI_number) - - for k in range(len(M.ROIContourSequence[ROI_id].ContourSequence)): - UIDrt='' - - UIDrt = M.ROIContourSequence[ROI_id].ContourSequence[k].ContourImageSequence[0].ReferencedSOPInstanceUID - - for i in range(num_slice): - UIDslice = image_vol[i].SOPInstanceUID - - if UIDrt==UIDslice: - sliceOK = i - break - - x=[] - y=[] - z=[] - - m=M.ROIContourSequence[ROI_id].ContourSequence[k].ContourData - - for i in range(0,len(m),3): - x.append(m[i+1]) - y.append(m[i+0]) - z.append(m[i+2]) - - x=np.array(x) - y=np.array(y) - z=np.array(z) - - x-= L.ImagePositionPatient[1] - y-= L.ImagePositionPatient[0] - z-= L.ImagePositionPatient[2] - - pts = np.zeros([len(x),3]) - pts[:,0] = x - pts[:,1] = y - pts[:,2] = z - a=0 - b=1 - p1 = xres; - p2 = yres; - - # What is this exactly: Orientation times voxels spacing in a 2x2 matrix? - m=np.zeros([2,2]) - m[0,0]=image_vol[sliceOK].ImageOrientationPatient[a]*p1 - m[0,1]=image_vol[sliceOK].ImageOrientationPatient[a+3]*p2 - m[1,0]=image_vol[sliceOK].ImageOrientationPatient[b]*p1 - m[1,1]=image_vol[sliceOK].ImageOrientationPatient[b+3]*p2 - - # Transform points from reference frame to image coordinates - m_inv=np.linalg.inv(m) - pts = (np.matmul((m_inv),(pts[:,[a,b]]).T)).T - - # So you create the mask by making a polygon: how to treat boundary pixels? How was the original contour made? - mask[sliceOK,:,:] = np.logical_or(mask[sliceOK,:,:],poly2mask(pts[:,0],pts[:,1],[LP.shape[1],LP.shape[2]])) - - LP-=np.min(LP) - LP=LP.astype(np.float32) - LP/=np.max(LP) - LP*=255 - - image=sitk.GetImageFromArray(LP.astype(np.float32)) - Mask=sitk.GetImageFromArray(mask) - - return image, Mask - - -if __name__ == '__main__': - folder = 'HN1004_20170922_' #interobs05_20170910_CT - RTStructFile = glob.glob('/home/martijn/Documents/test/' + folder + '/SCANS/DCM/DICOM/*.dcm')[0] - # image_files = glob.glob('/home/martijn/Documents/test/' + folder + '/SCANS/DCM/DICOM/*.dcm') - image_folder = '/home/martijn/Documents/test/' + folder + '/SCANS/DCM/DICOM' - name = 'GTV-1auto(DR)' - RTStructReader(RTStructFile, name, image_folder) diff --git a/build/lib/WORC/processing/__init__.py b/build/lib/WORC/processing/__init__.py deleted file mode 100644 index e69de29b..00000000 diff --git a/build/lib/WORC/processing/classes.py b/build/lib/WORC/processing/classes.py deleted file mode 100644 index de5db9c4..00000000 --- a/build/lib/WORC/processing/classes.py +++ /dev/null @@ -1,38 +0,0 @@ -#!/usr/bin/env python - -# Copyright 2016-2019 Biomedical Imaging Group Rotterdam, Departments of -# Medical Informatics and Radiology, Erasmus MC, Rotterdam, The Netherlands -# -# 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. - - -class switch(object): - """ Object to mimic the MATLAB switch - case statement.""" - def __init__(self, value): - self.value = value - self.fall = False - - def __iter__(self): - """Return the match method once, then stop""" - yield self.match - raise StopIteration - - def match(self, *args): - """Indicate whether or not to enter a case suite""" - if self.fall or not args: - return True - elif self.value in args: - self.fall = True - return True - else: - return False diff --git a/build/lib/WORC/processing/label_processing.py b/build/lib/WORC/processing/label_processing.py deleted file mode 100644 index 6d7b67e8..00000000 --- a/build/lib/WORC/processing/label_processing.py +++ /dev/null @@ -1,285 +0,0 @@ -#!/usr/bin/env python - -# Copyright 2016-2019 Biomedical Imaging Group Rotterdam, Departments of -# Medical Informatics and Radiology, Erasmus MC, Rotterdam, The Netherlands -# -# 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 xnat -import requests -from requests.packages.urllib3.exceptions import InsecureRequestWarning -import numpy as np -import os -import configparser -import WORC.addexceptions as ae -import pandas as pd - - -def load_labels(label_file, label_type): - """Loads the label data from a label file - - Args: - label_file (string): The path to the label file - label_type (list): List of the names of the labels to load - - Returns: - dict: A dict containing 'patient_IDs', 'label' and - 'label_type' - """ - _, extension = os.path.splitext(label_file) - if extension == '.txt': - label_names, patient_IDs, label_status = load_label_txt( - label_file) - elif extension == '.csv': - label_names, patient_IDs, label_status = load_label_csv( - label_file) - elif extension == '.ini': - label_names, patient_IDs, label_status = load_label_XNAT( - label_file) - else: - raise ae.WORCIOError(extension + ' is not valid label file extension.') - - print("Label names to extract: " + str(label_type)) - labels = list() - for i_label in label_type: - label_index = np.where(label_names == i_label)[0] - if label_index.size == 0: - raise ae.WORCValueError('Could not find label: ' + str(i_label)) - else: - labels.append(label_status[:, label_index]) - - label_data = dict() - label_data['patient_IDs'] = patient_IDs - label_data['label'] = labels - label_data['label_name'] = label_type - - return label_data - - -def load_label_txt(input_file): - """ - Load the patient IDs and label data from the label file - - Args: - input_file (string): Path of the label file - - Returns: - label_names (numpy array): Names of the different labels - patient_ID (numpy array): IDs of patients for which label data is - loaded - label_status (numpy array): The status of the different labels - for each patient - """ - data = np.loadtxt(input_file, np.str) - - # Load and check the header - header = data[0, :] - if header[0] != 'Patient': - raise ae.WORCAssertionError('First column should be patient ID!') - else: - # cut out the first header, only keep label header - label_names = header[1::] - - # Patient IDs are stored in the first column - patient_ID = data[1:, 0] - - # label status is stored in all remaining columns - label_status = data[1:, 1:] - label_status = label_status.astype(np.float) - - return label_names, patient_ID, label_status - - -def load_label_csv(input_file): - """ - Load the patient IDs and label data from the label file - - Args: - input_file (string): Path of the label file - - Returns: - label_names (numpy array): Names of the different labels - patient_ID (numpy array): IDs of patients for which label data is - loaded - label_status (numpy array): The status of the different labels - for each patient - """ - data = pd.read_csv(input_file, header=0) - - # Load and check the header - header = data.keys() - if header[0] != 'Patient': - raise ae.WORCAssertionError('First column should be patient ID!') - else: - # cut out the first header, only keep label header - label_names = header[1::] - - # Patient IDs are stored in the first column - patient_ID = data['Patient'].values - - # label status is stored in all remaining columns - label_status = data.values[:, 1:] - label_status = label_status.astype(np.float) - - return label_names, patient_ID, label_status - - -def load_label_XNAT(label_info): - """ - Load the patient IDs and label data from XNAT, Only works if you have a - file /resources/GENETICS/files/genetics.json for each patient containing - a single dictionary of all labels. - - Args: - url (string): XNAT URL - project: XNAT project ID - - Returns: - label_names (numpy array): Names of the different labels - patient_ID (numpy array): IDs of patients for which label data is - loaded - label_status (numpy array): The status of the different labels - for each patient - """ - requests.packages.urllib3.disable_warnings(InsecureRequestWarning) - - config = load_config_XNAT(label_info) - url = config['XNAT']['url'] - projectID = config['XNAT']['projectID'] - - # Example - # url = "http://bigr-rad-xnat.erasmusmc.nl" - # projectID = 'LGG-Radiogenom' - # url = label_info['url'] - # projectID = label_info['projectID'] - - session = xnat.connect(url, verify=False) - - subkeys = session.projects[projectID].subjects.keys() - subkeys.sort() - session.disconnect() - - baseurl = url + '/data/archive/projects/' + projectID + '/subjects/' - patient_ID = list() - label_names = None - label_status = list() - for i_patient in subkeys: - # Extra check as there are bound to be some fake patients - if projectID in i_patient: - patient_ID.append(i_patient) - - data = requests.get(baseurl + i_patient + - '/resources/GENETICS/files/genetics.json') - datadict = data.json() - - # Load and check the header - if label_names is None: - label_names = list() - label_names_temp = datadict.keys() - for i_name in label_names_temp: - # convert u_str to str - label_names.append(str(i_name)) - - label_status_temp = datadict.values() - label_status.append(label_status_temp) - - label_names = np.asarray(label_names) - label_status = np.asarray(label_status) - - return label_names, patient_ID, label_status - - -def findlabeldata(patientinfo, label_type, filenames, - image_features_temp=None): - """ - Load the label data and match to the unage features. - - Args: - patientinfo (string): file with patient label data - label_type (string): name of the label read out from patientinfo - filenames (list): names of the patient feature files, used for matching - image_features (np.array or list): array of the features - - Returns: - label_data (dict): contains patient ids, their labels and the label name - """ - # Get the labels and patient IDs - label_data_temp = load_labels(patientinfo, label_type) - label_data = dict() - patient_IDs = list() - label_value = list() - for i_len in range(len(label_data_temp['label_name'])): - label_value.append(list()) - - # Check per feature file if there is a match in the label data - image_features = list() - for i_feat, feat in enumerate(filenames): - ifound = 0 - matches = list() - for i_num, i_patient in enumerate(label_data_temp['patient_IDs']): - if i_patient in str(feat): - - # Match: add the patient ID to the ID's and to the matches - patient_IDs.append(i_patient) - matches.append(i_patient) - - # If there are feature files given, add it to the list - if image_features_temp is not None: - image_features.append(image_features_temp[i_feat]) - - # For each label that we have, add the value to the label list - for i_len in range(len(label_data_temp['label_name'])): - label_value[i_len].append(label_data_temp['label'][i_len][i_num]) - - # Calculate how many matches we found for this (feature) file: should be one - ifound += 1 - - if ifound > 1: - message = ('Multiple matches ({}) found in labeling for feature file {}.').format(str(matches), str(feat)) - raise ae.WORCIOError(message) - - elif ifound == 0: - message = ('No entry found in labeling for feature file {}.').format(str(feat)) - raise ae.WORCIOError(message) - - # if image_features_temp is not None: - # image_features = np.asarray(image_features) - - # Convert to arrays - for i_len in range(len(label_value)): - label_value[i_len] = np.asarray(label_value[i_len]) - - label_data['patient_IDs'] = np.asarray(patient_IDs) - label_data['label'] = np.asarray(label_value) - label_data['label_name'] = label_data_temp['label_name'] - - return label_data, image_features - - -def load_config_XNAT(config_file_path): - ''' - Configparser for retreiving patient data from XNAT. - ''' - settings = configparser.ConfigParser() - settings.read(config_file_path) - - settings_dict = {'XNAT': dict()} - - settings_dict['XNAT']['url'] =\ - str(settings['Genetics']['url']) - - settings_dict['XNAT']['projectID'] =\ - str(settings['Genetics']['projectID']) - - return settings_dict diff --git a/build/lib/WORC/resources/fastr_tests/CalcFeatures_test.py b/build/lib/WORC/resources/fastr_tests/CalcFeatures_test.py deleted file mode 100644 index 94ed7abd..00000000 --- a/build/lib/WORC/resources/fastr_tests/CalcFeatures_test.py +++ /dev/null @@ -1,72 +0,0 @@ -#!/usr/bin/env python - -# Copyright 2017-2018 Biomedical Imaging Group Rotterdam, Departments of -# Medical Informatics and Radiology, Erasmus MC, Rotterdam, The Netherlands -# -# 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. - -IS_TEST = True - - -def create_network(): - # Import the faster environment and set it up - import fastr - - # Create a new network - network = fastr.Network(id_='CalcFeatures_test') - - # Create a source node in the network - source_segmentation = network.create_source('ITKImageFile', id_='segmentation') - source_image = network.create_source('ITKImageFile', id_='image') - source_metadata = network.create_source('DicomImageFile', id_='metadata') - source_parameters = network.create_source('ParameterFile', id_='parameters') - - # Create a new node in the network using toollist - node_calfeatures = network.create_node('CalcFeatures', id_="calcfeatures") - - # Create a link between the source output and an input of the addint node - node_calfeatures.inputs['segmentation'] = source_segmentation.output - node_calfeatures.inputs['image'] = source_image.output - node_calfeatures.inputs['metadata'] = source_metadata.output - node_calfeatures.inputs['parameters'] = source_parameters.output - - # Create a sink to save the data - sink_features = network.create_sink('HDF5', id_='features') - - # Link the addint node to the sink - sink_features.input = node_calfeatures.outputs['features'] - - return network - - -def source_data(network): - return {'segmentation': 'vfs://worc_example_data/CLM/seg_tumor_c.nii.gz', - 'image': 'vfs://worc_example_data/CLM/image.nii.gz', - 'metadata': 'vfs://worc_example_data/CLM/00000.dcm', - 'parameters': 'vfs://worc_example_data/CLM/parameters.ini'} - - -def sink_data(network): - return {'features': 'vfs://tmp/results/{}/calcfeatures_{{sample_id}}_{{cardinality}}{{ext}}'.format(network.id)} - - -def main(): - network = create_network() - - # Execute - # network.draw_network() - network.execute(source_data(network), sink_data(network), execution_plugin="ProcessPoolExecution") - - -if __name__ == '__main__': - main() diff --git a/build/lib/WORC/resources/fastr_tests/__init__.py b/build/lib/WORC/resources/fastr_tests/__init__.py deleted file mode 100644 index e69de29b..00000000 diff --git a/build/lib/WORC/resources/fastr_tests/elastix_test.py b/build/lib/WORC/resources/fastr_tests/elastix_test.py deleted file mode 100644 index fde99c9c..00000000 --- a/build/lib/WORC/resources/fastr_tests/elastix_test.py +++ /dev/null @@ -1,73 +0,0 @@ -#!/usr/bin/env python - -# Copyright 2017-2018 Biomedical Imaging Group Rotterdam, Departments of -# Medical Informatics and Radiology, Erasmus MC, Rotterdam, The Netherlands -# -# 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. - -IS_TEST = True - - -def create_network(): - # Import the faster environment and set it up - import fastr - - network = fastr.Network(id_="elastix_test") - - source1 = network.create_source('ITKImageFile', id_='fixed_img') - source2 = network.create_source('ITKImageFile', id_='moving_img') - param1 = network.create_source('ElastixParameterFile', id_='param_file') - - elastix_node = network.create_node('elastix_dev', id_='elastix') - elastix_node.inputs['fixed_image'] = source1.output - elastix_node.inputs['moving_image'] = source2.output - link_param = network.create_link(param1.output, elastix_node.inputs['parameters']) - link_param.converge = 0 - - outtrans = network.create_sink('ElastixTransformFile', id_='sink_trans') - outtrans.inputs['input'] = elastix_node.outputs['transform'] - - transformix_node = network.create_node('transformix_dev', id_='transformix') - transformix_node.inputs['image'] = source2.output - transformix_node.inputs['transform'] = elastix_node.outputs['transform'][-1] - - outimage = network.create_sink('ITKImageFile', id_='sink_image') - outimage.inputs['input'] = transformix_node.outputs['image'] - - network.draw_network(img_format='svg') - network.dumpf('{}.json'.format(network.id), indent=2) - - return network - - -def source_data(network): - return {'fixed_img': {'s1': 'vfs://worc_example_data/elastix/img0/slice047.mhd'}, - 'moving_img': {'s1': 'vfs://worc_example_data/elastix/img1/slice091.mhd'}, - 'param_file': ['vfs://worc_example_data/elastix/parAslice.txt', 'vfs://worc_example_data/elastix/parBslice.txt']} - - -def sink_data(network): - return {'sink_trans': 'vfs://tmp/results/{}/elastix_output_trans_{{sample_id}}_{{cardinality}}{{ext}}'.format(network.id), - 'sink_image': 'vfs://tmp/results/{}/elastix_output_image_{{sample_id}}_{{cardinality}}{{ext}}'.format(network.id)} - - -def main(): - network = create_network() - - # Execute - # network.draw_network() - network.execute(source_data(network), sink_data(network), execution_plugin="ProcessPoolExecution") - - -if __name__ == '__main__': - main() diff --git a/build/lib/WORC/resources/fastr_tests/segmentix_test.py b/build/lib/WORC/resources/fastr_tests/segmentix_test.py deleted file mode 100644 index 52e107b4..00000000 --- a/build/lib/WORC/resources/fastr_tests/segmentix_test.py +++ /dev/null @@ -1,68 +0,0 @@ -#!/usr/bin/env python - -# Copyright 2017-2018 Biomedical Imaging Group Rotterdam, Departments of -# Medical Informatics and Radiology, Erasmus MC, Rotterdam, The Netherlands -# -# 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. - -IS_TEST = True - - -def create_network(): - # Import the faster environment and set it up - import fastr - # Create a new network - network = fastr.Network(id_='Segmentix_test') - - # Create a source node in the network - source_segmentation = network.create_source('ITKImageFile', id_='segmentation_in') - source_mask = network.create_source('ITKImageFile', id_='mask') - source_parameters = network.create_source('ParameterFile', id_='parameters') - - # Create a new node in the network using toollist - node_segmentix = network.create_node('Segmentix', id_="segmentix") - - # Create a link between the source output and an input of the addint node - node_segmentix.inputs['segmentation_in'] = source_segmentation.output - node_segmentix.inputs['mask'] = source_mask.output - node_segmentix.inputs['parameters'] = source_parameters.output - - # Create a sink to save the data - sink_segmentation = network.create_sink('ITKImageFile', id_='segmentation_out') - - # Link the addint node to the sink - sink_segmentation.input = node_segmentix.outputs['segmentation_out'] - - return network - - -def source_data(network): - return {'segmentation_in': 'vfs://worc_example_data/CLM/seg_liver.nii.gz', - 'mask': 'vfs://worc_example_data/CLM/seg_tumor.nii.gz', - 'parameters': 'vfs://worc_example_data/CLM/parameters.ini'} - - -def sink_data(network): - return {'segmentation_out': 'vfs://tmp/results/{}/segmentix_{{sample_id}}_{{cardinality}}{{ext}}'.format(network.id)} - - -def main(): - network = create_network() - - # Execute - # network.draw_network() - network.execute(source_data(network), sink_data(network), execution_plugin="ProcessPoolExecution") - - -if __name__ == '__main__': - main() diff --git a/build/lib/WORC/resources/fastr_tools/elastix4.8/elastix.xml b/build/lib/WORC/resources/fastr_tools/elastix4.8/elastix.xml deleted file mode 100644 index ca684719..00000000 --- a/build/lib/WORC/resources/fastr_tools/elastix4.8/elastix.xml +++ /dev/null @@ -1,171 +0,0 @@ - - A wrapper around elastix. elastix is open source software, based on the well-known Insight Segmentation - and Registration Toolkit (ITK). The software consists of a collection of algorithms that are commonly used to solve - (medical) image registration problems. The modular design of elastix allows the user to quickly configure, test, and - compare different registration methods for a specific application. A command-line interface enables automated - processing of large numbers of data sets, by means of scripting. - - - registration - - - - - - - - - - - - - - - - - - - - - - - - - - - elastix version: 4.800 - - elastix registers a moving image to a fixed image. - The registration-process is specified in the parameter file. - - Call elastix from the command line with mandatory arguments: - -f fixed image - -m moving image - -out output directory - -p parameter file, elastix handles 1 or more "-p" - - Optional extra commands: - -fMask mask for fixed image - -mMask mask for moving image - -t0 parameter file for initial transform - -priority set the process priority to high or belownormal (Windows only) - -threads set the maximum number of threads of elastix - - The parameter-file must contain all the information necessary for elastix to run properly. That includes which - metric to use, which optimizer, which transform, etc. - It must also contain information specific for the metric, optimizer, transform, ... - For a usable parameter-file, see the website. - - Need further help? Check the website http://elastix.isi.uu.nl, or mail elastix.support@gmail.com. - - - Copyright (c) 2004-2013 University Medical Center Utrecht - All rights reserved. - - License: - - Redistribution and use in source and binary forms, with or without - modification, are permitted provided that the following conditions are met: - - * Redistributions of source code must retain the above copyright notice, - this list of conditions and the following disclaimer. - - * Redistributions in binary form must reproduce the above copyright notice, - this list of conditions and the following disclaimer in the documentation - and/or other materials provided with the distribution. - - * Neither the name of the University Medical Center Utrecht nor the names of - its contributors may be used to endorse or promote products derived from - this software without specific prior written permission. - - THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND - ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED - WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE - DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR - ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES - (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; - LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON - ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT - (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS - SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - - - - - - - - - - - - - - - - high - abovenormal - normal - belownormal - idle - - - - - - - - - - - - RTFM! =] - - - @article{KleinStaring:2010, - author = "{S. Klein AND M. Staring AND K. Murphy AND M.A. Viergever AND J.P.W. Pluim}", - title = "{elastix: a toolbox for intensity-based medical image registration}", - journal = "{IEEE Transactions on Medical Imaging}", - volume = "{29}", - number = "{1}", - pages = "{196 - 205}", - month = "{January}", - year = "{2010}", - } - - - - - slice047.mhd - slice091.mhd - parAslice.txt - parBslice.txt - - {bin} - -f - {input.fixed[0]} - -m - {input.moving[0]} - -p - {input.parameters[0]} - -p - {input.parameters[1]} - -out - {output.directory[0]} - - TransformParameters.0.txt - TransformParameters.1.txt - - - - diff --git a/build/lib/WORC/resources/fastr_tools/elastix4.8/testdata/input/parAslice.txt b/build/lib/WORC/resources/fastr_tools/elastix4.8/testdata/input/parAslice.txt deleted file mode 100644 index f47cabf5..00000000 --- a/build/lib/WORC/resources/fastr_tools/elastix4.8/testdata/input/parAslice.txt +++ /dev/null @@ -1,117 +0,0 @@ -// Affine Tranformation - -//ImageTypes -(FixedInternalImagePixelType "float") -(MovingInternalImagePixelType "float") -(FixedImageDimension 2) -(MovingImageDimension 2) - -//Components -(Registration "MultiResolutionRegistration") -(FixedImagePyramid "FixedRecursiveImagePyramid") -(MovingImagePyramid "MovingRecursiveImagePyramid") -(Interpolator "BSplineInterpolator") -(ResampleInterpolator "FinalBSplineInterpolator") -(Resampler "DefaultResampler") -(Transform "AffineTransform") -(Optimizer "AdaptiveStochasticGradientDescent") -(Metric "AdvancedMattesMutualInformation") - -// Scales the rotations compared to the translations, to make -// sure they are in the same range. The higher this parameter, -// the smaller the changes in rotation angle in each iteration. -// If you have the feeling that rotations are not found by elastix, -// decrease it; if elastix crashes after a few iterations, with -// the message that all samples map outside the moving image -// buffer, you may have to increase this parameter. -//(Scales 50000.0) -// Better use automatic scales estimation -(AutomaticScalesEstimation "true") -// Automatically guess an initial translation. -(AutomaticTransformInitialization "true") - -// The number of resolutions. -// 1 Is only enough if the expected deformations are small. 3 or 4 mostly works fine. -// Less smoothing in Z-direction -(NumberOfResolutions 3) -(ImagePyramidSchedule 4 4 2 2 1 1 ) - -// If you use a mask, this option is important. You can -// set it for each resolution differently. -// If the mask serves as region of interest, set it to false. -// If the mask indicates which pixels are valid, then set it to true. -// If you do not use a mask, the option doesn't matter. -(ErodeMask "false" ) - -// Whether transforms are combined by composition or by addition. -// In generally, Compose is the best option in most cases. -// It does not influence the results very much. -(HowToCombineTransforms "Compose") - -// Number of spatial samples used -(ImageSampler "RandomCoordinate") -(FixedImageBSplineInterpolationOrder 3 ) -(UseRandomSampleRegion "false") -(NewSamplesEveryIteration "true") -(CheckNumberOfSamples "false") -(MaximumNumberOfSamplingAttempts 10) -(NumberOfSpatialSamples 256 ) - - -//Number of grey level bins in each resolution level, -// for the mutual information. 16 or 32 usually works fine. -(NumberOfHistogramBins 32 ) -(FixedLimitRangeRatio 0.0) -(MovingLimitRangeRatio 0.0) -(FixedKernelBSplineOrder 3) -(MovingKernelBSplineOrder 3) - -//Order of B-Spline interpolation used in each resolution level: -// It may improve accuracy if you set this to 3. Never use 0. -(BSplineInterpolationOrder 1) - -//Order of B-Spline interpolation used for applying the final -// deformation. -// 3 gives good accuracy. -// 1 gives worse accuracy (linear interpolation) -// 0 gives worst accuracy, but may be appropriate for -// binary images; this would be equivalent to nearest neighbor -// interpolation. -(FinalBSplineInterpolationOrder 3) - -//Default pixel value for pixels that come from outside the picture: -(DefaultPixelValue 0) - - -// The following parameters are for the StandardGradientDescent -// optimizer. They determine the step size. -// Especially SP_a needs to be tuned for each specific application. -// The number of iterations is also important. - -//Maximum step size of the RSGD optimizer for each resolution level. -// The higher you set this, the more aggressive steps are taken. -(MaximumStepLength 0.7 ) - -(WriteTransformParametersEachIteration "false") -(WriteResultImage "false") -(CompressResultImage "true") -(WriteResultImageAfterEachResolution "false") -(ShowExactMetricValue "false") - -//Maximum number of iterations in each resolution level: -// 100-500 works usually fine. -(MaximumNumberOfIterations 512 ) - -//SP: Param_a in each resolution level. a_k = a/(A+k+1)^alpha -// For MI, NC, NMI, you could start around a = 1000.0 -//(SP_a 1000.0 ) - -//SP: Param_A in each resolution level. a_k = a/(A+k+1)^alpha -(SP_A 20.0 ) - -//SP: Param_alpha in each resolution level. a_k = a/(A+k+1)^alpha -(SP_alpha 1.0 ) - - - - diff --git a/build/lib/WORC/resources/fastr_tools/elastix4.8/testdata/input/parBslice.txt b/build/lib/WORC/resources/fastr_tools/elastix4.8/testdata/input/parBslice.txt deleted file mode 100644 index 30d19190..00000000 --- a/build/lib/WORC/resources/fastr_tools/elastix4.8/testdata/input/parBslice.txt +++ /dev/null @@ -1,122 +0,0 @@ -// B-Spline transformation - -//ImageTypes -(FixedInternalImagePixelType "float") -(FixedImageDimension 2) -(MovingInternalImagePixelType "float") -(MovingImageDimension 2) - -//Components -(Registration "MultiResolutionRegistration") -(FixedImagePyramid "FixedRecursiveImagePyramid") -(MovingImagePyramid "MovingRecursiveImagePyramid") -(Transform "BSplineTransform") -(Interpolator "BSplineInterpolator") -(Optimizer "AdaptiveStochasticGradientDescent") -(ResampleInterpolator "FinalBSplineInterpolator") -(Resampler "DefaultResampler") -(Metric "AdvancedMattesMutualInformation") - -// ::::::::::::::::::::::::::::: Parameters to tune ::::::::::::::::::::::::::::::::::::::: - -// :::: Pyramid -(NumberOfResolutions 3) -(ImagePyramidSchedule 4 4 2 2 1 1) - - -// :::: Optimizer - StandardGradientDescent :::: - -// Maximum number of iterations -(MaximumNumberOfIterations 2048) - -//SP: Param_a in each resolution level. a_k = a/(A+k+1)^alpha -// MI around 1000.0 -(SP_a 10000.0 ) - - -// :::: ImageSampler :::: - -// Number of sample (2000 - 5000) -(NumberOfSpatialSamples 256 ) - -// If UseRandomSampleRegion is set to "false", the sampler draws samples from the entire image domain. -// When set to "true", the sampler randomly selects one voxel, and then selects the remaining -// samples in a square neighbourhood (in mm) around that voxel (localized similarity measure). -(UseRandomSampleRegion "true") -(SampleRegionSize 50.0 50.0) - - -// :::: Transform :::: -// Grid of control points -// This grid is defined by the spacing between the grid nodes, in voxel size -// For each resolution level you can define a different grid spacing. This is what we call multi-grid. -// The GridSpacingSchedule defines the multiplication factors for all resolution levels. -(FinalGridSpacingInPhysicalUnits 10.0 10.0) -(GridSpacingSchedule 4.0 4.0 2.0 2.0 1.0 1.0) - - -// :::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::: - - -// :::: Transform :::: -// Whether transforms are combined by composition or by addition. -// In generally, Compose is the best option in most cases. -// It does not influence the results very much. -(HowToCombineTransforms "Compose") - - -// :::: Several :::: -(ErodeMask "false" ) -(WriteTransformParametersEachIteration "false") -(WriteResultImage "false") -(ResultImageFormat "nii.gz") -(CompressResultImage "true") -(WriteResultImageAfterEachResolution "false") -(ShowExactMetricValue "false") -(ResultImagePixelType "float") - - -// :::: Metric :::: -//Number of grey level bins in each resolution level: -(NumberOfHistogramBins 32 ) -(FixedLimitRangeRatio 0.0) -(MovingLimitRangeRatio 0.0) -(FixedKernelBSplineOrder 3) -(MovingKernelBSplineOrder 3) -(UseFastAndLowMemoryVersion "true") - - -// :::: ImageSampler :::: -(ImageSampler "RandomCoordinate") -(FixedImageBSplineInterpolationOrder 1 ) -(NewSamplesEveryIteration "true") -(CheckNumberOfSamples "false") -(MaximumNumberOfSamplingAttempts 10) - - -// :::: Optimizer - StandardGradientDescent :::: -//SP: Param_A in each resolution level. a_k = a/(A+k+1)^alpha -(SP_A 100.0 ) -//SP: Param_alpha in each resolution level. a_k = a/(A+k+1)^alpha -(SP_alpha 0.6 ) - - -// :::: Interpolator and Resampler :::: -//Order of B-Spline interpolation used in each resolution level: -// It may improve accuracy if you set this to 3. Never use 0. -(BSplineInterpolationOrder 1) - -//Order of B-Spline interpolation used for applying the final -// deformation. -// 3 gives good accuracy. -// 1 gives worse accuracy (linear interpolation) -// 0 gives worst accuracy, but may be appropriate for -// binary images; this would be equivalent to nearest neighbor -// interpolation. -(FinalBSplineInterpolationOrder 3) - -//Default pixel value for pixels that come from outside the picture: -(DefaultPixelValue 0) - -(MaximumStepLength 0.7) - diff --git a/build/lib/WORC/resources/fastr_tools/elastix4.8/testdata/input/slice047.mhd b/build/lib/WORC/resources/fastr_tools/elastix4.8/testdata/input/slice047.mhd deleted file mode 100644 index bd265418..00000000 --- a/build/lib/WORC/resources/fastr_tools/elastix4.8/testdata/input/slice047.mhd +++ /dev/null @@ -1,13 +0,0 @@ -ObjectType = Image -NDims = 2 -BinaryData = True -BinaryDataByteOrderMSB = False -CompressedData = False -TransformMatrix = 1 0 0 1 -Offset = -57.6875 -250.738 -CenterOfRotation = 0 0 -ElementSpacing = 0.625 0.625 -DimSize = 256 256 -AnatomicalOrientation = ?? -ElementType = MET_SHORT -ElementDataFile = slice047.raw diff --git a/build/lib/WORC/resources/fastr_tools/elastix4.8/testdata/input/slice047.raw b/build/lib/WORC/resources/fastr_tools/elastix4.8/testdata/input/slice047.raw deleted file mode 100644 index cb02d1aa..00000000 --- a/build/lib/WORC/resources/fastr_tools/elastix4.8/testdata/input/slice047.raw +++ /dev/null @@ -1,155 +0,0 @@ -i“±®­¯®®Â¯žŽ{“…sv‘‰¢³§¢•‚ˆk[aw€Ž©§™ª¸»ƒzy‘Ç™}‹‚~zkkaw©¾¢—¼»cbb‹¡³ÐÑ©‘]~~ƒ¦¦žœ¬´®¤mht„“•­¹¶¼¤|ƒŠ§«¥¼É¶†W`y~€}•œŒ ÅÁž¤¥¿ÑÉŲŸ”tz¢›†§ÊÝàŇ…“–†‚wp†ž›£ºÓ¹’Ÿ§‡š«ª’ˆŒ}Œtr|™µ®“Ÿ¬²¤¡š•§¶˜‡z€¹«…yjgYv –rNXy•œŸ¡‡sŽ»Ê¾•…ƒm™¶Å§…XGYƒ£¨œxo…©¢Œ¬ÅÕ˜ƒ“žˆŒ‰etŽ ›Ÿ±Â²´¦©£Œ}dKels”“Ž ‡c_vƒ’ˆ µšŒ±´t‚³Ìœ`bv™™„ws¢±¸§¸Ø«Ž€•´ÇÆÀ®‰uk\s‡°¥© ¸²¡qfz­·­¯ž¡xs€‡££¿Ìº˜poyŠ‰‰‹–©ÂÇǾÁÙ¸¬¯¤¯²¯­—}{˜Št‚©ËÜ´‚tŒ•‘–©œ ½Á·ÁáÌ’Žš›•¢¾¿¤’‘Œwjg‚´³›¥©¨œ©œ£´©“€¢¯”v[ivn°²VVr›¾·£‘yx¨·¬˜nˆ¥ž“eRg‹œ«™k`w…ˆˆŒŒ¥·†“Š‚‰tdumz“ £¿À£¢©”seRD29Lf}ƒ’‘ž§“y~‹˜Œ‘´Ÿ€²Ç³¯¢š¯¿œ^av’¡–‡†~}©¬©½Î¿¹²¤Ÿ³·•}agoŽ–›žŠ†Š—£¥‡¡ÀÆ«˜”„qŠ…hv„ˆ…ª¹©‘ƒzŒœ©¼ÀIJ£Š‡€‹¦——Š‚•Ÿ¦”yhx¯¾­„q‚™ž§¶±“”ÁÊÏÍÚФ—²¹³¦¶Îº“–un^{³¼ª—••—¢œ”¬¸œvqj€ªœut‹to§Ç q7IŽÊÁ¡¤Š~¶¶›Œ}l‚•”•…_d…–¡ª‘lhjpy…†•‘›»Ä¥‚ƒ™pqzYT‹ª©±µ§Šƒ†‚ull[BDbg’š‘|Š¥¤”€‘•†ž¹¯Á×ö°¨ˆovŽtp‚†¢ž–tyŽ©´ª»Èп«›‘”±¤¤žƒsu˜²£•ƒvr€ ­Ï´°µÂ§lfq„œ‘y~x{ ¨¢¬•…ˆ”’žž«¨²Á¹®~|n‹•¦ °¸½¨£ªššoecˆ«³‹—¡²ÀÌÍ©š³¿Ã»ÉÒ¼¤¦®«‡y¯¤£“ˆ{vhv©Å³²r¦§‘~‰±¢tf]xª½†“ˆ’–£x8<–ÒƬ ¨‘˜­¼“zzyv€Š€‡‚£¨™“|hej~•¢¯¡Äâ³v€wjmxfWuŸ“§ “zut†žœ“…Œ—›‘t[‰º¾ÐÀ°˜¨ÁÌÔÀ¦›œ“{OS{ˆ”‡— ’—‰Ÿ¾Ó¬—¢˜—…wªÇ¾¯|{‹¯©–†owŠ­ÁÔÃ¥¦¨ƒ\aonŠ” †xz‹”«µ¢˜§©ª©§¨»ÒÈö¤‹ŠŽ‘Š˜¦©²·ÆÈÆ…o„‰rky“§¡ž£ÂÇÍÙÏÑɪ£’—ª°¥Žƒ…‹}~¡  ƒkreyš²º§€v|›¢ƒ†£¨“wy‘µÖÄ‹Œ—ž‰‹Žš…MVƒ¶¼­š™ˆ‡•´š€q{bw’‡¤” ¡—–’‘yiy…Œ¦¦ˆ³Ò±‚„vs{tpyohz{pp‚‘•zƒ›»¼Æ¹šŒŽ¤ |‡Ž²Óåçزš°ÇË°›–†Œ‘Šrc„°Á ††‡|€²²™‰{`WdhXS°ªŸ—“›€’ž¢¤‰…ƒ•¯º³®Ž•–xodt¥°«¥ž¢€­½½²®£—‘‡·ºžŒ{tpŠ›˜•Ÿ²µ¦¡¤¿¦‹r|¤–wv‰ž¤ª³¶±®¤ «¥—Šwptžš £›Ÿ†˜–“‹Ž†^Obu†¡œ~†Š¤¸¶–“ÄÉšƒ˜ªÂÀ–otˆŽ’§†~a\q›œž‰ˆ­­€_q„•˜…™¢Ž““–›‹ls‡“™’‹ŸÂÌŸ‚…‹„sZn‹r]dmem‹‘§²ÂêãÈ£Ž¤¥Ÿ·¯«¶³Åâæϧ¥»ª¤ª¦›¨Ÿ¨–›š¨©§™wz€mejmŽ¯­’rSp~q^}¡ª˜¢¦nt‰Ž¨º—–€xŒ¢£¡ªªš{ƒ¢¿°™žusž°Ÿ”ˆ‹‰†~t“{qxw¢¤¯­´¸´’®Á·³¤™•Ž}vŠ›¨ª³«¦Žˆˆ“–we{‹¦Âź•œ‰…„†qU]i|«·£ž°Û›™—£Àš‰}—¯¹‘eSrŒ¥ˆ{w„€gk|°ºš€w†¬´‚Ze‰§¡ª—­¥‰ŠŠœ£ §{o}Šƒ‚‡Œ³Ø¯‚‰•‹lb}|€snlmzŒ‰‰™¨¯ÊçðéꢰÄÌÚ°Ž›¶áã¼›«µ©¨°¨—‘ŠšŽ†€‚‡~y…ƒom]^qªÉ·°–‡›¤Žu­¾²—›¤—“–˜ ¨¢—|u~–©¯º¼¦lpyŸŒ‡€„}rprƒ‘“–‹z}€€‹šª­ž¬¶Á°£±§¨¨£®ª „|”°¹¯¯ª£¤˜zv‚“°Á‡}†•¹Êʯ‹wi~Ÿ¡ªµ”…Œ¦´¼®°µ¨¹ªš–Ÿ”ªœ˜‚ˆ‘©—|^r€ƒƒŒ¨–lU}§·®‰|‹š•‡rRwš¦¯·Å´vuœ®ºšwV]‰‡{Ž|€¥ÙÅ“…‘}cn³—Œš—rvŽ“©Ÿ’ ³¹¾ÌàÙª¢°·Á¹šŽ‘¨´Ø´§­° “™rh…“gjm•«®¡rd\U´ª®¢‘–©”¨ÛÏ©‡– ¦®§¢ŠŽ‡“œµ»ª¡_^m…’‚x—¯™“‹“˜‘š{…ˆœ¡¥®¬¡Ž•³£‰™ˆ„‹”¢®˜‘™¢¢©´«’œ‘‰„‘ªÉêÅ’’¸Í¸”wo®ËÑÏÒ±ª®¯™‚s†’‘‘…˜¤¯ž”¯®—of—ŽlXr‡¥¹£tR[™¼º¥‘“Œ‘ž}Re«­µ¾µ¡ƒywŽ¯¨}`YYvŽ|†€uºÚš~‰‰…ŽÇ¸¶ž‘‰—©¥®·­°·µ”‹¸Í¹¦ª¥¦™‚™šš²À¤“–‡‰Š’€ŽœlZ[q™¬¥³ ŠjRCPd¤¼­zª¬£Àξ—~x…”²³¨†{™¦™‡€‹˜¶¾¯¯¦…rbž¥“‚–º¼ÃÔ³“™•–„¯½ª•™©´µ ””„Œ†{€‚—ªÁ¬ª«£˜›­²€€ƒ{z…‘’±ÐæÉ Š›­µ¦¢­²®«Â¸ÅÔÁ˜”˜Šyal„œƒ¦·µ©•¶§lZ~ ž~ki¢¤¢³²}G>p«­¥•ˆŠ–’|U]–­¶¹œ›¦‘}xŽzWSWe€‹•|fn“°ž’Ž¿ÚæåÚÉÆ´¥¤­¶ÄÄÀšt§®»«›¥¥”‘¢¥Ÿ£­¹¥‹Ž…Ž“ ¢•|jdVv‰›·£›‰g[QRawŒ©³¤~oƒ¥±¶±”ykopˆ›°¬‘~~Œ“†„„ËÚÖØÇ¢cW{­‰q~•±¹¸À°¢ šŠ–•‘š–Šxs‹¦¿²ž•šˆˆ¡™Ž„…€›¥¤ ¡¥£¢~†“‰’ŽœÅ̺¢|z~½µµÎÖ²¢š¢£¯œ„ys``x|’®ˆµ®­—u_™®£…m”º´¶«aKP„—ƒuy|‹¢„dN‡©Äµ ¢§wfz“QUi|—ªª{Ye…£§¥„nkb°ÃØçøßÅ­ž¨Á¿ºž–“xŠŸš«~z„Ž—¨–¦¯¯Ÿ˜“›’Ž™Ÿˆ•”‰„‚Ÿ¬º›ŽšzYdmy—­¢”’——¬²ª‰‡’“ww„›‰zo}’šˆƒsx²åÚÖ£hPv¥²“œžœŠ—Ÿ²¶šw\Qdelx“ƒnf}š¼±¥¾°’¥©„xy|ˆš‘°º¤—˜Œ”‚‹…Œ¦™™¦µÃ±˜z‹›²¯¤·Á¢{cauƒˆŽ|`Id”Œ–‡yŠ®³¨—›‡€‰jr–µ®›“ˆ’£¸¨”a\`pujwtŒ´Ÿa8_•Ç³ŸŠ‚„tƒ¡zWg‘¬ª¡rTd‘¢­£ŽqkqÎÐÐÐä÷Û¶²£Ÿµ²‡Ž“q•™‘rXy’Šs{˜©°®¥—{†¨ºÁº£«}^[j·É¹§ŠjdlxŠ–™˜·­—•˜ªœŸ£¨‡Ti}—‘˜ž”||`^_”¹ÁØ„[xªÀª¥¢rgax—¶¨oRNm­¨tHa‹¬¨ ¬µ“š·Ž€˜››£®¿§ƒ‘•‘yx{‘¥™š¨¨¤™„ušž¢¬®rRQ]zz©£gDj”°—‰†ˆ{£ ¡°š’lz}£¯Ãª‡…•°Êµ¨…Š„{rmoz{‚ˆ±˜y:=q™¯š™Š€ƒˆ »º…]ŒˆŽ†an©··¼¢†lzï͵¸ÊÇ­²¾³¬¢’wjXh}•¥®˜•••••ƒxkk†Ä²¡©“{Ž¢­§±°ƒhRZSi•­—‡xy|{ƒ£–ŒŽywŽ¯°¨¶¹§Š‹·¿­„|Ž‰„ƒfRO{£½Ùà°mbœÇ²žycWUQf~«Äznt‡š©²¯koz‡“””®ª¤¸±¯°¨”}†’–™„‹“°¬prv†…Ž¢¢•‰Œ‘ ¢›¨­°˜p]kƒˆŒ¦®·„ch€££ŽŠ’’x|šº¯zfiuzŒ¤ÁÔ¯‚‡¨½Å½¤ ‹uicjkˆ‡ŒDR¡ÑÌ¢”“Ÿ£¦ÍÄG^mb{›Œˆ¯«ÁÁ³ubhåÚÇ´¢Ÿ²«££¡ž—Šl_Xb†œ¯±ŸÁÜŃ~ykvœž£§¡¯¯ŸŠw†‚~{pjy’{†…‹–œ›¾¸Šqwjc†´¿¸°­µ¢“¯³hPy˜°³¸ž’— ³ÝéÂ…Bd¹´‹qt{vx}›¶•ŠzŠª§³¼­‡yto†‘’°¼¯³¾µª™ŽurœŸ—š¯¬¥yt€}‚— š”‘•–”•š–š¤½¬€{Š¡³­¨†s|•¤¥§†š§šhgy™”š¿©•”¨¯žŽ±¬—tiflzsrŠ}~…_@T—ÍÙº£‘££– ¬ gXWr™±¢‹“ºÁ²’“pb°®Å؉§˜|\`q‚‹|q‡ŒŒ‘• ¶§¬©ƒq“Š~’’»Á½¼À“nio“¡™“}^Yj{‰Š›™•Ÿ¬¹Šjx{o|±Ë½ž¥®¨~—ª™Ž•¶ÀÚÒ¹‘”«¾ÊæÏ›WYŽ…—ª®¤‘up‘Œ’¨µ¿¸¯»µ™v}š³¶¨­¤¥«œ…~jw…’›¸­—¬ªˆ€’ šž¦¢‘š–šž—“¤«£•”¤®“hy¦Ã´››šž˜•“§›¤«›‡†Œž•ˆŠ~i|¾ËÆŠ~Œ„š“ƒdav„Žƒio€‚†–ƒnk‘´àÖŸ‹Ÿ†„†œ²–bdˆ®Ëª‰—È™¶¼šV¼Ãªœ…{…k_m†•¤’š¤“€yp“•booz–œ¤—¤¢¡œ¤np­¬tsqWYe›–œ  Œ•„zŠ‘~›¬§”‘§§‡”µ¼¬–“¢ž•Š†˜·Á×ØÈ~DWoŒ±À©•Š‡–’•­±µª®¸¼±’›°¼²Œ|m€‘“€zzœ£«­¯Ÿ“¦‰‹—™¥²²š‡†›µÆ¹«ª³²ªœ“‡ ˜„²¯—”Ÿ£ °¤œ•™ž³±ž„Ÿ»©|o…y]‚ÄÜÄŽnivttnUOVƒ–mi’œ™¬¶œvs¡ßà¦saqiahŒ±µ›†€Ž§¼´£¸¸µ¶Ê™q†©¼§£ˆ|‹”†—™‘¥Ÿ•™‚pjƒ–‰¡¦¤¢Ž–huŽŸ¹žl}Œ •ykffZc`uo€Š•{}…yjxŒ‡ŽŠ•›•£·³™²·ˆmƒ¤ª¦¡§–¡¦®±£vLHfŠ¦¹¹¡’¦£—²»²³ ²Ãºº¶¥¡ˆ€“¥°œwwv–¤–¤·º²Ÿµª¥”š“„Ž†‘´Æ¡ƒˆ¦¿Ç½¬“Ÿ¾¼¯•ˆ•™‡Œ†œ£–”¤ Šx…š•³Æ´›‰¦¬Œq…wo¯ÔÍ‘aXgqZdtpRYŸ®™ˆ¤­¼³”|u~§¾²rZtdQ…§«¤›†g]ÔἫ³ÒÇÌÇy™½Àºš„ˆ§•’—ž˜Ÿ›xty‚ƒ“ª¯š£‘…‚wigŠŠ|•”ž«Ê¦€jx‘ŽmwŒ|yqx~†œ‰w{‹tp‚™— ªµ¶¦ ®©ƒ‘•¤²¿ÓÛØÇŸz…y…€‡bVo’›Ÿ¤–¨¡†•½¸º¨™•——‚on€s‰›œŸ­ª™¡¶¾ÌÅ·¢¢°¸³¢¨§Ž†‰Œ­¾­ž­¼Ãƹ°˜¹Å²ª˜“‘“}‹¿¿¨©‘…xlxš—Œ¥¶’im¢–„gTfÆß©mak~ogœŽg} ¿©ygˆ””Œosmguœ½¢w†yc•¾·‚€m‰ÊåäÌŸœÃ¹Â·Œ“˜²¸´‘ih‡†rmw}€‹Š‡™©­­‘†ŽŠ”²…r~•|šœ{ŠŸ¹­‹yw}€ols£¡‰z}{„‹™¡šˆŸ¤†™–Š“¦¶¶¸ž¤¯“°ÊÔäéÙ½±l~Š’¬²È«–ˆ•‰‹’”§—„‚„š¤tR<it€ƒŠ˜šu„¤±¸³—ƒ‰Á˽µ¤ŒŒ¦«³°§Ÿˆ„¡£»½¹©¸Ã¾ÃЮ©ž¨°­­¨™†•œ’˜´º«šƒvŒvv„p†£”}f‘iasVH‘Ѻ…iy–€nŽ°–noš©±‚n€‹qty…yjcˆµ¹ˆy‚Ÿ·¨ŠŠŠ}„½ÕÖº™¤¥¯¯—‡‰¡›–€ZRht\Sheo“¥²Ðз«Š|k~¢¥˜ž®«™ˆ•zc^ay ¬‰€mtbbHAk¨Ÿ’Šgh{’¢˜”“•£œ‹sgjzy¨§ÃɼÅáб³³³¥£•‡uŒ†‰¿ÔϯŒxks}ˆ‘‚wjh{Œpi›¡°¥}wœ¯§©˜‡y™ÈÅ®´žŒž¬¯¡—‹˜«¯¥±³™–—““œ›˜œ–—™ «®˜‡Ÿ§§¨ª§efmv†„†Š‡t†Š‚vˆ˜gj‹~Sr™ ypo‰ƒy~ˆl„¶Ê­—–ˆ{‚—¢’uŠ±¢•o†—”š„‚Œ|Y„´éÑž˜–›¬À­p~’”‚cPR_Z_t}¦¶¯°³¬˜…s`„‘—˜µÆλ Œ{yoQ]uw¢’…shopP=P”²¶¨”hbj€˜¥¦„{tsrsŠ‡v•½ËÕçܲ±V^‰š‰“‡Š|}sp¢ÌÏĶŒs…«·ž˜ˆw|†¯·È¢˜·Å½¹¿Á£‚Š¬­”|ibv°ÒͶ–‘§Šy‰«Ÿ‘™ˆŒ¡¡¹­Ÿ{z~„‡‰œ¨ ˆu…±³§¡›Ÿ£´­·±w€ztyˆ º¡{z‹ˆŠœ~o…Žd4R}{w|ˆ~‚…—Œ}”¬Á´°’•Žˆ€›–ˆ£ž”~¦‹Œp€³•c`¬á߸“| ÕÕµw{}}la]noo‚“§°Â·qib}„ŽŸ¥›’“˜ž‰kmuz~{{‚jtŽ‚y€”‡iou‰œªŽxntƒ—´´q]b’ž¤¾À²¶½ÊÀȯŠƒrI=jš¡—…uƒƒ{yz”½ÙÏÅ¥‚˜¬·¨™†™£§¸±££­²¾½¶§ŸŸ˜rzŸ£ƒxvmxšÚçÁ¥›¨Ÿ~‰–¯¾Ä°›ŸÄɳ¬¡ƒ‚†šÁ¼™u[‚¯³´«ž”žÂÏÆË˳³­¨¤¥ª§‡„ƒ…”ŠxuiaD@w‡ª˜œ–‰ŒŠƒ„‰£¤¡•–˜—‰Œ¤¨Ÿ¤’£¬”¢¬ªŒ”¡š´°s–ÊÓ²›–ÄÝÄ“_[cci}•š’‘Š‰z‰¡¬°—b`u‰©¬œ™”qtpeVauu‹ˆ…ƒ…tn›••‘—»¶—Š€‹š¥¥’”ƒºª—z`X‚©ÐÝඖ¬•…„šˆ…dIUŽ¨¡ŽvŒ¢¤–‹Ž˜°»¯ŒŠ¡Âɼœ“„tw}ˆ›°±¹ª›Š|…‰³« •’‡±ÑÙÄ·½ËÇ ¥³ÊÖŸ—¶Ã¾¶º­“’—ªÒ•ow•¡Æº¬’ŽŸºÐÙÒ鱬²®œ„rl‹†|v{q}…iUJd‹»£‡‰y‡ˆ…ŠŸ™‹€•šŒŠ—¯¤Š›Àŵ±¢„w¶½°«¶±˜w¯ØÆ°¢¦Æ¢ŒTSgn€¡©¯µ´±œŽ—Ÿž ž–—ˆž¨ƒwxkfp‡•« š¡™„Ž¡Ÿ’—«º«Ÿ ¦©¨ ¡’…wˆ˜¥¤ ¤«­¸·¾µ“„‰rhx’˜cQUr£²®…¥²˜¦}„“ Á®’}h…—§˜™xk]¤®¹¹Æµ®š•¢«²·¾°¡‘›Ÿ¥ÊÇ·ÊÒÐÑ¢Ž›§¡¦’‰”«¶Ç˲©œ¡š”©´¾§†zm{ŽµÀÁ ‘¨¿Ì¼¾­ž•˜‹Œ|~–›‹_u~ƒrJCPk–·”w{}zƒ’¤ £œ |˜™ˆzt›¦ž£µÁ°•’‡–×Ä· «»œ}k¥Ö϶‰›®˜vo­¡¦«ÆÄÔ¼Ÿš~„ËäÓ¸ˆnsƒ—¼®¯¿¶¤Šš¸¸¯®‘‚‚Ž™—¨•¦²µ¸¬±­•‡|ƒ†ŠŒ­¶ÆÍÌ´‘t{{y€‘‡~”Œ’Ÿ‚vo{¢º¾± ¸¿º¸°Š|‹ŽnRFRo‰†“¬º—‹“°¼¹ÆÛâÛÍÊ­­£¡§º¬¬Ã·½Ñг©¯«¬…it†„Š{œ¸²­½¤„Œ—Ž„¡—Ž‘ž„’–©´¸²£›Ÿœ›«¯¶–‚‰Œ”‰ƒ…~‚xfm|rI7[l„Œ­¡‹|Œ‘©ÐÒ½†~šœk‹„{mˆ™¯žŠ §“¢¢š³¸°–«¾¬€zœèä·’~Œž¦ª›–«´§n‡«»¿­š“–ºÖÊȨ†…˜¸ÙÞÎÕ϶¥ˆ}u{‹ˆ‹ˆš§¨¶´³¢µ°¯ª°¤œ‰{´Þ̹ÂŲ “¡‡r‰Œ‰q‡sd‘•Ž¥²«ª­²³¼¸œ«Ã¯¯¦rx‰~€ƒ~grs€~·ÝËÊìÙÊÇÇÒßÏÀ´¨¯¨¬­´»¿ÉÀ—²´™zqƒ”„vs}œ˜†‹¢´£“¤¡”–šˆŒ²«“›½Ç¦–ŽŒ•¦º™Šƒ|‘¶¿¯šzq€xw~x~ssjWjjj`l~‚‰†ª¶•™¦›¶ÏåÂuUi–u|‡“ˆkv’…•š±µ”œ§‘§²’ž·°£ƒ–ßúÏ–}Š‡¯¤®¨“}dE^œ¤²ž–œ™¸º´©ž”…˜•Œ“ˆqfbnƒ“› «½·´³¤‘œµ³§©¯¬¥—•¬×Ë«·¨¤Œqzuj{–†fu“†snœª¤±·È¼Çʳ†~‡~ƒž’‘”“’«·¨zw}™¼ÅÃÖÒ¹­©·¯º³š’‘˜£ž¿É¢zter¦¥ŠŽ—‘‰ŒœšŠ™œ˜—ƒ{€¥¹¾²ÆÛ¢‘’‰‚‚ƒk{¶Ã¤‰wqombcwvnst\aƒ”Ž^ZiŒŠƒ›ˆ¦´«´´Æ°mBB‚ž„‰œŒt{›}|®¾±—’˜{{¬°¡˜³ºÇ¸¿åݶŒmh˜Ÿ–•†€WPUu•Ÿ¡§¬¦¦•‚“œ£ŠŠmN@I@7awyngh|‚Œ™¯«˜¢zr—›Ÿ¬¦šžºÂˤ™Š˜¥©µ·°«‹jhb`{jb›€|š ¶´¯Ñʹ±©|n_h„­¶¨¢ –“£±´°œŠˆrexŒ•¶¶°®´°®ÆÅ°„}dVx™±ªÄäÔ£”ŠŽ§ª²­ž˜§§±±²ª‘’—„~~‚{’¶Âº¨µÃ¾ª©‘ts‰—šuow– §§¨“mowo„~vnsqwhvqOWo“¤¸¹À­³°Ÿ–‰UFm‚‚º§ƒo–‚©´´¦}wq‚ ±—‹¤ºÈÉ•Ú汄mn„‹”‹…‰Š‘§„ŒŠŽ“—‹xlo{¡…VMDX^enz‚Œst{ˆŠ€›¤™€cPp•¯¸°¥¥¤Ôüã³’ˆ®ËÄÉÖÝű|…kff„km‘¬µˆ·²ª¢“‰•{^[cj‹ºÏͽ¯¤ ‘Žš¬°ª¨¤†r‚Œ‰šŸ®ÅÅ»šœÄ­‘™€s~²ËÙÙéßÆ¢”•§§¯½Â²®¸ºµ¬“Œ†ŒŠ”¤•›¬§¥§°¶µ§¨€oy˜¬‘hdt“›¡ª²™zvŠ‚m~ƒin|Œˆ†‹–c^Rz«œ»Óȵ¦š•‹}ˆ}F:mˆ™¿²†f«‰‹¦´¡iit„’›‰~­È»µ‘ŽËÓ«Œ‹†Ž¬­§¶ÁÎ˽•‡wy}wpk}€kwœ£“€}~€w’™¥©¨¨˜‰„ƒŒŸ˜¦¼¾ÒßÕÐƾÇú'ñÇËî -ðÑØæײ¤Ÿ¡…—„€š½´•‚ƒ¨¸œx…ŠŠƒUTn–˜ª»»¶²¼¤—–žž¬¯´¡˜•Ÿ˜ †Ž¢ÀÀrx¹ÔÈ˽šŽ¦ÎÐÔãçÓ ˆ”¼Î½¨¢¦®¦Ÿ‹¢¿ÙÓ²¯©—œ¥©¥¨’zw€‡Ÿ’‡œ lxŽ–¦œ¤jw‡h¦¨¢£´¹±¨£‡~…žµ¤°Ö˵¤›˜x€˜Y5d¥§§xc{¾’a’­ …bly” |v§¸£ÀŽ˜ÅÊ«¨²©’¶Â¶»ÊèâÑ©€see^Relfhpw£©¢¨¦“’•¡ÈàÚǸ»¼É¾¿ºÃÔúñßíÿó=74 -âÕÈÁÒÐÞäÖ¾¸š‰Ž ŸŽ¶Á®œ‘›•™•Ž{wsai‹­¤¢©œ‘˜œ¦ÇÞʳ¨¯²Öôé·¬¾Ù¨¢ÂÛïòÙ²ÂÙãêêêÍŸ¥ŸŸ¥ÂÞÀ°¡¤®°µ¤¶æøæµ–y‹…š¢£ips~‘–ž”“qx‹˜–‡ª–ft‡«âïØÛàêͲÇô½ÒÚ¾­¸ÊÁ·£•¢„r{lRP…š“r_KW˜œtŸ®¨rohŒ~k‘•¦·¥šÀƳµÆÞ—‘¥·¹ÏÝÞ«iSZWlrhbj’¤°·±›šºÁÅÛÝÈÉáþù98ö÷ý -ùó6=(ò!ûßì%0>D2Ö±‚Žš¿½°¨Ä°–² «Ã°ŸŠjHpœ™œªºÔÒÉè(-&') -%O@ÙÌÖìßçöãíþïôøðóæÚÚÇÊäùÞàù༠š·¹¹¶ÎæøÝ·˜§¨­¬¦‹ovyŽš››¢šiv}’~{Ž’Ÿœ•vqŽÂßòø úÆÒÍÀÈØÞƉ{‹¬«™ˆ¨•^h}Y\s’•x^E?–Ê…j€­³’oevƒj”¡©¢—²Á³Äã詧©—³¸Á›|¤¥‘ƒ„˜““µ¿§Œ“³µ¼Ò×ðûþ()($"+8<-"óìîçé ýÿöå)VUILWa\dIE9ýÝÀ²ÄÔÚ«~”¨©ÃÖ½¦®ÓñîÕ¨‚‡ÈÔÄÒØÔëõHj{‰…a6+'*/#÷íóùîÜâô  ýïø5E+÷üðΩ¦À¹©»ÍÙÖÓ¶°µ·«˜“—“{€–œ¨£ š‹zš˜s[jz†“™v‘¯ÊÒâöøòѪ†‘Œ¯´šer¦¸š„˜ll„wfe{†‚XZP˜gs‹¯•nt|‹‹“–x}–ž²µ³ÂÞíØ”—½²œšš‚¯®´½«†ˆ‹x´¾¾˜¦­ÕÔáÿ."#*)   ëÙâÚÞçãÏÅò .Zu„—Ž…weZKeyP äŶÐåÅÍãô÷èùçäì0ÔÁêòÕ¾Òæ"Ccp{qj[ED9=:A4þüîèÛêý  '+&þþ-F8òêÓ¹ÂÓ¾¢¯Á¼¸ ¤”›–™ƒ’žž©µ·°¯«“‘‰›©”Sa“©·ª˜’ˆŽÊàÊÊÚѹ˜{[isp‰o†Œ‚Œ©ÄàÇ~~˜y^MHQrxM_¤§t„£¤†qŽ°•‰„n{—™«Ç¡²ð²¯¬¡œ‡‡„ˆ›ƒtrvrpxŒºÒßÛÛþ ý=NP3ÿîîïø  úÜðñи»Ì×èãå [„oZ??Op–‹‹†~}aVZˆx< B‘½¦“}ejb‚{jC6LI Ì¥§Å»ÂæEYba`digior|uTPYE& þæõ$ùõîòýûúý÷âàÙÓàÒ®›š·¡ –—“‘¥§¢­ÍÊÄÆ¿’yƒœž¥¢ÆÓ«Ãɵµ­¥œ……ŸÆÚض¯¦xrlnwpP8b´Á®´ÂÙ¸‹‚˜gld:6=w¦—vJx²†Œ„˜³¦‘}œ£€yŠtz”¥­Õµqç ³›Šv}€‘˜œ§ˆn]igbt‡†¦ÂÐÐæ575FM佡ª‘ž»ãëëßòîÛâñ ÷èõ"o³šy^Nt‹ykYaz‡u^grrr‡·íYŒs`A79( åØšW0&î´š³ÁÔ DcZQ_bizskg‹†‡UG9)& ýÿ !õÿýÓÞòÖàð÷ÛÆÔÑØĘ‹ ·­¬±®²½¶–‰Š®§²±­ ƒ”¬²©Éç"äãؽ¶¦‘†w‡‰š¯—šq`b€xƒiQ:> Ó½›³¼º™|}„]FL@FV‹· ƒ]zªœž¦’‰›‰‹‹~Œ”ko¦®¼špr·ê‰‚upyŠ˜ °»§~jeq€ˆˆ£¹çßâå-2!íƱŸ”nWcdy®Üþ  àÒã -HszjR]¨’uWM[qzuXe“¹ÞáÿHº°xachZJ2ê±”™œ§bòäû -&AWZ]Ynqoqle~Ž’‘tUP\hDú÷ü úûñ/óàáÝöýûέ°ÎßÔ³š¢ÁÔÑØÑÄ̼¢Œ‘Š•§“š±»²§ÀÓ×ÿýöß̳¥¢Ž{}}itzyz~mquqhfhK?k¦» ÂÃaasXWSHWp„¯«xq‘³Ÿ’…ln—„™“–e”Ÿ§¼³vZÀ“ ˆ†¥²­²¢–¬ÃÀ¯¥§ÃÞìåóýè×ΟŸµÊÆ•spwš±Íö#33!õô%Po|imcyŒ‘{q_]afƒ}Š¢¶å>˜× 0úëÜÚä)4:FDU' FH@JKb‡ebrdfmq\pŸ«±˜‚syOèêÜç ÷ 0$&&!üõý -ýàäîòòúýîæüþäÙÇ®©”Œ‡¤Â·¶ÃÄÐÁÔÞɯ¤‡•Ž€rjw}wsqpvmWS[zyrYXw²±…|›¦‰~szsl``tŽ°·jTg˜°¦‡cNPr– Ÿ’’©‹gy•ªÃÆ‚To–§¥©§†xnƒ“¢º·¼·Êòìõìñݸ¡¨ÐÔÕÛ¼ºÃâú !' -&=/ÞÏÊUYDO_lqjh\^sm^Top_fiz“µÝ0uÑÇnÌ™udix§ê&X\UPc|>Ñtsˆ”Žt^^gjn^Kv›¢˜ˆ{xdDἤÈìõ'IE==MF0' +7:0%8=4-ü 9A2æËÏÁ¬z—¼¾Ã²•–¤±¨—ƒŠ~y‰’‰cjv†pWZPlxI/T{ˆl]n¥Ã’zž®ŠlwˆƒpvŒ­ƒgFb£§bfe`M|…ˆ’©^qŸ®Èï®Wb“’Œ‡ŽŒ¯ÄûÚù!!òÔÉþÒÞò!!/`­Ÿi>% ÷ùåݬ—«ïEN@GR€ƒ‡iG4RdZan‡hJGlŸí5\s–¿„2Ê|QC?Ez±õ5;GX`Sù¹ž¢•taWm†ƒqLITƒŽ~lepfF߸¨‹´ãTmu\k{‚}oOFUQMRA2DHE#  Y`M>úòóóÙεÊÕ̬Šv™•‰¢§’}vŒrc„}qB)@d{uZl‰šo`b„¯Ë›ˆ–²£Žr^v…ad‚nYQJgŒ«ŠyzŠqWSozf{£–syœ¨Éß©ah{†€zŒ’ŒŒŽ³ÊÏâú íïûÿ&-CV`WuŠ£µ´‹Y çÎÇ¿®ˆÇ*`N;Hs–€@õ7^†{mlb<HZŒìOqµµf(í¸…fN<_rºâ -"HK?꿹­¦Žpk{”Ž†qY\qk_d_[PN@ù覂 ;Ks¤µ§¡´¥›—fev~ssmY6Kk9,Kdjqe7+O/ -îɯ«Ÿª£Ÿ‘š·¦y~†j~yj^A2M`f–}“Žyebj“³”†š±ƒm`xiYRXVSJLd“»¢Šˆ‰tcnmji‹Å™›—©¿¶š}s¢ ‡‚ ”Œ™®²Õíóëèîú'0Sfbnpo€‰¶Ã©gîöÿþïÒ¬¯ó=E45IslNþ(:YB?OFLSN_±f€•u4ý¾‡yhP|¨Ä¹Ðï UQ0Ý°˜©²‚ww}Œ†wVCDLEEGE,  õÒæ*W]k†¬À³’†~sr†‘Œ…‚sQGNN9fwprrp;5VcFGT<#&éÊÄ»´±¥¡•–“z‚tihlinUuuZiˆ†‹”’m_bo{£¥‰”ž§ªn^tpVARwsX;`¡É´‘‹z}€—ŧp|žÃÒÉœ€Ä§®¹ÑÔÁÎÚãÚßÑǬ¶ÜèþáéE[>MPjsu‚˜‡’¯Ç´ˆÕé  öúþÓ© ×*3@I_|Œc-$%><YWH6Mû|˜pj`;Ù“gehu®Öôîÿ6“YHÊŸonj^bghd`r[B<V^WO5)&,#ýî7JQUmƒ ’os{y|•~kugM?IHv©¬½oL:atgw‰oG4õãÏ­´ºÑº­«Éб‚oo|w„‚y‚†ck“˜•Ÿ†aT`w¡º›—«­©˜Š\]oiS[•ze€«°¦Š‘ž”Šƒ™ ¢”¥¤qŸ¯ÓõÅ—«ÂÐâõøøàÆáÒÚàĽÔöõ <#0aŠ„€|qm}™”Š£i9ö¼ËââÑÓñÞ¶ŸÛ'JEMHMZ\C %2.>e^5.`ÊJÏà°“Zã±wj‚™Ì&]`BF»Å£žDÉI'=AT^WVenii}zdKB=%ôñþðǾÎÀÞ2E†¸ˆtpspsn–—zucGZ[Lf£å!Çq]a]T_jn_D+3BG4óêÿÿüÿï̧yie{ˆ•”—|lv{†‚|u­M@h­É±¡œ§Ÿ§ŽzivpTe…¥•€£ºÊË©«•‚­§Ÿ‰ ¤Ìܨ”µäÿóËÄ¿Ùéñû +2cw_Ik‰‡xb@&2KbahlW;ïÒ¦‚‚Šˆ„›¬‹†õxpC/!%(öü;I*)HA$•§èÛq* -þäØæôÿ[§Æ¹Šx¿ø»Ó,îõ,:@c\Pm‰Šwp_ccPYrTæÑíôðÐÉÀµÇNb’®¶|\PJRn‚]SFSWJEwÄ38ÛˆRQWGACA;Ufe]cpV?C=5.83$ -ö÷Ø‘VZm–†‚umos]Yh^iŒƒM<K¶¿¦Žm†©~vg_Nc°ª•}—¸ëÑ®›–‡˜“yœÂ¢‘†£²¶¾°“œ÷øÙȼÍÙßãè'&+0WaQe€~rn{zXA$ 6941ëÓÃ¥wNPTpnrŽ¬Î€ÿ¶+  .òüøñ •6É5E1 Ù€BF^\<19d˜ä6NÛì!- ¨â8ïçý295.HjudVJMtwœìØNçÒÎõóÝÓ!p¶ÓÜ¿ŒN5@]jX‘tXQMRPLl–Æ­†eKF=?Xk[Yh~si}•”tcaQFMcaA Þ¯}u~uzŽŠv`cjXLScUSBQq_eeŽŽœvcn¢¹§†\YN^ziˆ´ÈÓÀ§ƒ}„™o¾Å¬›¯¤¦§`JìÝÌ­œÂó$33:>NngqkN@Uzmea_@);%"ôꞣ¦}m`lˆ”›¢Í‡‚2Õô33îÛÚíÊÓ¿ÎÀähøš&iO蜞‹œÓ݉KNlÁP•|PT\ ËsêNÝ¿Óâ!20QqgC9*9tÕjW›ãÂß%E8$kŸÁб}:04JQ-:ˆ}cX?JMT_‹wVH[XFIMg‚oiekjr™«–lZNO…ÉɆ8ÜÉ ‡wa`–¾oK\QRQZmqK?1a…]@k‚—‚otμ£€nY\‘‹tXa˜ÔÃ’ok‚}Œ·ÞÀŽ¦’‚…lKéãÜÕæü+12D/C[€‰dWYI&4`ˆ‚\;(3[q[+!⨰ÅÃÔ½­£Åæüö 8Už~4Øæ..⺞”‹mbr §– “«Š‰‡‘µøÊN¼„’ÙoÂÄ­‡MÑ¢T$ðɸ¶ÑûøøNÁC2’öÚ¶¯ )/,0HcU!!  (T^Q11M]bDIuŽ~phfwpVZfv—\g_U§"ܘf9çtrW}¦—eWUffnkeM<E`zTe‘ªŸŠ¶°¤œdhx•™Ž‰‚fuyž¶‚dn”’Tø̘–—§‚r—vÿ.*#6Hw^/ -YE1'"÷èð 'ì¹¥œ³µ¿¾ëéÝäòöäåçáðHŸsÿÃÇÇñúþÜœicfJAe”¦•ÐN‘ë=J*õ×Ãë#üÑLŒ–‹eS0ñææéÞðüܾ¤‡­Ñó²ÃÏÔõ2u~)ê̬ŽžÕͺ²½¸ÅÜÙÖæÍêöÜÎ×-íþ#64:j™’ycZdts]IXe`hvdSkpiÅ^~º›c:ê ”ˆn‰fTWliF_nYJhy™tc„Œ¦»–p§œ˜on˜‡¨v†ƒ€·¾Ÿrr}…8‹á車ˆ”ˆ|Šœ”6PbWVI5# ý*.6ª~fddfíéòóõáÕÙÜàÛ¿®Ýÿü÷ ôÖÄÁ® Ÿ»Ö÷!CUPWƒ‹»à븄cRsvot¡¸ª¤ð.Fg/éáäïýçÆäÿùñǯ¯À˜Ž™¢¬èÿÚμŸp`’¡”ˆ”³Á²ºÚåÛÇ©„”¤¡•\UiŽÌ˼ÙÒ´¥·Ûƹ«¬ÆÓÌ´Àíìèãÿ.@#  2O_LQ^UNV]dqs|Ô§}Þš“Œ]ÆÀ›€ŠWO\IA_}cZyšŽmFir{£­š•“œ•¥­ºšŠƒ•œ¯Ø«’e[\¡Ñ³ph€”˜·¼cV@AKD-0<çs¾Mã¥|]HPHX\B9.8Xi‚‡„ƒ‰¡™u€’€2%=So›Å²ŸÌZ”×^|i\[wŒWj›Š««´¯¼ÌÔ×Ë­§Æöýúͺª“Œ‚‹nQ]wp®ôáÀ±¡yV]|‰{z„‡˜¢€s”ÄÉ·¥””§¢l[|™ºÖ¬™˜€~‹©ÍÙÁœ¥¹Ï²®¸×Þ¹²ÏÛØÓïêÞÀÍö+AA=NT<Oz€q~Ÿê±Š@4£kv˜gÔª”‹^XTLXhu…yo…u[HQhƒ—¬•†™ª°£‹¦Ê· Œ†sw“‘ŒÍˆZx—U*~Å¥i_€›œ®ÏÌWD.):XO8&ï–GÕ'¤Jô²‚twr~‚ˆ}…ž±ËÄ°¨ª Œ§ÓÎÏØñÖ›ox¥ ¸³ºªŸÖ#GÄ.“Ù:AOf}V:c”Š‰–€„­ÀÉæçÚõõÙöëѵ–qVHVcrM/l~‰ËÞ«”†uq}Ž—™º¯°¶©}w¸ËϺœ“ž§¬¯¼Ä»¿¾ŠŒ‡¨Ùýз¸À±™ÌÓ¶ž£¯ÑºÇ¶™®Ûþ+1Ozƒ}ck£øy3L€¬lEV|†a,Ù§…–‚gf`UYvžˆYSv€†^jŒ §£’§·«Žo~«©•rrej‚zh¥ÆžgwTB“Ƕ~}…›¡¿ßÖYcfbD,ðvÚ{âj«zŠ€x{Œ„ƒ•¬¨¢Àƺ‘eWl‰«É¿­•–qxxoh\r¡§¬«°·Èô3u³C–Ü <_Jg¦”‡Š“±ËέÇÑÑÕÛÍÁ«¤§’Œe;L_liPWt„w Ì«£Ÿ˜Œz“’Œ´½¾ÙÊbÖÉÀ°¨¸¬»ìêѺ››Ã´¯¸›‰¢»äÿË“¢ºº‘®Ä±©‹o|–º±•“©ÛÜ×½ÝøòGqfCm¹ý8‹¥.¡:!-auˆy%Ø­”…pVmsYg~[MZz…}‡µ«¬¬µž–Œ‰Švoƒƒˆa]feqtk‘¼¬yo€t‹¾Ã£ŠŒ’¯Äá¼qsNöš-œî{Ní¥‚‚…Œ‰‹‰œÍД€®²—‚n€‡£ ¶²šp`djpLh”’‰¡·ª}•‘•Š’¶°ÃçO¿%Nm¾¯”†œ¶É±¡¦¯¿½Æ¡Œ~’¥¥ŠUKo‹¬®”zw––Š‡ ¢ŠlCkœ•“–«¶Ð t²³ºÂÉáËÁâ쮉«ÙÛÂÀ¨“¬ºÄ¢q’·¶§‚Š½Î¢s@IÐêÁ¹¾ÙÜ¿¼««°©Ð ,6^±ïûæ¾™H4KSV[{t>Ò—uflvxzw‚{_Kjœ«ª¼¤°¼¡Žˆ}€kez†€tko~x‰‹´Æ‘gx…tµÇ¨›Ž“¾Î´¼QÊB±¦”©³ šŠ„’‘‚~¨.Í~[€ºÁ v^pey”ª¢iVKXec|ºÑ¹°°ž|q…}ƒˆ¹šŒ~®óv*÷Caª¹‘y{‘Ÿ›Œ‡¯ÈØÕ¥xusz‚mlYUº³¨£²Ñͱ‚pD.Ušƒœ§ÁÖ¦¡¦«ÇÉÙëä¼ÑÀ¡ƒ¸Ð×» ¦‡š™ƒŠs„™²ºš‰™¤Ž€kqÃòûî·”¬©ª“ulpg¬ØØñ=…©ÅÎÑÐgY_e{–š|HÌ„m’ €pƒ…tjm¢ÁšŒ–˜“Ž†zu{zx_i„’Œox{”¡xµÂ¡v’„³µ ˜«— Ÿ¸Å {ømñ³gYa€º©““ ­¨ˆ€‚žÞõά›ˆž¶Ã·jR@Kr–­¹Ÿ^aŽ‚¡àíçâè°Ÿyn€ŸÈñ˦~ªîóVpˆ±£y[ax˜¬ÌàèÍ’~YPNspfFCz¦«ÍçÙ£~^<:l™”Ž‡”­¤¬ÌíÖ¹¼Ðäçëȳ®·™–¢¨¹ØŬ‘’Ÿ º¼­£Ÿ¦›x‚–¥Ã¶³ÜúÜظ‡{Ÿ†xUB6Jz‡q€žÍö<†²ÙëÖŽ~s… ¿Ñ›7Æ€ƒŒ„hkqeVerŽ‹‹„hUg†vr}ƒ–ysp‡…|”v–›t‚ž¯‘–§˜thš¹²­ª — ´C -Í‹evŒxjh„ª™¨§²¥Ž‘§¸²›‹šŸ…›¯¯}yxš¥•ž°¢”Ž¬¥yx´ñ&ä¯}mwˆ¥Óìåªw’tz`fk§Ÿ–ra”±«‰ªÖ÷Ü’†zfm‡xH1Yz¯Åéì¿‘fnŒyuŽ¿¿¼´µËÉÌÇùöáÜææ·˜„”°²¶©¡®Îо¯Ç³“Œ¨ÝìË­—x—¦µÀͼ¥œµÀʺŸ…”§©|R3!#?^IÿêD–áõÖz‰’¢Úè¸WÞ‡pnbcyvTBWcto…bP`bmx}‘‹juŒŠyu~‘’Ÿ¡¬£¬œŠ_UÄô—˜ˆ¢¯©okjml}Š}p|¡¿Ðǵ²§±¹¸¤ ®Â¿¢“’o…·ÓÆ·«®¾È´••¢¤±ÐÚÅÄØÍáúØm†Š¨È·©„¤4e(t]Tf•¥£—oo§¾ª‡‰£½ 謟¦ŠdMg{lUoy´Õæ¿°”€Ÿ¬ª“»ñõ ,KD(ìíع—•¾àðæÕÈÒæõÙн±Ž™°½¿¤¤§Ž•¦ª¥¶­§–¨«Ç¹»Ã–zŽ{g[>/Dij* Íe#ü"§rî7‚¥°|a|ÆóËtØvgdVmjPFOo…‚}t^Xb†‚Ž“•œxWep“šœ­¯–~vnO‚½Á¤Š„—¥°²‡z•||t“¢²¹®ººÂµÁϾ»´±²Œt|®ØÙÛÄ­çpx¯‡ž¤¿áG›PžÞГv‰——ž ’—øŽ çHVrd„¯¬usbNp¶Éż–›éôů¦”vZm›Ï¬ƒfm”ú°¨¯ÁÝØÊ¿Ý;1<moldKP]M7 -$-^RôÜçô÷ñãÏ°ž—““•—¡ž¨¥¢¥˜ª­±©™› ¦jakaXktmy…”q7ÙYçx3bàQ|Ý’U³Á¤lÀзdú–zk[„‹lY?R}ˆš‘{…€o~–ž¤ž’W:GŸªz}«¬‘†Œv”²®žzrr„žÆ¶š‰œž–“¹Ïج‘Ž–®¼ËÒÔѼÀ¢’  £½ÒàïõèÑÑSãÆ6Èœ—µí5¨ ½2᪠ÖÚ‚djThuÅR·#;E1FAl»Í°U<W„¬®·ËÜûïÙ³ž•Š†­Î«wR?KlS†²ÑÓò&1:9G+Fz’tU33Qd~ta_t{—Šƒ]çæñòîóá¿°®˜„¥´« ›¬¯ªÅÒµÑΤ„uehhw‰’Šxtu——™¨™uNú+Ök-22Gsùı氈˜¶ÁΞ%º€mz•ŽuHEq°¢’œŸ‘o`‹”š¶ž…W)O…”eª¹®¦˜˜ƒm’©„zy{„½Œ–Ÿ³«–Î^¼ZÂ|y‹•³ß Õ§¢™š¢½»±ÊÜåóóÓñN¥kÞɵ¼Þ&‹Ô€ÕÆÈðé…XekŽ¦^òF}‰{4<R§õêКhYuœŸ®íëáÅ¡Œ|dpZTgtzxCS¶ùý -%\†Še=Oˆ§‚XBIVi•²ž—‹ƒ}T&âø& þéÐÉ««ºÓÙÀÃÜÚÙãæÛÕÔ“spu‹Š•ÖåÙ±¢±Ÿ• ‡~kE#îž\Ìs*箧ÚÖןÒÔÚëèí¢Åž‡‘¡—~``†©µ’™«Ž‹oU…Ž‡» zZM[]tš¢·¾©¨§–tUgwŸ´›rp…¢ŸÄÉÆÜO '“ßbkƒ¬õ>=ï©“ ¦ž«¤›¬ÇÌÊ÷ûôèóÜÍÅ×ᲕÄéôÔ¬˜’ž÷pze‰¡µ´}GF}ÂÿÞ»¥¨­©ªÕ÷õÞÞÝ›|\P$)Gs«ÇÕÈj²8u¢§švPStŸ­}p…‹™£ž“p`SC8 ,úäíþö÷(ðøþðÑ·ÀÒÖ©wºÃØÿôÏ­¢§‘žª–‰{xW4àÕ¤‚øF?‚*4+¥ù ïáŸJ枪§Šcwš°ª‡š|jqdzw]†“Ž†pKO¢±®³¢Ÿ„hal“¨ÚÁ…|“›ÏÁ¾ÑäÏy.KÏzo}£Û)1‘Ÿ}~®×ˆ’ÆÝõö¶±qgõàͼŸ¢’˜Ûíœp~º#½x(T³ÌÔÂÀ·o'þF¤û ß»°¾´¦—¼ø'"íº‰TB>-0a½öüøË !B3=Rn¯Ç¾ymŒ©»²·ÈÆ»£›Ž…hG>?Q[?òê êÑËÝ+, !ÝÒÎÅ›–Áçᄃ±äüßÚ½©¤¹Á­¹¨š¤¯ m^QDS(•ô6”E4XÍcQK/Æ ïªgΰ¼¶€z¤½¦yi…k|qNJ>Vuhx‚_e˜ ¯¹¿¤…ƒf‡}…¿Ãðݪ™˜§µ¤­Ëí¯›ö°Ž‘w‚§Þý¿¡Ÿ˜Ÿ–’—ÀÔÑÊšcq›²Ç½­0òÚ³‘’‹¸È?TþŒs»R> yåÙ½»³¼¨‘ƒ?= àùÝ´››ºÂÊÃÅéË©‹[J<C<Šò.ý A,RR?8V‰–·ÛÄ©ÊØÒ¹º¿Ã¸²™y{wWOY„©—M ãÓõØåòïÂȻξ¹À»Æ´ÍýØÕÓ¾ÛàËÀÃÉÉÚÑÄ̪œ¡¤e`v{t^€˜Æp{§¨y墷°~ûýùÔ›NòÀ©º³µ”žxq‰–zUB6:Gxaƒ™Œ‹§°¥¥¨ „”ey–­äÒØç°—šÄ‰ƒ”ª´Ãú쩇ˆ‡—šÄó姥·¾¾©—ÄÏ»¨­«yVf|Ÿ”¶ÿEP Ì ŸŽ£ô÷Ãçd:9×ô  ò°’¦¡~wrc2B‘Ⱦ“™¯·¼Íê &ìðÜ—„˜¥™}q†¸óüCiWg‡y\Ls¹·§ÁóãÙáǼ§–™™²Õ£„m^€¨Ç¹‰> 7MINB åÅŧ“‹³ÑļÊÑÇôüâìùäÔÈÀ¸³Òæ×»ºŒyaXntt‚xIÚ(Æ¿ëÝŦ‘¼g0þý¹öâ¥m(ײ²¯È ’•©š}’“mO`d]T†¼²  ›¤®§€Ž¤ž“ˆ~§¯·³Èà·†±Äx{t{j…£ž¥Œ—°ÃÃÎãâúÄÈÆÔ½£²¼§œ¢§}iei¨¾ëÿëË»»®£Ã!V ÈÁý†Dþº2;§…‚}rQV{”„žÃÔë-t/îÓ¢‰ÅýÝÕÞö -^”Æ¿»—|Š¸ÑÑŽÀÌÄÀÌÈúÈÈäýôѹ°›ÃÑÐÜɈbSWiz‹~a,ûßßÇ£‘—™²´ž½Î¤¶ÕÞîÿ ñßþ°¦Îÿù¬ƒ…dYCZ†ŠŸˆc e‹úÞöá¡}·üm{¸€Ð±lÒµ¬¨¿£Ÿ¬®˜˜¢nM_pp¯Ë²£•‘‘™›…‰¥°ª˜‚“…†·åÀ ©”muxszvsŸ’£ÄÁµÅØÙ µ«®Ãñ‘¥ª£œyŠ› ™ª¡žªÃÞѳ¿ÖV•q̧@B“Þ!(8Gû¹‘…†›••ŠbPs~‡’ÃBqŸªŠ=Ç—¦J{xM$7l”˜‚trdu¤Øåدœ†§½ÄÔãüçíÝÆÚåíðóþÚžfiˆŽeLLõò϶¯ ¢”–¶È³™¸ÊÒÓ öâ´¶ºÂñÜ€\„ŽgPVz€—ˆzZÁYçáþÖ¬Œˆ~ž&P&¢£‘BÓ¯…¦ÊÁÎÁ®­¼¦w}‹—‹’³ª®¤•swŠ¤³³¥³§ƒ–š„¬ÒÁ…]U|v‘ ¢¡˜’’š—Ÿ¨µÙã¡–©£¸½”t†©¾«¬°¥¯¶ ª£Ÿ¬¾êЯÇh”kñŠ“%š­ÍÕö( ½—`Rjq|s]CVœÜÚáEm’‰”{5 öÄ¥ÖHnm_Y@1J‡m_Weohy¡»é÷Л{ž××ÔÛäòÕÖðäØß¿ÒÿÒ¥v|Ÿ­ª«|suU1ïìì̬‘|€ ¾¹œ’“³Àéõåů¯ÂëãÅ–x‘‡~g^j‘•|hV+žÐ Ýßá¼ v|‚œ£ -áõ‚µs* -íÂ¥Ñçæã×ÏØ×™ŠŸ´r†«‹œg]uª¥¬¹Æž©­lƒ§ªhID›‘ ±¦’†y—Œu}•¸íð̹¡€}—’vpp’³¨žž“š¿ÞáÔÅÊëéËÀvgþ©Òg=£Âªµ»²Ýýﺆf7?]|zd8A¯3lkk~mujx|U ÿ常Þú9]“®­€cr“—‡•»Ñ¸™š Ý) -ÑŽ ÙÜ´²ºÖÜÓëä¸Ã£§ÛæÆ©•‘´ÍÅ«¦¼¨†gaL?îÎɇ‚¯¥ŸŽ£Óß×µ¤±Ïöܦ¤¹™x|pUq„‰xn[:9 p¹Úý÷Í°­Ã̲¥õ»æØŠ²I ôÕäéðãé𳃟¼®‡w¤—“†a^d…¦¨˜™»Ñé¦ioœ»Y[Šˆˆƒ{tndq}{lv•®ÐéäË¡Œlt‡‚€na}‚‡‚š¡ÃíùͲ°áøغ¿ÿ$Äí¯„2œµº­·ÅÒÕåàØx|jVVTaoRšEˆ˜™¬®Št/ÝÕæÍÎÌì^ÎáÁ‰Š°Ç«®Ñùûá“­Øð -¹—´ÞĤ¼ÂÌÐÆĬ³¯©¼çÙ¸«š•–ÂäÑÝÌ¥”€ ›Qèâ¢x€¥™ˆŽ§¤Ô÷É¿¶Ìø% &Úæå©pkOWwvorwosiuÃ6 ÿñÕÓÜëôË—Ú›£ŸVaßÓÛÜæ  $꬈”­•€§¡wtoqj†¡®µ–¨ÓΆ…Ÿ…´Ë³“~jp{‚ypefxœ¢Ÿ¦¯¦ “}^a‹“Œ‚ƒ’hi}•¨¦®¸½Ë­ªÆÑι©¯ŠÚ«ž\¯À ¡¡½ÝÙ±¶¹¼ŸŒsZB9Rl†ÓbÚ¾¬¿ØçΤPﶿøãæ'xßù໕’œ¼ œ³àîПŠŸ³ÒñÊ”ŸÑóÜÓë°Ö×´±”°Ðã¾–Š…˜Äö 㶫©¬Á§h.Ńu™¼ª£Â»Äðéïäü H5ãŠuv_w‹„“ª¼ª¡} p¯.ôÜÙϾÅäâ’p«‡†’ýùλ¼·Àì *¹“…°Áž°–oyŸ©š—›™¥–ª·¯m±§ºÉÀ²”™œ™š“…mdzŽ§²µ©«‡ŒxmŒ×ö°of“¬¦„ƒŽŒ‹Ÿ§—Ÿªº¾ÇÆʺ¡¡¾~•bª´©†y´ÃÈr„‰r]i`Ucz‰¨×&ŒòÒ›Ÿµ¼¸£bùÀå4E. R’»¿´©«ž´½¸¾×Í¿ª°¬ÈÖÕÖÙÛ¸žÈÞîïÒŸ–ÇïÍ¡‰€²àʈ±Âíù÷õîÜ¿º¿Æ×íФl9êÇÐü õòòRW3äÛ?>Ζ{Ž¥®³·¹¹µ–PÑ"‚ -߸™“®Þ㹎›å{[XïñÆÂËßÄÑöØÁ¢Áɬ¡˜{”›œ‹wx”‹wv˜…šÝÆ®ÈÓ¼¤ľ®¤…ƒ‰|‰Ÿ¬¬±²¡£¥ª¦Ø!5Ýy¢†|–„§ÊäÏËÞ×É̾° ž¹</I¹¯Œ}r`fqÀª~`N<=grr~ªÖCmšäÅzz_Jcg?.NŒ„qf}‘°ªšy…™—§µµ°ÈËÍÄ´Àäé㾑¯ÂºÁÏßéÕÆ´¯Ø¸ ¬®¦ÆÏѨ‘¯ÚóôÓÑÉÇ·¸ÆçúôòÞǾ”ae^9$6Jn–{6 ûôñùúô 7 ø°‡q‚¹´Èƹ±˜s!¤ôaΪ‹–¸Ä¤š–•²EGIÒñÛêêüøÇäèíãÇÁ­¼Ò¬„ ™‰ƒŒlxs‡y„²£«çâ½ÑÌÒ®²º®…zˆ–—Š‘¢­¬£ ™žª«½æ'*ë«Šutj‡Œ›¦­Àí':=Gݼ£–Š™ê½Í–Îœpq„x``‘οŠSB3Ev•¡­Ú7g”µïÓvz>3_gŽ•¦ˆ•¤¶Éžjr—³¼°©¾ÖçîïؼÌóþܨ¢ÅÉÇÁÖñóÕéܪ–ÐÜÁ½ÝÕ¹Ÿ”›Ë×ÞßËÎÇÆÒóêÕÕÑí úâá·aby‹ ¢–POB$ïûæÕú 36?÷œ€‚‹²ºµš„—œwq¿AÖ–z˜¸«Ž~•ºU\ZíÜÙüïÎÏÊ᳡¦±ÄÁ‹‚Y[u~dv†¬¶¡¤ÃÄŽ©àÅÏãé¹® Ž†ˆŸ®“Ž•—¢–œ£¤Ÿ©¬ÁÝÓÊ¿®zt‚”£¦¯ ¾ò‚Õé©-ξ°©¢ºoz>Ÿ¾‘gd•ys£ÐÃm]Yq’§Éà8V~ŸÅÑ©‹¤>%kÀÊ¡ot}š§ÊáÒmv·ÎÖοÂ×ÜÎêå°´ßüÖ¥¶ÎÛ¬¨ÏõðøøÊÃÍÔäÓ¿ÃÀ—„w¹ùìÎìïÙÚäíǸÃúùæíÔœ““ºæåœpo}`ô ö8D4)äÌ«“šš–•±½ª]ðY¼Fú³…Ž£¥Ÿ–‘‡œÈ­Êšøùïíüñ¸±¿Äž§´ÁÚ§jl_dzlr|¢ÆÛÁ¨³©~m¾×ÉÓïÖ©¢—¤©³¶™ƒŒ‚’‘—ž–Ž‘”§´Êµš««¶°¨Ÿ ·95Ø¿;°­¬¯¹ }’¼À’ˆ”ˆ|‡¨ÑÖ¶•‘z{¦ \hH.ƒÄëÌÓèî«€§ïæ qŠ™É˺Çîþ¸’ÍȾ¼°¨¥Ê¯µÑ¾¸× ÿÉ·ºÀ¸½ÐàííüööúèÐѺ­››¤¹ÔèÿïÓìõâÌÆÁ©´ÛîÈÔÖ»—£¼Ý׺–¤«‹6 -5D2JhmK8;C,þ¸——¯³§Ÿ¥ŠizÏD×¥”›•†˜Œ£ ·ìݤúõíÙ³ÁÓѸº«§Æ³‘~ihxŠ°Ò㺘¢˜€gÓ»ÆØË”Ž„œ£–‘’ˆ‘Œ~~˜˜„t~nrr‰ª¾µ­²À½¹šœ›Ý´ÏE ¨w’ ÜÛmˆr¨×¾”‰hQ^ ×׺¢}v¤Vƒ~Y%ø eÀìëãñ-&#ê¢zœµÞåÖËàþå¸ÈÁ£‘ ˆ‹«´¡ ¯¹Íð÷àÐÎàôÞÒÏÕèñô鬩µ·¼Û÷ôäÎÛçÞÌÀª—ÃùßïÞÇ®Œ²©µ®šºÃ³vI:S>8V‚˜ofomQ0í÷¯¥’ˆ›¢{w®÷·Œ}o{‡˜ÀÍ»© ûâ—ÿöõûéÞýÊ¢—›¬ÕÓ¸‰Wi{ŒÈâƘ†š¶ž[e¨²˜Ãº||‚udzƒ“‰Œ„mxxy•œ–‡…™»Ã¯¯¯¾Ã²˜™ü[ï2¢ÖŠnmӺǨŠŒŸÈ¨pTrc5,i¯¼£Œ…½ 1RƒwR82MXq£²ÂÖùKr])îs˜¥½îßÍÂ×ÕÀÄÞ⺳¨´À²–‚¡ÃÎÕÊÓáÿçêëëÓ»»ÍÈÓÜÜʱ³Ä×÷ÙÙã"àÄ“¶ï æÁ²ÍéóõÚÅ£’Žž¹¸œ˜}ŽÁÓ Y@]K<.Xpffqklc3' Þ¤––œ¯¡|ôî⬃‹šŒˆ¥º¹¬®ÕÅwåÿñ âž‘˜¥ÖÝÜÅyl€€¤ÉÈ–kz§ mn¢ªz”¬{z~„{qr€Š¥»®ªŒo‚­äõÜÙꥣ¶»±ž«¾Å¬#Á8"˜¬Ö¤ƒO®¹±¢¢–i8 B{bHUŽ …›ê E‚¹¬‹Q-Xƒ¶ÓØì  íך}‡‚”Õæ³±¸°ªÛ  õáÔ×Ѽtƒ¾ÛÙÏÉÞ䯺¼¾Ðîïñúôôâû캺ÄëëÀ£™Ç ,ýéÞúÿᦥª¢Žªº®„‚~‡™¯®}MVa52(?U`nnl‹v@Ú¬¢‰Ž ¡‘$×ÛÇ¿²•ooŸµ­žõÙæ­,6 úê·¯¯¤ÄÙß⻋–r¨Ñ¨rZ’€d›Ža|µ›¨Ÿ”‡…œ¾ä Ê’™ÆùëË´ ‹‹‚‰²ÎÔ·¥(¢ÜdÏÇž¼¸ƒ¤²ª€qweT30‡‡gq”ŠŽµù:HOW‰ÎΧU$8<Q_œÙî±”’^ZŽ»Ç²²¿®¯Ö ïÙ¾ËáíƦ—”­ÙËÁ¬·îÞ¼¸ÕÙí#/$?.ô×ÛëÓµœ‹ƒ”ž¦µÄö ëëè  õ¼¼°—”om~–„¨ÀœqdkZILMRXjd[rtiL9鲂~” ¦FF@¿¸Á¾´”|Ž¶®³°Ÿž%&(àéêæï -ñÛ·£Æ´¹¼¨¥ohŽ´Ï‹Lmš†Hd’†•Ö¼´¸¡win{~±¯Â/²eƒÅÜ«“Ž…‡»¬«•‡é2M™£ÝwbVƒ¨©¤lX€‚aAsp‡§¦° y¢¬†Uz¾Êªy`qš—ƒ±ÃÁŸjP} {^U‰®°Á³¢½ÂºÔçäÖÈÏæäæ¹€†©×Ô¼¬ÏÝéÌÍàíý "öÊ·¸ŒŠxœ¨«´ÀÌÖØÚâê/<*Ͳ¨¨Œhlf\||š´ÇƯw^zvcTkD0CN[[?4)%"ù ‰˜¤°¥T‹yÌ›Ÿ«²¥®³¢¡ÌÞС´DP=Ñèâåþ&þÞ¶¦¶±¥¹¨”Šsœ´¤__…ŽLc·ÊØ件´«‰tgz‚¤>+LYŸ\où”–¢‹‰™Åú®•{Pˆc |¾Š„¬¦o­ª³ªœuPb‡²„q”¡ÂìÿO¬ÁË©zŠ½Ü༦¢®¡§Ç§Œ`SJ[†v™¬ÃÄ¢’¶ÉÁ³ÑíöçòÛÆÁ³¦¯Èéר³ÓãîòïúùíãÐÕÝîïòôáŵ¸¤œ¢˜Ž”»ÈåÝÛ¿²µÄãø2E.ýÕÇ·–Œ“yq„‰£Åº¬‘T4N^fO]`d\eZZW:/ãÒÉÄÀ±zÀ¸Ó‚w‚…‘²À×ÞÍÝÏ® Ï…‰VÉáÞðÿùÞº¨¶Ç¾Ë¾Š›wg|‘ƒW\~©~˜êøäÎÉ¥´ÑÈž}ywž&.Fe§Í˜DH©˜¦¬ºØ йž‚q‡½Ü©•v°±ö¯æÊÀ¯˜grý˜’ªÌìVŸËáõçű¦Öæà‰ˆ¤´_>8[`^k…“¢Ÿ¡­ˆ‹³Â©®Ü.è××ÂÁÅÈÕÍÝ·Ÿ°è ãäíñëÒËÍÓ«ÇáØËÄÁÌÃÄ°¤Œ–±¿øëƯ¯¨¶â (ùËÎǧœ¤Â©Žv†•šo+.F`WqŸ²¦s|rc@ENhXÙÄ»®‡ééâhJU`„çRT Ï¿¨¬À³Ø²dÅØñ õð¿³×äÞçÛ“–~f”Ž’xn•°¤èÈÃô±µÚÚØĶ™˜â—ÝbÁ¹(5£Ì昣¤ºâ5Ń–¢¿Ç·¡¨¬½‰Óßû’²¬›¦¬©“‚“±Ë±sah•â\ÆðÚØú -Û¿¥«Á´•š ›ŽnP8DUOE[qXDAkœ¤ÌÑÉÏôè¿ÈØÀ­ »Ì¾´¨®¸ÁîýÜßú ßÈ«Ÿ§ìá·­ÁÙ¿¿Ê´•|–¤Ûб¬ºÐï -éÝÍ¥¼µ…h“ò‡e]e`ht|nF>LUP¥À¹˜—€~Ž–…wfrp;á‘œ›‚ôå^EVbµ@ÝÍAÏ´«¹À§¨/ äˆÊ×ê þüêÐÚõÞÚ ktv‚£Ÿ±—’™§™x¤Êž˜$ؾÄÖÏÑÕ‚}â0ÛÑY,)=ŸŒ––«ö6*ËzËþÞ¥˜¨¡†þìÛnŽ‹ƒ¡¶´‘Ž­¼²zl—üj¸Í½¬Üóؾ¼ÇÏÒqxstmgcdU9 - =‚¡¶¹ÍÙÉ¿¬¸©”“­Óìɘ¢©œÅÖòÔ²½ûùü#õî캺ºÖß¼³È̸ª²Ì°g‘ËßÈÉÀ²Ó¿ÍÖ½¶“ˆx›Í·~K@Hdˆ«¦–„’‹€~•Š’™•¤²À¤gaom½Ÿ¥˜-$ -‚r‚»×HRðÂøæÆ´XB(§Æê!4ñãÛõáÜ°{z†‡®µ´²Ÿº®‘j…µš`覃Ž–˜©„ffx¬ÏÊè@q.Á¡~kuË-K霈¨Òàí˯¯¹—r-$†wo}©´²¤™¥·ÕÛƬŽ¬d‡¨®«ºÖ˯ÃÕÛÔFAZZOYWDOKüÙèú)h¦ÖÌ«´»©~¥­¡¨ßñѪ™ ð Ç´Æ߸£¥ŸÍèá×åÜ×ãàÒÌÔÇŸ—°¹–}ŒÆóð˪™ºØåÛÛ nuˆ–¥›m<A`›åè·˜˜fUiˆ¤½³›˜œ·¦}bxˆUÿ¸³GbT¼•©ÇÂœ©-·™ªåóLjÀjp_Î:V_A<!éÝÝØÔ±‡‰“£¶Å›‘‡¦½ jn©UÚ‘E>]n}}e`u¡¸Ûÿãœb^a_—-ŠAà´£¬¬ ˜Ž‘ÆÖ®™Eħˬ‘‚—È¿§—²ËÁ²“ Ë/z¹µ´ŸÃÉ¡†Ÿ´´fav|akgA;> ÌÈІÖæǦÂÜÌäîÚ©›¿ðûèض¯çöÚøâ©…‰‡jÅú áÓãòþäÆ—š¢‘ˆ¤ÙûìÙÀÁ×ÜÖÆ·nuoŽœ‰vu¦Ìbx^û¦…„zp´Âª„xy‚p’«“DÞª€ZÃÁæ—¦¨¬µí³š•¹Ô­‰d†Õ¬ÜÎC`OEK?*óÔÍáçÖ™±¢£©“‰y¤žw^«È«ÊöÍ”kYaw’€ŒŠŒœ²ÈÈ…UQ[•`ßʶ³„]kl¢èùôÈ̵2óÖ°šx{™³šwWZ}ŠŠ‡µf©Ä½©€‡¦¾©‹“¾Ã䓲ÁŽxl^$ýáêýNÈÒµ«Îï×ÈÜÌ¢–µçùóØÉʼÅÜÞÊ”uŠ °ÆúüîÿíÀÍöçÆ „¸Õå.;ûòåÉ®–|louqz›ÎæÍŸÐî"ºúÎmôº¦¯Ž‰‹¥¡~fjqg…tŠ¦¨q#Èx—‰˜˜‘¡ËÀ€’ °u§¸!)9ð6' - 6çéêâò¡~œŒt—Ÿ‰yyqˆlk­ä¬ëâ£to‹¸³œœ–ws’‡”›„•£óV} ɾ»¨˜vvõ5óØ -âþ—“¡ ‹_u¥‰xvŒ˜–ºû@€ÉÊÜÙ¾¡ÄË»•®ãÕ¾˜|¢¶—{iLÞ¿æB‡—µ’’šªÐçç÷ßµØã²–– ÓëÙ´œ­¹©§¼ÌÂÐÉÕ¾”¡ÝàŽ×ûö¶¸çóì稕°å÷Û÷÷ÜÐƳ‹VBCQdzzŠ½ò äü"eîÐ_÷ñÏ•hrŒ•€\DjŒ|y„os—³•eÊ–KD¡–«vtª›„‚¡ÕØ»š¼Î¿GNhý 6-ûôäʇTms]˜Â y¢‘|p_ìÜ•¾ôò¼ˆ€·¯ˆƒ’}k|ƒ’‚¨ö.LÜÇ·»½À·’Æ)A ÚÀ%ëcx’ž«yl™Á¹››«¹Ì.v¦æ üýܶ›Šq‰º½®eLliq_G=${¼Ýç½—®ÖôüÕ§§¤Á´³¸±Âѳ”y ÅͺÈÜË«†¬þáºÃãèòßíùýËÃÐä×¾Âõ궦²ªY4OrlžŽ€¦å -/II~«èÛ’7õÍÊ­†my‚zs`Rs¦¥‡‡—¸Å½•Dì¤DeUέ¯ªn^j´¿—ºø3Λ¡ÖÇÔ…Ç»û -þø øëÖß¹”KH~x’É·ƒ ®ŽwU}É阰ÿ2¯“ —…}ŒzšƒŠç[|1÷Ѻ¨ÈÎÔ¾®Òk*Ê–¦=N#kŸ¨«›‡_|££Šs|¢ªêO•­ÃäìäÝǬ•ierˆ¨¢qI?Rt‰˜uŠ|v™Ë½Ãáðô -åÌ̳’’…”¿²±àϹ°¬§š‡ž×ÓÏóáÄ̸ÑñÒÐâf.ØÉÔÛþÚÉÖÞÜÕÊ×篘¯©”k9Cs‡¨®¬Ž¡Éf“«¿õ®~1Á©¶³§—•œxy„ƒ|¥Æ¯Ž¦Â¼³¶™P­G™· ·™zcTiºÓ¹Ýr›1° ¥×þåáµ6ãõúñçϾÂÏé¿zu­¯œÃ¼”«‹xu~×ýÐåpëµ´‡„imsœ²ž•ÿ¾/Á““ˆ±ÊÊÅÅ |’ó|Z’Gšb ±·ž‹mSV{‚}‡•Âè%…ÇŲ¸Ä¾ÓéÚº³‘ft†«Îecwx‹‡Õä¹¼ÓÍËãïß櫼·˜¥¯Çͱ‰•…„»ãÊsu°è»Ä!æËïü ûæfZèÊƬÓÚ³¸ÓçÅ¥ÅÁ ±§‘Žt¿ÇÅ®®’k— ‰¾ù/'þǤrн² ¯³ºž–¡³““Ÿ¬’›ž¯¸­Y¶gí*ÅvTAhœÌÑË ¶JÀ¢ÎÞäݨòUŠêòóþêÛÍÕë ã°–¬º³ÃÍ®™›˜ž¹ÞûïçÞ£½n_z|dpyŽ‘žšìïó˹SDGr¨Æè.iœK¡Mk´‘˲°¾²”‰f}‡§¯¹í*iÂçÈ©¥£·Å­“‘ˆ‚pˆ²ÁǧŠ©ª ™¦³ÐùÚÐØèñа«­š¤¹Ä¸³§¨Ï­„q¥±¾ÕàÆœ¢±¦°V%ñß 6äÝÿõóÖ²ºÂºÖ̺«¶á©®ÝÜɾ~¬ÎÑ—Œfk–Ù$aNüâ»f˺²Êº¸¨«§²¬”œ’‹‰¸´z;Ò†$MOºb:F™Í¿ÄÝM\ÊÌâäßØÕ›MǼ -- ï)É¡ªÅµ¾Â–œ¹ºy{´É>ªúPÕrQadkw¢¹¼´±YͲ'‡‹68iŸ¼Ä•¨³šv§5¡¦²»Å»½²‰ƒ™›šÛ2u‘°´¹ºÑðÝ œsl•Ÿ µÊÏÆ­»Ÿ£ÇÔܾ逖ÆÕØØó廽Ùÿßѳr›¢˜—³µ»ÃÙÏÛʲÁËÐý(&âô%óõíѱ± ®ÝîÖ­¯Ùÿ'𯋔¯ä§ÎàÕ¸sSx¶ÑôŸ•ÅaÔßd_$þá’'ÏÛìÓ­¤¢›—’’‡­¼©ˆ~‘­¨ˆV¶_ z C4\¨ÙÛÓÑóåä×àÉèëêÑ׶ä2†#GH7 ñ -êÂÏÊ­§·¡œ°¸ ld“Á~Ô+°ÿ‹tmq†£´­®ªf!íò.uIe~ž­¨êyåñ“­ˆ´cyY°Œr‚˜¥¬ Šœ¯²¹þa‘‰¨áèëçìÕ¥ zk|ŽŽ®¶ÀÉÀ¸ª¸Èà¼yzŽ˜¸Ð×ëãîÓÔÐéè;°_Wœ¯¬µ©¥§Îûó³¯áÖäçÿèí̶À½v]‰…†¤àäËÜ#í‘ŠŽ¦œ¯š…£ž¸­]]šáÞßáà:Ð&+4/%ó÷ ÃDò÷ﻀ†~|‰…”˜¥­¬±†oz§ÜÊŽ>Ò„ûêÚUFW™Óäèäæ·ƒŸ©»îþß¿º×ô®ðÔÿ-A+ëÆä&ߺ¸ªœ°¤ ž©µ–u“Ê©à²)8™£±ªŸ”Š„|•IÙx–~sq„Ž¥áTµÁ$ʉ¡j–h–vWjnhm{€žËä*Jž~¥ÛîòÔ«¤Ÿ§jn‚´±µ¥Œ‘Ÿ»²zgyµÑÜ» ²¸¸±ÈÊÉǯš«ˆo…˜ÁØË©µÛð×±ÏåõâåâÐѤ†‹k{¥Á¥ŸÔòâÚÏÕÓžy‡˜¤Âµ¨·È¢Ž½Ñ²Øô3¥ bf[) õó›(öÔˆx••• ¨˜‡y’©Š|…¢ÔáŸTÎwI¿«ªC@^¬ÚÜ͸„RU‘¶÷Ú³ÆÞá:DSÉìíÌÝ'ꨱÛ¦œ£ ±ÕΦ°Ù‰ªžƒG±²·©—s[Kv3Wžëý´žv}‘½×ó,EC'ù›®—Ð_Œ“shk|uo„•§Ë"Idƒ‡v‹¯ëïÒÉËÅÁ¦ƒ|Ž†vtŠ“j…˜§…ux–ÑÇ¥¯¨‘Œ¸Ì㶱ÀÇÂÌèнªÄÒÌÄÕÑÙúþóÏÃ×ϵ¨–©ËïÄ‘x©ÏôôûßÁìýÒ£œ¨´Â¯€™»áóÐĸ£­ÉôãÁ¿öTäQŠ‹g$ëõœFè“ŽÃÛàÒ²§ˆigyŠ‡‚‚{f\÷†sQ`3„CEc“šƒdn]‰¯íýê×ÑȮբÚ¦èû éÔõ嵧¤©¿²©ªÉÓ­—¹š»[Åzp÷‚¢½½®ƒ\FFrÄc™GÿÚ¶š–œ—¥­²Ïîêûì±ËÅ‘‡¦¥‡˜aQ[i bbfƒŸœ´ÖàáíÔÀ¹~g|˜–†–˜¥‡Œ“¬ž“„‘µ¬¿ÜÑ«¤¸ÔÜåßÚÙÞäöõ ìñ±¬À°ÅÖÏË´Ãس–…v•ÄÖÍ·£ä(@ìÎÅÌ­”¡¼·Å­‹ev¦½üïÀ®š¾ÅÕçÍÙ6Çÿ>`zo4.6F05üœJúâö¹ŠjXdYWiŠyYFQ1à³…Y¥T0Gq„lKar‚˜²ÜëéçÏ¿¡žgcÚíãÒà粦ÏëÓϾ­–œ”Šv–©õÄZäý …™³§†cYGXe–ñ ðþÚ¸˜…~Žš¢»¹Ÿ£ÆÍÛí¤’°¸’£ˆT2,Sˆ ~„‹”•†—¸½ÛóÓ¯·ˆ{ŒÌɧ ¢¥“—Ÿƒ‡¶ÄËÉäÕÌij¸Ï çÖÏÉÎíâ¿„^v»ËÖðçÁŸ²ÎÛÅ·Œ‚¨¼ë!34ûÚǦ– ¸¼²«ÅÖÓ±Žw¨ÈäÒ¡˜©°ªÁš­®­3M8$Vo[:>@L98;#ÂhN4-# ¼i;32(/Qd~~‡§ŸqҨZ‰E"Hq‰{V`~¨°œ°´¼Íïò¾œÑ×üˆÜÿîäàöÄË,ѽ¯§~z†vqvxŒ’ªp‰‚pmWPhkm«ôïéùéÄ°Ÿ•¢˜¦±‡¯Þ!(Gͪ™”tupK5+k …­³ž|z{“­ªËéòÕÒµ¦¾É»¶š”¨·“{Ž˜Ðéܵ‘“³Êå×ÐÓãüãèј‹‹u}³¾êÑ´©ÍãÞÜ™‰«Ãý !)ð¿ËÒ¸”˜¶ÂÂÀø #ê±¥¡ÎÞÉ–†“³¡’ƒ„Ë+Ï[•kPNbB.;*2IN/úÆv[6,$×…`- 5?hž¹Á¥Šk¿r¤6<)=]¸ëž}™¬ÄÇœ‚ƒÁõÚ§ÆPbJ²æûúÞôöÎÎ <7öÙÎŬ‰|gjq ïÔ˜€{„Œ‚|ƒ¯ÕÚÎÙÐÍÓÆÊÁį¸ÈµŒªÊ0-H¶ŸihiYh”Œfb‘å,‹¸¼®•š›´Ù×ÕíïÜ£¯Ç²¼»ª¨’€”­ÌÍÚɬŠ~¶ßáéåÕʾ«ÍßÅ ‰˜±»°©§¨¹àËž³ÆæØÑÝÊ·»Æâìì "èìë±og–Áäþî¾” œ¨¥£“”¯¨±žœû|ìi´Ÿ_:RN3 -BEᬃyZ/Ï—M/#! Jswqz…™”„p"ÀW„*5(HÊPF×­ÁØÍͯ}„³­ÕõÙ©´Ø£ÈÛöîý Ûã&÷ì­Œyv‡kmpŸ¶¬—›žª œŒŸ¾ÍßóÁ¹¹ ¤¹ËÍ»®¥¨¬—€»4KEž©Što…‚§ž”¶L‹­¹Ç¹Ç×áêË¼Ö õªi¡¼¶À¼°{p‘³ºµ¯®®âèÙÏØËËãÔÔزÇÖž­Ãà㿱®Á½ÓÎœ{·çûìãçì¼ÄÅÁºø#,(ëªig«ÏÚâÅàè«‹_v¬³¤‹§»Æ¶îxß2rœŒA.Sn9ðó E$ñ«¦vMù¸˜k.(/0Ii›qyxŠ›w<ÜUg,K$lÊpˆÊæóãñ⟗¾¶«Å¾¦x¡(6XÖ$'åéúÿóʹ¢‘‚›¡®­Íϸ« ¬«¤¤§¬¥¶¹ÁãÚƬ§•ž›«¿¤”‘¢¼Æ°¤Ë|ƒS™³¨£Ž”“Žyw­?o“‰¦²ÉøýäìÕàÛôóõ¬‹°Æ»¦•|qv‘“¨²»Éõ÷ÊÁÍÁÒÝͮƱ´«´šÎèýÌžš™ªËêߺž§´îéÏòìÆÁȸ¬ß ,,àXl©¿ÔâÑŠy™£Œ€Ž¨šz¥Î åü)ewgSDIqkò8R²§°¶}h]':YN?Rhƒ‚¤£q8ø€tM—HQ…#o¹µÆçõ аµ¢©¶Æ r‘çÈþÄò,L`(ÚäÌÅé &÷ß²¢•­¾Â¨»Ëᕘ“¡¸µŒ¦æûÜ£•††Ž•³£™˜µÜêàÉØœ¯et—¯ŽdkÅ>Žº¾¨ À¾îéÂÎøúÇ·Ëƪ µÂ¥‹šª´´Ã¾¸ÖØÄÐÚ¯™¶Ê­­œ“¢§¡ÁÓèñÆvUj†žËÓÜÕ¡˜ÌøÊËýðÉ×àÆÀÆæëû¿{b‘ÏõágUm†¤ÉÚÔÀ¦•}¾ lÈåèAO?T>=Zj9CRö¨ƒ•»zì†YBZn†˜uQ`ucf—£Ÿ·£Šf@¢|QªafØ늑¥Ô)õÜÐÔßÝ»x›/IIÑôCM âçõÖÞíª•}‰{¤ž¨¼¿¢‘‘Œ™¨ºÅ²¦®×Ò½¥‘“‹‡Ÿ¿¸«ŸŸ¿åòù˜µm…š± ™¶ÅÄļäD¨ÐÇÆà ÝÆäƶºÖݶŽ¥ÎÔÍ´®§™°ÖåæßÖãÑßɵ°Ä§›žÁ¥›¢³¨§ÀÖѳ¶®¦¢nwœ›µÌÆÝÍŸ§ë ï")Û³ÒåÚÅÃàø϶•°âÍ|f‰o‘ Ä" íÂœ“¢ý;‡ËÒÞ)2GE÷G=3R;󼙥ÅkÝXcƒ¤¯hVosfj•«­£•…QýˆlB¶‚…Âй¯’sq‹Îú$2KIË¡}“ìÃð´áÑ;"ëøïÑÆÜá÷ñœ†…t«¹ª «¯¢ž¥±ÁÃÇ© ¨³ÀÎϹ›Ž¨ÀÀ¹¦¥Ç÷òðÿÎу™š¦›˜­Øïöör… ±¸ÎÕ¶¤©™‚ˆ¡²¸¼õþêÎÉηªÛä×®¤ž¬©”Ÿ¿ÀƘ™³ÍÓÑ¿¬­»ÆÉĉ©Ô㺪²¤¢³ÂÿäÌì(Ìž¯ÐúëÆáðȹ碲½ˆŒ™´ÄÈç óçÌ­Ø\°äê/'>#õÂó>B6@9áÕÔ¶TðȈs€ŒŽ{nX^^e„˜§|s†‹7Ô[zN¤zžÔ¼ˆ ¢uoš²ÊÑ5™€C'&Ê£©†‹sÚõÁÊüØÔæäØÙç "½ŠŠ¦¿ÉÆ·¦¯¶Ÿ›˜¥©¢¤­¨±Ÿª·ÂÍË£žš²ÆËËÎÉ¿’¢ðÝó®~œ£Ž—Š™Èé1Šy•›¢”—††™¥¨ ÍõóÒÕʾÃÝÔÀ ¹È¶hv{Ž¢ºíÛȽ¾×éàþ²¬¯©’ ÅÕîÕ¬³©¹ÓÕúõâí íÆåçÙÜÑÝÿáÉÍÐȺ¡ˆ¸ÔÓ°¡¬™£²¿ÝæßÓÎñK¦×'L\<þò Üä_Z@7C,àǵ‹;(¥vrop‡“xw‹€{QI‘ŸV#ÙrĪ“°£¡–‘’Ÿ£§Š•L.äÎJàÔ›  ß±ÈÒ´½é$ -ù鸨»´´¶ª°¦¤“„„…~yŠ¶Ã¨Š«½µŠ‘¬ÈÈèÒ«›¦ˆ~ÚÇô™¿ œÀœn^mœÖr‹”¯¿¨ÀË£–»ÚÛÆÑö À³°¶®ÄÒ¾žˆªŠˆy€„›¬ÁÝü¯°ÜâÌȵ§˜ ¿ÌľÌÅÒܺ’¥®¥ÂÍèæíçßÚÐÇî=!¾±¾Ê»§¨Åйž¡ÃãÁ®§£­¢©ËèѼ¡15EA<òÊñIwq<5¹¬nB:¬¤°’‰¬­•…iftih„\-ö‘ įdhwŽ|š´ÀÃ¥˜}‰Òßì -ÞáäA88Þö»ØÀÎ-' ÷C'ëÕŒ“¡¶É¶µaSaqw|{‰µÍ§ƒ|ŸÓèÐËØ̼§|y—«¨Ô»ÔzÁË¿ }`e‚µáh•ºÑØ̶̪»äÝÙÂí´¤£ÀÖ¨Ryq~±ÜññèؽŸËüà ”’¤Òöþðë𶋎‘ri’™±äóãáëÙÍØøëɇy¦ÅÒÆ´ÔÙ“jg“ÈÚΞ­¥•³äþàíó6ÌKWõù&@5ö+!8^`/1&ݸ˜aJø³ÆóÊ–£”ƒw~gZUtˆ“šYÏnðÛÊlSj€³Ò´°}gˆoy­ꉙº«°ÈÖúÂÉ·!øç÷àÛæð"#IIñ¡‰–³ÜíÒT:;RzŸ®¨½¡’‘šÌ æç ’›¢¯ÏÐÊݬÚs«­€fWoŽÙ.Rm‡­ÊÕÔ¯³Å§®ÖÚËÇî÷´ƒ¤¸»Ð‘Xe¡œž¼®›«ÆØÍÁ¡¦£ÈÀ˜¨¼Ðüþô½xVd¨¼Æ»ËöúèÚÙÚíýîìÎÎÒÀšÄ÷éÁ‹”§‘‰‡¥«Ñɧ”™·ã -nÉ(:ðþOg`>$#>IG.ñ±¦²²–Cö½ÈíÀƒ}{”€dj†zs|QÓgêøý™Œ‡›£–ª¶½²‘€Ïơ̂ܛ·¬˜ÁÚÙP<R4üãÚõ=)&1RY+ùv_u¥†DçŽXGXq¤³µ§š«³Çî Õ²Ÿ³ºÀÍÒ˼t¦‰æ{f{–’‡v}¦PU`–›¦ËÑÂËÔ°›¦±•¶ë諾ƾ²”s€µ¾À»»´½¶±±§¥¡¨$êçÁÐùûÿÎ_h“ª×áóöæøöÿßÖ ! ôÅ·ß±±¼Ÿeq}‹ŸËÂÄ¥°¨£Ž³ÕÂå /~Ä &,(5L7&1 J]0å“š¢©£¡3èй»¨¡•¬²¥˜‡”›“šN˜ÃÀ¶´´š«ª«ª˜—]XÅbçÐÜâнÌËÆô‘À¿ñ!$éïÿ870=D=óds]|üûxñ(׬†lmˆ¢¦¤°¹ÄÛü Æ—¿Ä—ž»¿‰q†€È~t‚˜ž’ƒŽ¦]qtŽ™ ÉÐè鲚¦ÄËÁßÏǼ›ƒ³šµÑåç÷Ø­žŒ‘ªµ¯Œ…ÖüðÆÆöøøÍ‘“®¤šÄìÙæäêîæÿýé,CL1÷™¬µ‡xlXUr†’­ÓêÒ¼©²®¸¯Áǹ¼ç/pÃ+$'/+ -3FE$:A䪦}rvD÷ß©ž½Øµ–Œ©¬¬•¨§¢¥Q)*àF( ®¼Ð·ž‚ŠªåÞšs2q\4èüúܶ¢¥»µ Uß -'' üöîÞQIDG1픓—¸…Ô*&ôƱ”‘Œ‚ƒŒª±ÝT|!¼•„‡Ž™¡¸Â¤””-£“¿­·ª‡‚…÷ƒÄ§Ÿ±•ÅéñëàËÂßñãòÿ³Ÿ«—½áʱ¬ºÔéôÈŽer˜¾ÔÆŸ|‚Ü2øïäÉÑæÕ¸Œp}ÒæиáÞÇÎÿ$&@ ™R_ewT;n³¾¿Ìâ统|” °¢Ÿµ²Êÿ*rÝ$ 04SZ^L "ºšÇÂZ*=?9Ä¡™¹Ï«–~sxŽœ¤–”šŸQ$Aa<û…¥Ã¨{Ñ0+³’7oò6ìóúÞʱž¥Ä¿¢Iœ®øêôïËöDRK=.ôìÒ½ìÓò֧賮³©‚m^eqx¼ògé(Ì®ŸÉÕÑÈ­¥ž'“°ïݧyu‰³ö}ÁÁ¿Ü¼€šÐéìàÚÒ×ÙÍ¿ÐÔ¡y¸äóÙÔ²¥Êé±zl¯åÖ¾¨‚ªÔÌܪ©è3'í½|ozËǵ¼îðÖÂùó*æ–Ë%4ЈgylUW±é¬©¦È¢gf†Œ}h~¢Æ·Åîoã19#ó@l}T(èâòÑî°=#çµ›˜›º­ww{^ctŽ¡¡¡_8;û^Nmzª°‹’šã.2ø¹‘¾i ʳµ¼´´±ÈÌ׶Û;ÛâýòíæÑÏ 4>;õíÞÇÀìÄÁµ²°Œv]ct¼ÎhT­öþ¾ÉÖÑü -üÍ‘“$^a¦‹atˆ”žé`ÀÒÊѾ™®ÒéêÓdz»”˸¨ÞØÑß¿‡dƒ£Ü°ww…¶°«¾¯Ÿ”«ÐòÑÆŬËü2"èLJ€ršÅ´šËØîÙ¯ªÊ§ÈÞ Ð€_sloª×³„_t›™ ”~Vd‘”¡«ÒVADH6*4 ûQrH èß6êÞÅ;ýÿ彚”¤–y˜«³«³­nHF{¥£Š~\2íFK1|hvz}´Ø è·±ÛçÝÉžºÀÈÐëíÀg…‡èõãÌÝÛÓ×â4D"ò¨ºæòæÌÆÛÒ±Œ‡‰‡¥ÒÙøN‰')»±ÇÐÏ´Õ]Ç‘|ÜõÛL6E`}‹¦å+z½âÏÐõ¹µÀàÞíÙÓÕÆ­¥Ê¹~zŒ°Õõê´|Š–£¯Åü·œ“ ²²­¾ÊÕáçèãÕãø3)뢛­¯È§zÁ@1éÛ¾‰~ÇÚÁª©ìæa}™¹Ï´…Ž”ªÄÕÃ|RyŒ‹§»BYMFBHYI!ûè<( ÿ &óÅšdóÜÄ·¼¸Á±«‘••­À©_16Zƒ˜|€P(Õ(³sPT”Ïú!Ü¥“…u—©¾±œšª½ÀÖó¿ÓÉöÕÞÌÕèçÛØéñ*S8!¬¥¦ª£°¾´ÉâשœŽ¢—ŸÂدm}¥ɘÀÜÀ˜’5äz ¼Zgf{ŒœË%`”½âàæêåƬ«ÀØÜüõåÌŸž£žn­ÀÝéÜÀŸ˜¤¹ßìƲ©¢Œ~°ÛÐÎÜ*ÏÉÌã3bÈ­½”®’`œ$ôÖ²„ª½Ðª³Ñ¸…€•”±ÇÙìÉ°ž ¦¶¾Ÿ‚¡Í½»ÿqãD;>*  üîÉñ*AZvBïî´gjZôÐéöñÍϸ¬–„…•¥hA7@Uzšœ†F¾Í¯ÂmNW‘»ò,ñnƒ˜ ¾ºÄ·£žž©·þúϬAUØëìí×ííèñ'aZ<¤±Çª¡°»Ÿ•¥ŸŸ“‰”¸Ì&±&Óù¨ÃÞî­Ó$A㤜‡–™Ów¨¨¬¸¨ q”¶ÉÑÕ˼Åĵ¿ÍÓåöùÒ°©¶½¿‘—¯ÂÕÜïÜÜ–TY‹­ÂÄŸ°Çª•ˆ“±´½óþó°¸û!þÐǨ`]un‘Y!ßÚ;¤¥Â´¬©Ð䱋¦¶¸±´Ð»ª¡œÅå´¬Þ÷ðáRÊýÿ , ɽÏðÛ÷=bsj'æô8æqD2ñí÷Õ­³¤…m~Œ‘¢g6MfWŠ¼¯‡A -業‘Ýxu†”½þ*´{†˜™­ºÀ«•ž¨¤½ó)éØ´Ê´ ø íÍÃäíò @5ÿ쪴¬˜“ƒ`Qer‚¨¡Žƒ•¨Á÷X˜FíñêÙ̪Š… ¾À‘zy‘ΛÏi’¢¯½‘»ÖÎÊÂàè  éÜÿñѽÃØÅÆÙðˤ¡»âáàΗ˜fYz¤•‰‡~‰­Ã™“œ¿ÃÓÍп©úaD%Ì’ª—XX¹ñ>ƒ:îëéàÈÍÖÙµºËÙ³ ·²—•ˆ˜—“ºÖãöèÕÇèïÝï|ãݾÑòô»Éý0;;.>ùíôÝ{+'ðÛŸ¡›ni”yp‘jXrvhÊM Ó¨b’~ ôº¤vwˆí7^ ¦ˆ‰}®»·¦²»«¨Ú/È»±»1hµ÷äÁÐéóÿ -!öõ‹€„{sdWJOeŽ¡Ëßѹ³š©Ò  ìíÊ£ˆ—x\~Šv}dq–¿Pm/Xb{Ã@±ÙñõáÅËì÷üþüØ‹|±åäÏß  -·—Ÿ¶É¾Ä·¬”ŒŒ‘y^w¢ÏøÛš§ÑÚÔéôáÜbY9Ú°½Ù¤ƒ R^YáäÕÃÕûûßʽ¤¨ž“Œ‡‹x~µÛå´ÂÈÛé -ˆ¶§ž¯í'æñ-JE-#1öðͤl3)>?ëм ‰…‹|MYs„†–Œ»ÚpìÁpPDí檣‘Ê0¥ÁeÕ—qy¢¯ÍŶš©WAÓ¾½£ßÌ7êúçÁ¾Ñèíóø #‡snYUZ|—››­¿ÛóìÚË­´ÔÝÆ·¶®£ykhqpŽ¤šeTmw£.xŠ¡·[¾ÂØôñDZ¾¯«ÊãÐ˺¥‘¥ÈÙï4!Ó«˜™­ÇÍÖ²¦¤‘…xjÎìôÒ¨°ÙÞà -ôÍÒú øõ¿¯Ô,g\7 -ÌÐÆ¿ÑÕÝξ½Á¥›”…†}v{¤ÃÕó±l§ÅÙù8s¯´²ÖôéåÛ1#ÿÿ., â뻌§jrpLE5Ϙ…ƒr&$€©¬ÄÒɶ[ïDzjõ »àÿýû«m„î¡xYUˆ²ÄȽ©ªæ`Õ²µÎ½Çeš¨íöÁ¹ÄÌÓÛ÷)1™†…|ƒ£ÞèÕ³·Öøé¼³©µ£«¨´£ŒŒ§°¢‹’ªÃèÔŠd]s¤”Íå -üŒÆÂÛëÕű«£•¾œŠ¬ÆѬÆþøóÜ·•¥Ò¼¶Í°¥««¨‘œšÓäÕîñßÖØØòêáÄŸŸá 5`9 æøYoC襕˜Ÿ“Ž ³Ë˽ŸŒ¨‰–ŽŒÙ÷Òƒ}«‚JžÃÅ!‘ÖÕêí2ùÓÆàØô -ÜÊó0&Ø”­¼´ƒ„c>&ù´•Ÿ‹e5nµÃÌɬn·°»±7°×ûå$9OSw^·{oaˆ¡ËìöÙÎ$È)ñ+³ÒÔÁøù?ÜÞ°´¯Ãñÿ›–¤«©Ëñöçä×êÙ­µª—¢½Ç®ˆ„ÝÀ¢¦Àï ÿܾ§¯õÚØlÄèÚÇËÝåËȶ¯–¦™†“±Ë»Óüñ»²®ÉÎíØ£´¯Ÿž«­«œ­©ÂÙ»¸½ÃÂд¼ÉÑõ¶.!QXJf|ARgTÅ•x…Œ¥®¯£µ¾žµÁ­ºÎ¢pvÂÖ±‚€Ÿó*ôýêþþɼÞõæÌÊö Ýá >;!$ñ»´¯¤pPI<误­£”ƒaG€Å½¸ÁŒ7ã±ÇîðrS.©rr¦×âéaƒQUd¹“ˆ|†¢Þ+K è#ªî¦ª¶¦¤Z®p»½µÊý47“”œ ™¡ÔöüëîêéÌœµÉ¾¬·¼Ç³š›á æꛫÇ!SN%î¯Ã‘£<i†Ñ.E†ÌÛÔÕܸ««¡•š®œ «¯ª‚˜°›œ¹Ò×ßâüߎ¬¨š“œÊ½³š¹ˆŽº÷ø૳ؽÔÝÛ6N=C`dtŒy‘mXôš€{†ÓÛТ ¥ˆÁÙ»±¹§¨¯«¶¼¿°—Ú<Pu·åáÚ*þß´›Ì⪲Р- -ø!æÄ©˜uG  -ýæ·Œ‰—¢¤ ‘˜ ˆ_2$ñÏe~[Å—rŽ¡¿õZæânÇ°°¥¥¨Ý#8ùÐÞ &ÒŠŒ™‘oä•Ãà8On]J'+q{‰Ž…–±ËÕÀÃÍ×ÖÁ¬¡ š®³®ª¸Ìî⼩ºÌõ7'믠€ÅHQÊ-JÁßȼ»¤©µ¤²ÆÀ™¦¤›†‘ÊçêÏÏ·¦Œ¥Á­Àº¿·†¡°ª©u‘¼»½Ùùà»ÂÏ°²¾æ#FHiŽ€sT]rj>ð⑃µ±Œg]…¨¨Àž¯ÊȽ¿’z¯¨“¯Û`|žÒðàîëÕ·ËùçÎÜñÿüðéù -ëÖ¥›^1÷âÏÇé÷Ý¡{sˆ©ÆÜ¡Œc`]cbJ3(ù„ñ)PåÖª’“ºø39 ðîÝÎÇÀËÒºµèêdzµ›§ÄËœ~}Šw™{É¡Ê•ÓÇe)0;……“‘¤­®¼Â¶·¯¸¯¬™§½Ë×êþéÛÍÉ×Ü÷ôÅãïɱśéwUo¹.~’£Ê´£³©¤¾ÆÝâìå·”ŠºËúØ¢•ƒwÎàÐÐÀîyw‰ ŸŸÌ×ÔÊßÒŽÆéŦ¹ÉPd{ˆŽu9"L`8öÁŸ”‡y˜kk•ª¶âÙÁ¶UJZikš×/a|“ÇìÎà0ûüõ û(A÷¸³Õ <:Í´žj1ÖÓ¨ÊÝ府‰Š¬ÎÓµ’bd„”€T"Ôm¥±ÙÞÍ¢•­ß뵨¾ÁúÅÉŶ –“™»²¬Ä¼|œœ˜+„ŽÍÏO>ó“O*L˜™¡·¯œ•—œ«ª±®¢«ÁÈ˾ÅÖçÑÓâäáçõôõëÒ§«£¥ÀÔo±WB`¾fº®´Àµ¡£®·ÍÊÔëì 烄½¼®¬„˜”‘ƒšÌÇÁijµº’p{Åë°®§Õåï±ÁäÊ™œ¼D]iˆ¥–bRUI#䯒{¤§—’©›‰|‹¢Ääô -Þ›†{^M[˜È GRP‹°ÒØʸ¼ü$ñ74Òá Uc<Ù´†0ýëÀÊËâóôúᾬ©¶±³¸–‰•¦‚3ûëÒg}tâÀÅÑÀ¥µ¿à㽧“Ÿ¾Ê¹¥ €yºÉ½³¶¥Ž’¥´›²ïþ8¿â‡‹Jè„RY¿ÏàÚ͹«–œ ²¯³¼§¹ÎèëÙÕÆÁÉâÛéçÛ’ž§“ ß|¦Ul¥”âѵÁƬ©ÀÔÕÂÂåüñÓÁ‡b}‘¤½¹°}o£ÖÝ»¢¶¡±©”ŒŽ¯Ã “„šÁÏ¡ª»ÅÔîËËÛ[`v¸×­‡g[8 éÁ¡†i’°ž¬¹ËÃÌèÞ§¹ÃÞ/k ¿§Š¿öìÁ¦ÅÎ$ææ6C)3FI60ô̾döÙîúßÑΪ¡°³Ä¡Œ”U äܵ?YzíÕÎÄÍ·ÑàÛ¦‡ˆ•ºÉÃÀ¢¥€„¹ÀÅ®¬ÄÞ¿°ÉÕ§œ¤dÁ¨ Ä•«Ž.ÂUAÉüá²¢Ÿš«ÅÚáÛèѺÓÜÚǸȿ­ÈÑÏÝòüÉ•€–‡€œ"++Ÿ±´ÞhÌÉœ²ÏƾºÎäϼÇÆà׫’j`…¡¹É§¢¹ßçîÅ{ŠŠs€’p€œ·’˜¶ÈЫšÁ»ç$# ô1>i¥¹—€_tyå˦‚m‡™£±ÖÖ¾î笫ÆÝÛâ GVW€²ðúðõ õ ë ô+@45  hNðæÿëÙ®I FbA%+ÿþ÷ÿÿ᪥µ£º¼˜~ÄÐÃ&z-Ϫ±À®ºÛÅ¢‘—µâѽ¹ÊƸŒ‹ÂäÞƧÈú -5 ½”=PÀZo¹´WòIç:nFá½±º¶ºÎêòÞξ´¦œœ¡£·³­¯ÃËÅìëƈ›Ÿ¨ðº÷šÃ°‰Ÿ •ÔŶÒÑÈ™§ÔÜ¡•—¬ºƒ]\y«·½¼Å¾ÑÈŽ°ªekxow‰ˆªÂ®˜¥·¯±­·¹Ôàû·«à4Z‹±ÒÜÓ´Eà•ª³­»Ð½äîöÔ××½å TÄâå!>7÷6%âÿìàï'( EKó*,Þêþþî²`&U~‡W èèð äÁ¶»±´§²˜dº±›G³½E$ïħµ««É¿ “—äÊ›Â÷ûÔ«¸ãå៲%DmN㜚éÂëTѦcõ¦hù/n%èãÔܯ¯µÒËÇÓº ©¬º¾°Ÿ“–¶´³ÈÓÅ»»Àµ¢ªî„XS´¡‚ˆ¤ éæÍÈæÜ»š¤¢~|…”usnœ¾ÛòôâƧ˜€uŒwge•¬›œ±®š…››®ÑóÕÍ̾Ÿ²³§ªá#d·ãúäªgÛj†ÍÖêåÍÆÏóèùêÌXi¶á 0KZ]dF/  êÛÜØñ%=S<:Eùáõ ÷  ìÎÆ…BN†º•=ÿæóñçÏ£–Á¦~u”¥˜Ž8É¢mESòó¾±¹º ¨ËªŠ ò1Ãrº ×®Á"ï”z×H|ªxóÂît¦x ²oXò·„³ÛñÎååÔÀ§£ÈàËÖÀäößÒÒɪ ©°¥­ö    걜ÁDµž†“éD«ðïÑ××Þ¡^CWXh‚myª¿Ë°Ÿ²ÁÞÕÀ©›†meyae¶Ò¿Âº ¨·ÜÑÜÿ௙«”–•¼íA¸ýí ˆi÷‚Š±ÏßÙ»¾½ñ>™ÌºÅº¸Ùû+YfRRC(-.óÉÊõ÷×ìIyˆ^UH7ñÌ %2%2åÍ«~l§ïùzñÿïÍ£‚œš~]lƒ‹…Hঃǽë®ÏáŬ¦ÂÓÑ·¦§Ð8p(›U«?†9ÇÃ-‚•Q×¤Ô -0y¯@ô×2²Â_-ðÏË·Ý âÓîäÝÍÀ»ËÞÌÄòþÚ²µ¶Æ¸©¡¹ä$PðÇ£˜„¿”­ˆ¬±øAœÒν§˜•…bIZj‰›½¼²Àŵš°®§£–§ƒ]bw“ª¹·¶°•–¯Üòã¾ËíÑ ‘‰|w}ag«_ø!ï½kBm­±ÏÊÐè#1hÓ2bµfà›¾òíë-9 -ý þëÇÂ%!d}L(257CM[[Z6Ù¤™Õò×=õýãç‘‹}|€t`c^:õÌgg/¢·ÔÁ“—µôÜÏÔàñdÆeÁ|ûË:ÁêÔBݦ8øðöìTrEûå¾Âˆ–iKÍÑþæ ×Øàçã߸½³ÄÂÂÇÌ´¨‰±ÞÚØëú/5Ç´Œ€|…x‚!,4ºµ—Ü\š—†ž´¼§xjŠ¥«ÔéÁ±²³•vŸ²´»Ä³ƒBb©Ëß”Œ¥•ƒ…Œ—·¸¼• Ë˸¡‹ˆrv_JN“" Ûä˧L,T&Ñö'b«¼´õ7MO`0¤•ð(èöóïæìÚ¹Äüé -$(Q[YN@GND41Ghkm|X"úΗ‘®Ñ¥‡pH ùÓµ­}r|Ÿ¸Ž~b_5üñCúꣳÈɨ°Á ÕÓýÁ%ƒÅ‘7Eš*æ2»ÿÃWêæÁÊü6Mê`7*$?òÀÊ%$ ÖÔÓϬœŽ££°’~r‚„}‘§ÊåíýéÈÐîÁ†wmqŠŒ¡œæ¸ä¬©v™è;‡¸£³ÊëÞÚ¶¼Ï± ª±¶´¾ž‹fr€±»Ìξžih¯æÔ y‰sh‚ƒ}‚‹£§Ÿ¢À¸Ï°©¤ŽrVY€Ù_´ÄÚºoa^>D|ƒ¬æ1, ãѸ‹‹× êãù%îîÌœ¡á<ìÐã.00IeonmXGI?:Gvyki_(Ø¢Ÿ©©’t~{>Øѯ³Ÿyt¯Ç¼œ„{EïëÊÚƒÞÓ×Á×ÚѦ¤3Â|áÇ,ôU¼²I1ï5ùQxPûÕÎÚÐÎä -/)èâGíÏe&ìÙ5ûã¡š„dp–œ¤ˆxvu„™ª¸¨¶ÆÎǧ”°æÐ’ˆ™Ÿ›­ÍÎËYkF‹sœøAœËÐÐØÕ×ðÝÈ»‘gf‚¡¸¾´ˆlo}ž¦¹¹Íº‚G€´³‡ekU^‰£›ƒ|yš¤‰¬ÖçϹ²›ˆˆ…B[*¾Øµ¬‡fu¨ÈÙð1IR%â®j82G£ÚçëÓÒòþå´¬êòçÑÒýChoflmcnaK0!H?$'+Tn2ÐœœŠ{•Ž\1ÔɾºÇ§¡ª¦£”€Gì×W9%ÏÜÝÆÒÚ®ƒ¤‚r-â9ÒÕiñRªÀjõÞÕñÚ×ÁÈ×âØ»ÊöàÑ3÷¸©ý¸~!ã%ÔÚзŽ}­³®˜}{¡ ªÎÙ¸†€“›˜ˆ“Ìà—¡—ªÝåÊ" ⃨«ùGÅÛе§¡Ä«wWhW‰¯­»²¡‡Ž•˜ ‰²£[K‡~tbTKc“‡gux¨¼Ìèë̱¥£’|ˆr=1»‚ æΰÂÐãþ0ôÆž‹O,Bk§áúüöýöþÏÀ¹±èëÍ{‚WZ]GNKA0/N_Nꦱ‚ˆˆ|> -ÝÁ¾É÷ö¾™„‡z’‹[(¡º„Ç«¿¯Åæ豈³±°n`ÉýÏ´z|B -λ·—œ£ÔðêÎÖÖ¹Öø ïÀÉ™t½Æ‘-äü´É½¢†‹¬­§“pxž¸ØÎ漢x’ˆy~—·»œŸŽŒ½ßÞÒÛd¦ Ã+p”²«ª–‰vcu‚hf€¶»À³«Œª¨š¥|hi‰ª]Uq{„rK6Lƒw£²ÖõìÀ¦Áɬ—ePgB9x8à ÷ÓÏÝù"7"躞‡‘–y‚µÈñ&üóðêåÍÈÀ˜­ÞìÃÝ+&4M?%9*EfdÏ}' ìÃÁúàøûÍ›“‘ldx_ÍzV$¦¾¾£Å - öÎðj{ ÷,„·ª5ã¾Á¯·½£ŠšÃÛØÆÏÛÛûîöï£àkVa§‰0Áʦ×Øν²¹˜‚{Ž…œ¯Åä—Ÿ¹ÄŸ…}fOXy™¥ÁƬž»àקt…0|„Å?Kw¥°¤¤›Š~¦ƒtˆŒ ¡§´§¨§m’¦[f[stf`K¶°XT•·èÍÂÏËÓ»¡tpE&W¾ëáßÏÏæ"<?ðÓ§†ž´­×!';¾´¦ÌÈйªÂÜêüéÌð ö ÷é÷ü9SH4?b‘ ¬w‘¬º /DøòÉ›™˜fO_Uò°8þ·¾Á­à[mù'o–RÞCLAО›¸Å̲š›ª·ÃÏÎØðÿßÎׯ¶;3/M›“¯¤Êá⿲ÌâäлÂÒÁ««»°Œ‡›ÒñݨoLFƒÎáÒᾸÎýÍyL]âéÞiŽ©êù'ŒÒª±¾“vŠs”¾±¡±±½¦Œtt‰y©Ë¢”Šwbnm[Zj} çÑ~>9j®ØÜìúÎÆ´¨l?23/©S›¹ÙàÒöêæ%窄–™¬Ôö9]Mîç︓¤š­ÉÙöÊÑßïùÛðßÐÄÍàÝéí3]R/^ð2Ç™g˜Çï;M2íÔ×Òœ€qvwN5Ü‹Í­ìÔ³¢¹ÿì4õº§ôUZ+üÛòêÐÚÔ®¿Þ͹¥¤³²ÛåùÝâæú௑¢ûçò¦Ù›~²×ŤžÃ`@ëâê×»ÀÁ¼¬ÁÍèúåµ€bcªàãÀ¡žÎîœgi“ê¿Òz}rŸîaËïÈ …«´™ƒ‘€¾°¡¦ rdyk†¿À¡¦ƒ§¥—€tz‹|œÝ¹iUe•®²ÏôþÒƾ–}aRW+ó¦gÁ¿¾Ù!ÿ7ÛªrU†ÛÏõ0UWNÜØûÞž€¤ÇØþïóêãüüâʵÁáþçñ 3WR); ý½¿ÁÅ5,*31øÝÆ·¨•wp’8üsbHÙ•©Èz“ŒíàÝÂÒü#/% -àÄÈ¿ÐÖáÂœ•—Ðö#L&ïÚ’lhb¨ƒ áGCŽn‘’Ÿ¨ÁʆyÿÏáæ͸¨« ¨»ÄÞ‡•µ²£¡¥Ò3#ÉŽ‘¦Æän`-MCu¶ÊΦ{”¹«xŠ{v•¨|WX~…°Ó®zo ­§šÅʲ®°ŸŒfYHƒ»ÈÅÕÞ÷ßÌ«rYM]?þº´(¸ÒÃËúÖÃ’š ©êø>> ïõÕÁ®ß"DV=.óC߸Рêþöüåç /ó -FF6 û×dú úñ-4Ù¿©€yx‰©§W %aÌÑÀØ:3óðööáêõ÷ݼ¹¶˜ŸºÓíΡŽ©ÞG—b+*(í¢}ZNk\©‹²šŸL•ªÉÇÁáÓº¶¾¢„{}‚—…‘½Ê¾»©†„‰·Ù :?ûéÏ¡žîÌÇRqÐfž»Âª“‰iaP<e¨¡tet–·²Ÿ›“”¹×Á›ÈÈÀµ¯™[>RTE€Íûóÿõݾº˜uVY)ÖÎç ½JÎ×Ä×âÛµ¢›®ÒÓÓ-6Cñ÷Ú þë÷÷_V5ÿ /ß­î&ð  -ùì5N%ë6E9òæߨc=?üÏ½Ò é¿¨˜¨œz›µã¥8ö,ù¥¾¯ÛA­sH85>ïÖÓØУ‹”–˜²¿Øýü½ ³Ïõ&\D,-($ 䮃YkÛp6¼èÄA¢²Ñͯ«¯¸¯~n€Ÿyƒ‡–Œƒ†‡ªÈϸ•qZw² 1*%ò«‰n³}¢v»ÂÉÝ%„°³»‡wpqO8G—ž”’½Òŧ€z¡Þåß¹†¡ŸŠ‘]>DnŒÄÙÐØää -Þ“{X#2N²r­Ôé鹘Ñßì 4 ÿûîãA÷Þù-׿ÈÈ =èÜÌâ 4AdYäM\*ó¤e^WÇ œ¸Ûî붑ª¿±›´ÀÀ{   kñŒ”¾v¹)¼Ù*W$ôÄ«ÅåÅ~avŒ¡¶ÄÅ×÷áÌÀ±¯Éàäáê 1CLI´‚sÃ×6Õ“4gÉËЯ‡‘yp†¼Ùѽª¦¡“‡“ŒŒ¨´‹swŒÒÌ®ÒìÍ™’Ã_zrŸÊ<[†{zzaD,H€·ÖÔæ䦅©ºÑÕµ’•šqq‹‰šŸ’†•©ª¦Æâ /"öȹÇK`†Èú1¨!Ú¤Ô -͸ÎÕòô]Q0ùúß¹µ¾ymÜ08þõ$FRVU) -i€?VPð„ll)ß›Œ£¸ÊÐͦ”¤¨›rv¹‘hOÃꃨ®Îø*[a¡ã’ä´¨½ØïÒ‰cŒ²ÑÝϼÁÊÊÌ£¡¤¨Œ‘§Ó-em-ߦ«™öm6e\•ÇÆ´¥|ƒ˜©­ÑîÿøèÖ¹œšœš‰ˆzs~Š™¶âìõçÎÃÌÌÉÇÒ·ÁÐ+&Ÿ¥˜—ÃP‚™‰‚†€eVæÀ¨¿¦¨Â¶ž¡p]oot‰v{µæÛÍÍ»“q{‚©Äû$7&èÛì×ÓØçܵ¸ÂåTÌàŒ«ã üûû áÈÚæ#a-TQR"úÙ©š¡}‘ö#&"(7<B3$'9=LUnnSA-¸QQ.ß¹³¥¯¨´ºœšw\u­·e,íl„cÈÉÕé(J].ß””¤ìèÇ©¬›˜­Ç×ØкÂų¡©©¥„’˜Êï9ÕŸ|™n½¿~¨À«¡ªª¯ž—ÈéìËÁöýͬŸªœ¢®ž€Š¬ÊÓéóâÒæìÁ¯¥˜•²´²ºÔt˜\‡š©™¹Ii†›‹|Š†ƒ™½¼–†¨¬¸«Žƒˆ™‹jWj™¼êëÄ©¶¸œ}\] æJO*Áœ¹Ãâã÷æÏ©ß&±°…“³ÂÒçþ47 #0>&-Dh3ÊРקœ»©°Ü=;÷ JJõ()+^{TB4ú˜+"秮ڵœª£””²¹Ä½¤ž”¶æÏ–xµÑ+¿œ™·Õùò÷åòÌ‡Ä Ò¼Å×Κ˜²ÌãϺƽ«¦¾Î· ­®—«¹Óè䶞”œJ“æx“õüšŠ˜ÃÍ·‘¡Êº¼Áð0.÷ÃÄ·²­³³»ØêðÇÄÉÚϘ¤¾Ê¸¯Œmez#&„Ÿ¹ÅÇù,=s­––’ˆ«®†u™ ©vk“²¶¿Ÿƒ’ˆg}}…›šu™´§’seŒ¹ä*?A÷ª²Õâùìá’‡«RŒ¥šš×ñ÷ëõ<ý(`/ 9?=òí¶àñ¼Ï¼³ý0JL$ûâÎöü%+<ow<( í¹n/ãµ´Ö¹ª³½±·ËËÐëùíÉÅÖ¸A–¾ÆçП}—×ÿ à°ÃêÝĵÆ᤬ÆîõºŸŸ¾ÔÆÄŽ¢¡½ÞÒ¨¹·œŸ­Çɬ¡¨£?y´yRs‘¦¶´ª­¢¨¢ÅUR@줎™Ÿ¶ÄÁ¿Ðë䎰ª´® Îþõ­iRNpçÔÌi©ÃÖÕäõö6‘°º«°Í¤}uÊ͵k8s¢›©¶À¬ª‹\@Ng”¯š½ÑÒ¼°„yv¹*¼Ÿ¬ãîÙÀ”`;_ÌQ”£œª«Ã8_D'7$!JCȇ®ß/òïñÇ·L(ñâìãñêô SHAg_;ò};%À›µ§ ²Ê¼¶ÐØâÔÆÜÛåìÛÁF¹ñÌø½áÐôØ•”ÐëÙ³¡µËßÊžš®µ¸º´«Ÿ‘ŸÄ—ž Š—ª¸¹ ·Àª6µ¾$~èÎßÑ¿·Åö³Âî 4é´ll|˜³ÍÐÇ"WÚѧ˜¢¨®áñ‡v|qt†ÎvTŠ»Ëêìç9€µËåáÍ“¥ª½Þ¸–zRd•œ‹ªÓÈ™ˆpQvºÉÑ×ØÙIJ¡b.&h÷"æÇÅÆÎÒ¯™pJIì|²¼­¨¿ï ,./=cX<-ih1üòð•“á 4çóí¸5­¿óõàÜîF/&Xl? þí¢´ešº´’¢ÐÓ½½ÎÕÎÁ´¶ÝðÝ‚\4dyÜóÖÑÒÉÑÌ°™¼"öѪ‹š¬µÊѺ£¦®¯ ŸœŽzk£™Š“¤£•§µ¸°®«-¬Çƒ™0Ü úÞÍÓÔʽ³¾Êþ©±¢Ÿ”—©¯Ôánûð|º‹±Ç\8÷Ψ£yjƒ²§f.“¼ÅÖù*Ql®ÑÕ´›ž–„“¥”§±Š íÝÇÒ¢‹¨¡Œ±áÜáåêÈnSÞ äÅȶš¡™¦‡\ ˆµÑë)*)*,XkM_•^àíõÞÃ`=ñ'ÿÌùàÀÑÔúùî×ê 4<!ïôþøª±eD‘ÓÒ§œÄãÝ»´Á×ÏÇÜæâÉV¿Ò‰•\qÌ0>,Ť’Ÿ‹’Èõ쬠©¯©ÓéÒ©£‘‚w†œ[d §‡§©’ˆ¹¹¨™ÃgÍÓJ܈À6ùàÒЮ˜©À¨ƒ—Èíàukj¬@&…`ù®¡·Ö< ñÙÅ™nm“´¢ž`–½àíTn©Èµ¥§’€w‰·á ýÖìI*Ø»»¬šÁÌ¡­ÅµµÖù»ì -5ƒ·àüØ‹‡‘“‚¥†‡ØlÖåIS91#ÿý -BF-!1\b: ø $óÛ<w+ÂÍ ùÕëùöíáÁ²Ú"þúõèëÛ³¦â -Í`ápy¢ p˜“¯å³À×èèýÊhì#‚“‰Â#[€k/Õ™–˜Š€¾ÌÓÚÛ¿°¿Ñ¾°‘‰z{‡¥¡ˆ~˜ •„Š¤‰”¾Ô©’ݼî»aÿ‡åš)Û¼§œ‰–‡yw˜Ú¦K;|½rRz¿ǵ³¼°«ÑíñæëÞÜѲŒ‰”¸!›ŸÅõJs• ©±«”˜–†ˆ°ô *îóÒ±¹ÄƳÁÉ« ¼’¸ÔÎm_i”ÙãâŽMJ™|kZg¹)§"! ÿçúøç;<">B2"$ôåë奵ùã¥ÙççäûΫÑþ$;ýƼ¡š‹‘Å×›@áevwacOvrr•ÉÒ×Úù ¡:'4§œ¨Åìužk8ëÞÕ˜›˜¸ÔÂÕßåÁ£¹³´•oiv¦ª´­˜Š¥¯Œ‡§³›•½Î¯ßßøŽ7‘,Å:WЦ¥Œwahrso™àåž{–¼bBGs߬¥ª‘‘¥ÌѼÁ·¬¶™¦±¦•ÀCZ_¢¦Ù9QŒ›±£¯ ™š­±ÒóéÔÌn‡·ñÜÖɽÁ¯Œ§¬Ÿµ¹¿Ç¹~Yn²¬‚NC˜©zZ(9‹Ò\û2âÀÑÃÆÚ Nb`%õ07ïïò¼®·Çö$ãšÚ ͯÖè´ÞÛé ÿ¬¢x^yžœ£¤\î‹YGaxTJ^v–§•|¤½××ÛéùÛu½‡VÂÇ¥È -k·”@(ìÜÛÅ£§®”“ŸªÎùöÇ–‘™£³ªm]l„¯Æ·²«·ßâÍÌÍ騾´–À½ú‡æNË‘ƒH³{‚iPTm‹—™È98íš™´:÷PÒ©Œ}›ÄÈ¿Á±œˆyk¯É²¤Ÿ³ê–¥r“º :PŽÂ±¢ž‘’§¹ÊØ̸˜\eÁÆÚªŸ­»©‚¤¤z¬ÛáÚš`PVuiR5#Ey@;B|,‘öïÈÙíþ.Ec]=(èòøóïæ 饹Èã9²ÒïÀÄñ-çãØÏÜÜ£md†²­¤\ü™vETaicp­¥°±’„ “œ¹Ì×á® í®çÍÙß~¡~ àæïÆ©ÄëÕ¬°¤€…—ÑúôÇ•Š¤¨›yio|¤è÷Īž²N4õÙ¾¦¯¯¥¨yáœÅý"jÕU ’X`r{fuˆ«¾Á½é)Cõœvtò³Ó=ꙕ’ž¥´¶¦“}†“¸æñǧ¢°Ô õ™•ð*O”Ê¿“ˆ˜’ž¯¸ ™›º¾†‘¤‰ntqy~¥’ÈøÞÍ¡fXLRLAEWVyw6l–ÔQ}¨ê þ+:ù!3*öëèãéñWs,òóìÄÂÒÏÖ ùÓÓÙå03 ìà LJ†¬¬^ø¼•‚_rxa`fk¿¸–xh€Ž‰‚•·êßO"Îæ²ç+Kxgý¿¹Ï¦¢°àü̸­˜Ÿ¯µßó綢–¨žˆwxp‰± Ú©£³‡‹S"ÛË°§£ž˜+›w¦Õó@Ïvo}—–‹–¦´¯œ‹™Ö(®mhþÃÌ&º¬¦¢wux™¢±¥£• ¼ä÷ɨ¦«µÚ€]µÄA²°’‰–¬vh}’†‚Ÿ¡¢˜u…Œrfvzpˆ“–¾ôë½»wZ@GHOif[€¥…´à^˜¾ü(9ôòÒè íçÜ -K€‰C×ÍîÔÆÝöÖ×êÓàâ7694ÿàßèìÖo°|y•‚Y^YQEQP’ Œ{cd²²°Îàžž4ƒÅ^M1÷̼û¸²¢¡ÖøúñÕ¿Ä®ÎýöѦ› žwq“¬¡¯Ý´Õ.E=Óº©–™§ŠúskÈëØ›T­^z•œ’~~†ˆŠ€y—÷-Úp±‚3ͳŽŸ’yjz«Å½©š›Àöüí»¯¦¹ßê‹¤Ø +]‘¡¡¦®{E[‹•ƒœ‘Ž…±œ¡¦Ä••±»ÍÝඤ–tI,A^b^Wr’¾¤­ T´Ëâ0=åÊÈáßMH)ã=ow:-ÛÆ éú-ÖÏñðáó'#5⯋ Ú· -We‘|`DA?6 #l£”¡“°½æüä“Æ“a£ƒËE3ßÆÄÊ̺Ç̱²ÌôøøùèÑ°¿ñçÅ£ƒ‡˜–›´ªÁýóðÒž©¿Ó {˜™¤¢b^ƒ²Ú²¥ZŠ`q‘œŒ‚z{€¬…hÊ;U.‹ä󙈅ˆw\Xc‰®˜“ŽÃù⺢y•·ÉRZ*€©Îø5}Ž‚Œ¦¥o[Š“˜…”©‹††—½º§·Û˱Ùí¬ˆvŒºÑ–c6J\^]tz•´¦¾$xÑìæ7<â¿®ËÞoP  Ò ?hd$)êÔÞî )¸Íüû&49öíûࡃwC:-AG…ŸŒ†vXC>HD%8zž¼ÝâÔÎÓö¾Ô—{ϵ±£Ì!üÁ¯ÀÊà×Þðà­¿ÑÈÀÉÿѥĭ—zo¤°¡ŒšºÄõäîîÀ‘’•Šƒu”«Å¾es”¾È¨|ƒÓu‚‡€‰v‡˜®½t]}ÌgÓâïyw°Ô…{hYj^i–°¤ˆ€‰ˆ¼äó×Øر€‡š«Ø½E€Áã3qynp˜³zly–’•‘‰–¬ÀÖ¿ÈÞئÛð­ou¡äöªsW">stjŸÄÎõZ¾èõ%äôã¿Á͉*øè+\e[8 ηÙÕɸ ¥«Ú42K%Þ“‘‡}: ÷ˤ‘„…{icebNJKK_q†‚ÔêÒϹ‚„!ÌmÔåýâ«œÕÿäÖ§³Íêúúúß½²¼®—”Äô+ §‚›š{¤Ã§’¯ÉåúÐËÏÞ¹¥«°’}~œØôÆ OŸ·½É»|Å„\nv|´Ä·š‡™Å9®ÎË0ž‡‰¦¼¿ÃÀµ¢”s‚Ÿ´È¸½´¯–›±áw-ãY”Ã*{•¤®˜®§uwŽ„j‰–”¬Úøÿײª·†½»Ÿ˜ªÂÚZC.1SXHqÍÖüY¦×ØìÕ¿ü ÌÀê;Yú2buWTF õÔÑß¹Šes—«ùK@! Ò~N<YpHãÖ·|e¹Û¿„b=0BapaYTo–…y©åʦ‚vGBè -Ýÿ÷ä±ÀâÞÈÅÃÒîåÞÜãàâΫ¦ ¤Ü>5ÎŽz”Ÿ ©·«¨®»ÀÑÛÈ›™ÄàåÙÉÁy¨Öæ¯ -]Á˳ÁÕš P„^Tw‹Ž—µ¶“…•Ž’§*\}±Ùû«´ÏØÌÍÍ»œ§Œ…¢ws†sŽ ’š²¸Çûa ó}Ê -f˜ÂÍŸ•›wLc`^xxŽ•Öÿј‡}Š…^¯ª¶«©¾‡[dQ0757H‰ìô"u¾ÍíÕÈÇ9ôø+õî.ci\lxføíÏÃÁyGaªŒ%©oì†7$F: Û»qj{—³·¼‘W(9Rqg_{„•– À×ÈŸjM*x]PÞèÀ»ÃëÜÉÙæÞáéË¿ÇËÈæûݵŸ ÑFq¹ ˜š³Â·³´¡´¾·²¢œ‰•¸ÇÈÖË¿¢‹ªÒÎ’uÍÕŸÛ¨+p³Šro†ƒƒ„q†¦ÆÄ©£E¾éÿ“Ô¯ÄßÝÙű¸­®º¹¶¥‰Œny‘š­·²Â̸«ÆñN?D¸í)`«³“z’‰dH\‚’—§½ÀºªuuvrcT^‹¬£± £›}|Ÿo8#<vóÞ”Û¹Ô²Öë 0/ýøåðàÅå-j`Yx†Pøõí©¢¬jF•Ò¼¿)gÞ4IOêðþß²‹tw}¬¶§­¶I8CI\avoŽ‚€”‘ »Ì¿„HÛ¨€ëÇ¢œ”ÀöðåíâÉ´¢¥¸áúõçÐȨ¥îe¼ŽA÷²¥­¸Çž°¤¬´ª¥¡©¯¿½Ãĸ¢†’¤Å¢‘ -~ÃàÈîY5·õµ|knhuŽ¥Ï þã4¹ -Ø:·½ÅÚéÚ·µÁÍÓ -&«ƒ³ÃÏÈÀÅØθÃàÑðŽšVšé<•–‰ˆœne‡¿¸µ²—†m^U`vmHl€¹½‚{†„‰¹¶ª‚=  iœáÿ¼Õ|µÖìê %ÁɾÁÁöWg`]Œe"÷囃„v•ÅÑdz­±!ªÍÛéÒÅÚÑ’^€«ÂÈ­›†ŠwIO^pYWmŒ…uo‡œ™«Â»‡öÊšä¼¹ž¥Ç9A?0ßËǸ¬}žÙüúÞÁ³¦Ÿê -¥&ؽ©ÉÓÝŬ˜œ µ»Á³¹ª¯Ä½¸¹¿¤›•œ•ˆ w­îØð õOõ²†zuƒ¯¿·ºããµ›àS¦¶€!ØÙÔµÈÛäô C…µçÖ@ ûÁ­´ËÖǶ¬µÕÈûÉ».š–œz‰uy”ÆǦƒv~[/Oxwm\ilt‡^ep–±¿Ê Œ8 ?–·½ÉãèU—»õ  - NEé×Ì*+@H[{‘m)Ýk\…¾ÌƘhÔÌž—ÌÉ¢·ÊtSˆÃÆȤyH]|m|nr…¨tEX™¸¸¼œy¶ÞµÀ·¸Ø$3D28Õ£»ÂÀ¯¥±ð"Jü¡’€t½a3XÈªÈʽ£Ž’­µÀÊÖÒ¿®·­µÆ¶˜š¡ ’øS¡ÖäþÉôÔ½¦¸¸°‘¨°š•ˆ–€¹Óÿ(õÛ±}©Uqƒ}€•Áø\*³Ž/dzÀéðáÏ·ÁÒØ¿Î~ÄPŽxtl€ž›®²‹hZ^s…’—†haKFA‡xg‡ƒ“£¯ÀÃ…Cï `¦¢¦àù1ÁýôúçB+  Zs01o£¤Y©€lr°µ¬‘FÞ‡Þé·‹¡‹¥|p‚ˆ¯Þ­y_f™¥´‰y|¯Ÿ{UT˜ª£«uðÜåž¿ÊßNoC ü㲜ÁöìïÄø›ÝG¯vc_›2 K¤ᶦ˜¡­¹¼µ¯„Š†žÁÙðÜı¢°À¸²• £»¥øA̽լęϤ°˜”“€‡}Ž’¦½_*Q¿)ãȯ·ÓE`ýúvÿü©‚F÷ä%' Ò»Ëóñ´‡ý¤q¯AZu¦–ˆ˜‘ƒkXw“rg{utV^Ž²ydn†•e2ðØÊ4²ÃÛý&r‘ÃÛ³Çøý#K06{`EJ[so3ûÊocš_8!è„.^¬Ò§oWu†v‹uaÌà’†Œš›¢s›¤´rj‚—ˆ›<Ö ¤¯êx£•<îìñ÷ó˶½õüܽâ o¾†qu‘ÙcÈl¿‰…“™©¿Ö躢ƒŒ¡ÑóòŪƒŽ·Óë« ¬§÷(_Ë»¤Á—u4¦—”|s€œžœ›”‹–µÀþu’UÙ£¬¼Á¬–¦ª®©«Ÿ–µÚ)4$)2÷ã·¼ÛÐÖÇ¥¦Þ^çˆs$r³‡ceh…kfa~r~•ž­·œƒˆœ{gd™z;þìãÚÞ9¶×ÉýÚD‰Ž¶>( -4@F+&;çâÀ^60]Yಬ~H_vŸ~h~•„_wml¦¸¡²«~qk}œ«~˜°«µ™†|ƒ‰‚Ð|añðÎBg–†OôêëóìÅÉÕËÀº<!TÑœ¡–š™¶ -°u~“¦§òÿÉ—™”—„šÒÏɶŸ·ÊÙ×¼¨¦Àû:¼Íº£?è“–…~tz’²Ä·¡†‹§²µÑéóמv|‡xG^sŽàôÚ²¸ººÔþñæâÈ»»Ôßß塼‹·‰qMrjACos_phœ¶Š ÄÈ’iefnhhYWh4 ôáîñJµÕÚ*Þ–ëûÞøUç  2"öߦWˆïïëõ©w3úÝÈ tX¢TgmtkŒ›”sœ‹ …š¨ogl‚’¡¥œ¢¢ÃŸnpi·¿mUyƒ^8 æäò "ãÍÀ«»ÎS̼­½¨Šyw•ºµ» ¯Ôߦ›š–Š†¤ÆýÊßÓáÔ´žŽœ¼êä/Ñéӵ߹Ã}}€šª±¢»¹¢¦¬´©ž«­´ŸtZq€‹¦³ÔÙë严¬ÀÓÜ×˵²¼°¡±Ûý﯅œ¹¹ÂÎåTÖIÕ07ZŒŠy‹µ¼×Áyy’~bGMeyxje]v^! íþ-Ciˆ´çßÖ͵ä -_§Ûß­†FISOU‚ÇØv¼·À ~xdjzx}qz„…t˜¦Ÿ•‡‹ªj‘’zluŒŠ‚€¦Æ¢qV /LÛ&¯ôE¾œ]6ýöíõçÉ´ÄÔß=Ÿ[Íš¬»£ŒvfcŽÅÙ³¿ãÚ¾¥žª£†‹‹›ª·ÄÎÛØÔÆžŽ‘—¾ÚÌ ½öç§Ø“~‡´ÕÏ«¶æ -äû¸•w•Ä¿¬~^™ÐîÜÓ—…“›Š¾âÐ˾›‘Œ¡ ¯ÀÚñé±”pŠÒìù˪¿ô8ŽÔ”õ!T}ˆ©äÇ–‘tjs…Œlbc`dWq…‰i êîÑý&ršÑæœÀ ù¼¹±×ò 1]-íŨŒ†®lòz_y|qxŽ¥rfr„y’˜”jy…xmŽº†a«»„[~–žqJUdpˆ~v$MJ¸Þzà´h&*'  üïæÑÕÍæ'2⟄œ£—”ª–›²ÏÓ¿ÐÕ¬…‰Œ®Á¼›Œ’’Œ¤´¾ÌÉ«†‚uˆ·ÖÈýþ]ãñ·­¢¯ÈÔÕÇÈõ߶¬ºÛ  æ½¢šÞøåÒ¹‰kkqš·×Ä°š‘†Š”²ÕêäâÇ‘•²ÐæÃÇïùÞíoN¢p…Š•}–‹tœ™{‚ˆd\pŸ‹e1ÆœÂÑò ãi‘¯–£úî‰m~£È«šÍÆšXíš‹ºË²y< H„m^dkŒŒlgh^vmpŽ‰yft…š„Ž™Ž°¦x\Š¢’@-@_y†luM“s¤vãNcšJ>XELH3!ûÜéóûâæßùÛ•}“¤®¼Ñƹ˜Œ³¾ÇÖ¾Œ~n©ÏÔ³«©’”š¤¢£Ÿ€„’°ØÆöò†Ù˜¿¿¯š¢¼ÙÕÏâÞÇàU)€TùÌÀÖγ£ŸŠnoŽ‹ÅÇ®¤¦´¯ªËÙãÙÕÈ®µÌïÿíֶǽ”z© nJ{wvY}œ¦ˆ‡z†~zj”¥€a7 —…¦´ÐÓ¾ä4Tj‘‘ûŽZ¬ÎÌK9H=žNAk¥ž®¿ÃÔCsOFZLVXIHIPbo~—~†‰™™ž™º–‰œ—‰sv~€”œ½`nƒ‘¯¬w2eq¹y|ÁÊ¡Œ96bclzPëàüåÏÐ×Ì™ƒ—ª¾ÙßȲ‹Š·ÅǾ±‹qmƒ¥ÅÆ¿ÛÖ¹¢‹‰š™‘†¢·ª€–µí¥Ç­ÚÒÆÙÂÖ‡¢£ƒ{~¦­¢Œ›²¶Uëa>YóÑÖÞÄ£–—Š€ˆ”¡¦ÅǼ­¾ãعÂÄÁÄÖßîöòðÒ×Ù´“œ©§«Ù"­k;³ó #PŽ˜zuy…Ž—”‹oCëèÜ´¼¯‘–’•¡ð-=r¢½øžªøúâÖ„ÿʾ´Ô8¬o®ä+I?NUI.8PcGTn’t{²ØË„q½š‡ywy{‡~~£¾¶¶ÙùâÅ}ï"uwš€os`Rô¹á#Bgu;úòÿãÅÍß³{w†›¤Ùòâ©“~ƒÀÒÁª•„“´ÂÄÀÂÙðéÉ­Šv{•‘£½Ì©”¨Øxxn¾Ç«èIׄƒv‡ˆœ’€wxnhh„è1Ҟ݉ëàáʲžšœ¢²Æ¾ÉDZð¨ÃÞÐÈ¿¶ÈÒßì÷ÌÅÊõÖàöݳ½çôöëäô1·KÔaÏ<\`l{ˆ¢˜‡[Õ·³Ç Òºª’žêY±À¹Çö öýØNóöCt‹uwE§€åþ. BeZL^{—‚m|¥áñΚ€¨°Šws_`wq{•œºé#I-ºK£ÄÛUe£¥—Ždïª~¥ë5YTsx^HýôëÐß×ÈÍ"!¤—˜¬ìúÍ™~|… ±ž‹€ ò㸶êîÇ­…x…›¬ÛÞ»”©›À JÌÚ쬀Œ¬ÒÎË©„rjm]U~Ûw›[KêÜÙÀ»ÄÁ¾³ÂÚßÝÅ´ª¼¶ ¢»ÁÛÓƯ·´Á¼¨²E2"*áþýòÛÑÛÎúTã™1m¡Ó)Wr¦´a0÷ÔÁåéö°ª¬{{~ÂôñÛ6À©ð=Ö3*ù§xSt±Ó˜u_/ðá÷¾¯ðóñ)JKL‘±¨lKe{”Õﮦ·œj{‚aXj`g®»ÉZI°Ëe·92²×¾¸ÓŠº«‘•ÃòGu‡p,òд»Ó¼Ø[”Oͬ¢ÂÈËζ“ˆ†‰¦››"«ƒ4íÀÅòϵ­³§’˜¯ÅáÐÉ°¨áá*ËùÓ8¤ƒ¯ÚâçÇhT`kggš ú‚pâEáËò²¾ÍâÑÍÉÊËɶ°¸ÀÊ¿š½É®®¸«Ž–¯ºÍ5¢¸Oë×ÞçõLhG98n¯‚© WamGíÍíééïÒÌ¥—‡yo‘³ÙÆ·€†‘÷J»G;òûôý¬l\S1ú鲤°ÒáÞâú!h¨«„V4_dpŒµÍªŽ‡zhwvwwwr‚ÇÄÞ4GÁ¦‰µR)/’:j]¤ï̧·Áã,MWdpQ Ëž¦»×P˜r ×̹¤œ´À¹x¡•š¨Î6úeÔ!ãÇÃçïØÕ¯ ­ÍÀ¥­ÁÖíîܺ®Ú¸ÎK¿¸²µ×ܹm]X\wš›ÒF¸žhÈ“¡·¶¹¿ÉÝÌȹ£ ¹ÊÅ·³¼¶—•¡Š½Ã¦“¥³×Þ²ü‘7ó¸»Ü(d† ~S:û w èh§®™š¥àáøÑÕɉ‹™“°›­ÀÂÜ 6bµ<)ßEE6X57ú‰u`K6Ѫ¯«ÃÌ×ͽçñ=qnQNk•…œ¼­z€uf‰Ÿ´²³Þ'<±ŒQ`Ʀö6¦ôšOƒ]izêÉÝô%EbK/9A -Õœ™®ÜCoGÛ¼¢’›¹¸²†Ÿ£©À$ ÿæé˵ž¤Ã¹³–«ÆÔѵ¥Èô鲛ł×ÕñëäΦŒšª‘{w}€œÖ2G80¹Š—®ÀŶ´ÂÎÅ¢œ©ÐÞÔ´Ÿ§¹§¦™›·øýÞª¢­ÑåÖÞbË)êÌÝÔ 6WY_#ó_©Ø-·Y¿ëåìÑÙÞ⣢ÃÇÂIJ¬ÉË“£ð3i0þ5GLe‡T)1õ“ˆŠ~oF™mŸ±‰™©Àž£®¢¢ä!@VTx¯¹¢·Ç²t‘z“¤‘©»ûI=â‰2kívxÁù-‚3tOcåÏ¿>]P >OZTD Д¹Ïù1-üáÅ»ª¨º²§™™˜œªê"Üï{ðµ嶜{†ÃɽªŸ²ºÍÜ°™¦ìüê·›§=¤Ö÷òØäϧ{ER¥«–˜“œ—¸û>*𷓨°Ä¾´¼Ï½¥¤«½ÐÚÇ£¦ÆØÕÓ%`a+嚎 ÈÌö*ÚÝQ黸ÀÖIJå!ä¿ÜåóÒ®ñËË^¥êñÖÇûøüêïòðÞצ±¢r˜ã/ 6KrƒgT*.ò­}ZgR“dœ¢—–™­”’™²ÀËè:@w•—¾Ó¸‰WAi~ˆuOOG4+KoŒdÈ™¼ÐãD@ØÂÁý«ÏedƒzqcB-!8Ñš¸ÑããÓÈÆÖÝÔ²ž §Ÿ®´µð[ýþǪƒ?»£’„…ÂââÀ¡»ÁÑ̳Ž—ËÝÚÚÞþk¬ö2»«žyuÍìÝ•¢º¹Ñ 1Ö°¢¨›¨¤šÁÐßÅÁÑÑǪ±ÍÍȽÈýB¬dì“Ä À«¯˜š¨«7#I‚ Ø”•´ÞÆ¢®Ñ黺×ãÝÌ°¬%7 ä ìå-&KòëǼ±œ­Éã¶$ÎåEhiW:0ü¼ 'F,î›s‚Ž²±™€­ê½¹?JP_¨Ò­J#91ñËîÁ;ÉîTÜšïö%Þ»ÇÄ*C-7ªK7Yi9üÈÈÙæmRﱡ¹Å¹­¤ÐÙÞðã·˜•œ¡°Ü(¥ii-V%ªŽ–±ÕÛæЫ¢¸Ä®§œ˜¼ÆÏìæ€Ï6¢¡‹Ÿ ±ÍÐÛüʧŸ·¿Ôõ·“¤¸´­¹ÉÒÇššÄçàË»¨±ÄÕÓÁêâÿs4 EîÊ’Œ¡ÅEvó.ÆŽ™ÑèÇ”§ÚàÁÀÄÈÂàå֡Ÿ¼wä1:?:XM]ç÷þú÷ô öñ´uׂ™±66/V\5ès%âœ_.-LV%=[j™îÈ£§Ñ &+erŠ¬škåÖ±“Yßý×XÎÎΆý³ñ<>"â¿É ăÈÛ9ÙÏâãÞ·œ¹Ð W[)䦮¼µµ¨ÐìßãþæÌì¯Û?+úÑŠ»nF 6«À¦¯¦¼Ë¯–—›žŽ”¡¥³ÊËæÚÍQ:uªÕçßÕàùêÜ´¹¼ÏâûóÔ¾°°›­¼ÊÈÀ³‹€–ÏìÒËȽÈÝ×âY±ü •b‹j;dû¸Ž£°Þrå!µ™ŸÁûãÓÓ˜ µÇ¿¹ÂÛƨ‹>o^ƒŽ…R(MMGôþ)tU  çFQoÍýï2Z2Ú–Iîá¸~@ýϾšmˆÃéõ6*äïtÌ+¤ôݳQèfÀf-ÚÀÄ‚2ñãÑÁ¦å0NAÙÖ žãìb¸}£àꯒ¼¶º³¹Ïì'ݸ½º¿³ÆØÒÜôýþùAa1”¤iǽÞ{ëôÑŸƒ’›•ƒ‚¤ “¢§°½¾¿ÊÄ—â•£ä¹z„«·¢’¶ÍÎÄÇÂÑÍËÈÓÀ½À­•ŒªÞ峋›ÊÜËÑÄÑèÚÊÆË«WÉûn}‹¹0üܼ“•ß_mæ­—¢ñatÎͨ¹¿ÍÀ¨¯ÚÍÍÆxЛ—°ƒ@%N8.J_jyŽNì¬ï$911_…„£Q'6"â¶Ââ¨g|B'ý7WxŒzc9×çzÛ/ºvÛ« é -zTlT* þ·š¥œ£³Ý1XUN<"1jf}GlºÅÅ¥ª¬“Ž©ÚàÞ˺ëêöÌ·¥ª¶­Èî   =O4v¬ÖWgjÁmX6(+Ó‘}Š‰‰‰¤Ë¿·®±ÄÛαœ¡à&ï1X±~‚•–¿ÜÀ§²ÆÕ¼¯°Ð͸®²³œµÐͪŸ®×ÙƼÀÄÛ즳è:áœ4Û;Á§ «xG Õ³œÆçùß¼È9¿Ñw ÏËÀ¨—™¯ÄÁÖãõöŽŠ¶™ª_5ï&PQ:îa˜¦£ôQL(òÔug¼ÞÏØÈJ„æÅ»˜Š™ÆàÖ»žh\mŸ‚~óöqÜP…Tld"Ë›™¥„¥ÒÞ>^Pu¡vGÏw]ˆ¿ÒÏ¡·Ê»¢Ž¨ÆáØŵ»ÎìÉ sŒœ¶í%4 #'T-¨ÄýFòðÜðKb5ÙŽ£¥˜¸Êʶ³¬¼Éó£²î ¤B`ñ鳫¤¸¶¼ÍѺ®¸«§·¸ßèÜØëç쪞¶ÁÕÖ̵£”›”¬À°“Š³Ú“”¸IǘµodM#úßáðëëF Uófû¹¼«ž¼ÿæéüŠ^|][=,B>Kÿ%V…–©‡0Z8ééÑÛ”ƒ:J¾+WBÖÑzf\ü1GQK?H0#,ü´òÁï‘jäØÜß!øÞß´­ÞîÕÜ6‰],²¢yªÑàÛ²®¾ËÆÀ´®§ÆÕâçÐϾŒbXZiÈ94ü×Û™.iþ\⥩˜‰«à'd€[ãÕÝíÑ»±¸¸Å¦´Åû*ݬ†Ö øÅ°¥™Ãìò·“ ÈÌÝõôéí̵¢§¢¼ÇÐÐÞƒŒŒ“¥Å¼^|¤´G·sÖ¼Cíð&C& üXÙê‹Æ”œ½Æ÷BQëçÝê¼: WJD53CO:N:1NXr–ˆ“tM*=\À¯­Ù½†„ƒ [wi ÈÇa›ƒ|†Ç"=!õK5óÏ»Û)ÆíŠÀ¥ÇʾÓû>WkY3ùìð rü:j¸¢«茟Ó௫µ¼ÂÀÙÊÁ³åIUJöÁ‘d`w{žÕ# Õ¯ªÕ8i8Ý£›©®‘ŽŸ§»èG……Ž‡XG]i%ùÒÉÑÙ¯‰”¸L»KñèåƬ¯¯ÏáÙº™¬ËÑÈàýîɱÆÀ¸»½´¾·µ¯ž ¶´ ¦ÉÆ­†‚††åó/ײŶ&ܯÀþ&'%'í4ê·±ž¿Þö$Q-ÛÑÞAÖ6ü(\SSb‹ŽCQWgw|‹gnZQL?6饡ÙìÍ¢Ê -$KIG¿CDÿku|‡¿ó 8yo0ïÙí -ùßóóû ñÂÅÁ¹¨~¬±¶a %ý®‹=qœf€z«‹Ä¾¨ž®ª±Ñáô7îH[3÷¢2Ò‘‡ˆ|¢î#À˜œÃîòÝ©zªÄÀ¬¦šoTqÅ%e³ÏÁ›¸Ñ¨X ñââÄ–q VW†ºຟ¤¹ÃÆÈÏÁ¾½±¹Óº­¼ÙÇÁºÄÌÉÖÄ«¤­±ÒÇĦ˜­ÈÕãÛlÔp)¦¬Eи·ÄÚ迦Èåö ÷Å™‚’¬²Öøûùà¿åúO”%XÝV]mwh-!WgdbSscNIQU= ÿ -^jŠ…z‹xK-&2»)ôebˆ©¶ºÐIž¬@ÓËò$Úü§¯ÂʹÊâÕ©ˆ¹!Õ²Oúé&.éß?‘ÃDe0u;û¬ÎÞ­š¨¨Èßô7šFŽ×¼s /Xÿ·¯¨©¡©ØÌ«¦Àî㪉”Ž¹¼¨­¤x>A{¹öf•˜”°Êµc ÔÓÉÆ«…¨&}šâ¦±‘s‚ŸÄÊΞ¹Æ¿¶¸À«–‘§»ÂÇÓÒ·«§§³Òíس—|Š·ôðïߟ}½25@gDÞ³¹ßÀ²·£’®ÐìWlJùÈ«š®æãÙÒ»ÆÚC{Q 8]ho{qg1*4ak\I5XdQTvƒ( VÄ Vq€–”–fþšN=ã“-CE‰bt‚—¯¿ã^ÊÃböÙ Úµ¬­¥¦‡¯Òý÷ßÄ÷-¡Ækíé9Z'ÜýqAÜ4)æ?¢ËÜË¡šÅãö)¨™ŒùþÌ1= c$ÕÂÁºÀ×ØõðÝÌÓõ乜§ŸµÊÅ´«œ™ZW„‰­SH8,''Ô²¬´µº§³B¦¼ ³ˆ†Œ—¼Êµ´¸½¾¾«–”²¯¥®¾ÔâÛ½ –›¢­·Í°’lz™ÐûóÉ®˜ù2ˆ­àȤ¼¯§Œž¢¦¥¹ê>Ú±ñ+ä´®ÚÓÛàÃÄßqˆÕ0LuY]civ\?5Mu{tGENdxµÏ°XjõlÈ B<É[ ÃDÙwÃÇÖ|{ŒÅ)56 ¹Tçóö×®°·¶©Œ®êÿüéÏîåÞØe„Cæâ!n«Fx9œ«ÞëÀ«á÷%™†îƒ¡†6-ÀÂS1#öÕλ¿É³·Ñáã Ú­¦ÁÁ»ÏÕÞ£™s†œ¦ŽÀ ݹ¤­™¦Ÿ«¼ÁÎÌ^ÉÛzŠ‚•©ªŸ²¸±±¶±°’Š±ÒõóåÑàÕÈ–‘†…ˆ’¡žŒ{¯ÚØáÒ­|ˆ¨ë4Á©»±¨˜•ž£§µ½¦–ƒ¯èB %_rð£®Ùíäóáêð‚í+WXoFThr‹|K5?\Šh9:y¨ÄÔµÁ,­é/OOZHS@ý Û hý{pM°hˆªêR=îW—m éÑ×Ǻí¯ÁÇÞýýìÁ“ƒ¨ÃÉÂÇ+¤¼k0A2ocF﨤xºêÏÉòfK¾5Àí&H÷Òη¼Èª­·í Ê›­Êɳ±¾±»º¬’–¢¿·ÈÚÉÁ¢y‚ˆž ®ÇÑÁÈ}  q}• ´«˜ž¥£ª¶µ¡«´Øäýæ´´«‹‹Šnt~{p|¹æñѸ¸ r}¢Ð÷Ϲ««¥“´»¼³È½Ÿ¦Íù@8ô-ËÇå -ý@MñÛá¢s_E8QR[sn‰iXnUECB#'T”’ˆ¯ãSòðL{bB6>C)>}‡÷‚×ñ¬¡¯õôô;‚]âá¿·»Åª§ÓîÜäüú°€jkŒÂÝâí@²©I*@FÿïŠ-[¤nŽçüÐÎüx&oR fƒhàÜ×ðà»®±¸ÍʸÔþó óÍÄÍƨ±º»Â¦‹¾×ܶ³¾¥Žƒ’¢¬¨»Å½»Õ¶P7Zœ˜¥¦´ªªŸ­¹ÖÎŹ³¥³Ïâ溬µ´¦hTnd`…¶êôÜÐͪ•‡—¡©á¢«±°§³ÊÊ°§Å×½¾íRf9òá8A)6pLåÚóÒ’e&UtL'\lmPif*%E`hzÁVêø:[ZEP4(Q]lykH· - Ùo3ÐÃËéãíúæ :"æÎüij¶Õæòû @X¢wxŽÐü$@ ÈÆâ$6W‘h¿„‰Ôäû|Äv¨!,ÕW:œ_ËÁ½ÊèݧšŸ«Ñû úòùÛ²£¨¦£ÃÁºÀË¿¡§ÌѾª›£¬¤¥¬¾ª±³Ÿ£íýwJ)ŽžŠ©ßéÀ¤·Øéïη¢ …¢ÉîõÀ•³±ksp{˜ÇåõÓ¶·¶©¦©šŽŸ¤¤…•¥©¬ÈÒÑŲ®Æê×ÎÚÙÙéò Kx0íô0þì×zH,?jnüLˆw`tV #áó:h¹]ç990)#+3IbGBeosX<j3˜ @ër×µÛæãïÞÜÁú,þÜǼÌʲ½·ÆÍØü;î}å#Å°Í÷îå̱†}À37%20'.¬¤Ò <í(p‘X±æ{w±¼·ËÆ ž’Î&L*&ïïúÞ¯–Œ««¼È¼¨¼ÇÈ©ŸµÈѸ§•Áµ¶·§Â®•ë‹b8ã„žÀó&+öÜÐÑÞóÆŽ’ž«ÎϲƒŒ˜§…ŸÓûñÒ»˜•²ÓÒ®ŒÊëÓª­­µ¾âÞ¿¤Ä¿ÇÌÌÐ˱ÀÑê"13ýìù)üæ*òCShe__þL‰ptCûÛÀ× •Gÿ<]iS,:JkRHLW;,OZLÍIš›óÙ»ìëøÌŸÐ-!ëÕÑÖÍ»•jˆ¡¹¯%}[DL11%ï××Íʵ£ Äå üðâð1HùÉÚ*y Ÿ /’¯ÙÖ>P}£¬ªª²°¤”˜½/yC(&ð÷ ÷É´ŒŠ¶³Í৸ÚÝÇÅÃÍÖͶ‹ˆ‹¦¨±­²À¾ŠÈ2ÚÖmÇ’®È iDåͺ»É¯’„™¯¿¬‹‚»¦¨µ°»Ð-g+˾±©©ÖåѳònŠ-ÛËÚ2-ÝÏÒÊ¿ÖÕßѾ«¬­Ïùÿûòò< -Ahxi„Pri](ÝÇÝâйÒP/é6OcX%÷ (%8&<uiU¼[{¸Wë¹×9ëà( õ⬑wJ:fnnGç”'49Ì^3 òßÔßåÊÀºÅÉÄ¿ÈØÆÈÿ@? Z¯6¯~) |#%k…”‘™²·ªªØE©Œ.ýüóëëéÄ›µ°Æ×½¾àïßÝν´®™Ÿ¼´š¨ÎÉߌâBb•Ä¶¬ªÖ8h(Ʀ°Åг“š «oO£öûÌ®¤ÂÑX NÊ¢—ºÎéÆäHÅ7)õ ("ÞçôÔÑÍÓÎ̽§›³ÊêòóïëQ: QEšŒŠow‘s@õó"%Lj¿æʹÆÜs†íí&B58A$ùùüGrlj]AnòŠ¾ #þáÍù÷çÊxGL}†i[CÏœZ|¨+ßìÙÏÏ×ÁËÇʵºÃØáÖÔ?OA<zË;,î]æ“Y85Mv¢›‰–«¾Áœ†’ŸC+/cÞÓÖìöÒ¯¦·Á±Ìïá˵ §¤ˆƒ¢ýEþœ£Àº´‘£gD¨¨¾ÂǹªÃáÇ””·Ûêê¹——~cp©ñ Ź³¬ÞZ™vŠ®ÀÛìÌÕ/l3ÿ  $/å×æÍ­¬§›šŸ”™·Ôô÷ý=[L86†Õ.¢„UGa{mú¬éûzÅßÔËõízó=@7[1ãìÑÖ?C"!Bow[|žEGß\ -ƒŸäïâóöÔÆÔ§…¢Æ®¥©¼ÿ6P0ÓÄ®ÁÄ·•£§­µÕìÖß éÓçýúHÓmÏßJ’•aVLbbŒ±­’˜¹Ë³‘}…³ØqT5cÓ—¯»Õ  ÞàȨ›™ °Ã¹ª™ƒšœ±Î11®•Š›³ÂDg¹¨Ö¨£’{’¨¡–£´â -õÅ™”‰—»åùåÖàÑÀÅå;Óž¼Ñ͵Ÿ¢ªß! -ûôïì$fcý¤”‡v€qw€ŠÄÚßù#/"8?:C ô<^Q †°…R-7gfÞu°Þµ¡®ÛÉë«þ,M7"9RÚà·îIgX8);fLNu~@w/”+› Ó-*Û½â*?$õàÅÆ£Âõ% » ·µ©Ž„y™˜¬Ïçæöõáõ¹«„v8{…%*ã £ƒ˜”¡ÉξŸ´´¢Ÿ ºêXÈ¥ʪ•ºÅÖæèᦛž¦™…¥¤µÊÕßìý" ­•€“¢µÙ„®^® €‹‹ƒ…—ž±±¼Íß7Z(̦›¨ÛùààãàϺ¨»©›±µÖʨps »íìãîÜEäî|Ì]a`q‘§£Ø?7Ga55(/eXG^…£ü¶®…H%0$×s—À¹ŸŠ§ç2cí¼þ?LPPB$õÙÌÛ<HX<%Q=Kd@š«-šе÷.ø Gv‹ŽYôÆœ”Óù&7<4-茦 }md‡Ÿ™¤Øüí¿ªÇÍŽbONHZe$›G(kܲ±¾ÄÍÍÓñÚ½œ£©Ñð +ÛÌÏÇ»¥Àñ'í·£¯«’|Š·Éèúôú -ûÅ»¼À¦¶Ð½÷¤Ì`¬‰8˜¡–¯ÌÛåðõ ,€Ák߯ŸÁ?ñÊÌßĦ¬¦“ªÀ¼²¤£›§½§®®°½à÷å¸*YŸÛö¦¯dz”¼ÊâÿV¦“8 .J4!tæöœ…©¹£XïÊýüÁšÀ»§w’Áî™HVU?43õÔç1E9AAJF+¹ó%æG4VržÅË`Õ’n‰±Øô96ß¼„Œ¯ª•’ƒr˜ÅÞîÔ•“ —€J47:l¢¤[úì‚Nu6ÎÌØâç¿í2 -ʲ©¿ñÞÔê×Îà”t«3}[ 棪«’¥Øâ(ñëâÒÆ·²ÆÝåÉ·ãªùŠ•IL–±ÂßöÛè×Ïv^_b½Ñ=_¯¯Â³‘¥¦´Á¦©ÊÕÑÐɯ”™—¥µÉÅÃÞêdé^•±ˆ§Ûðêä1lñú@ K’ìâŠg˜&…QÖÐ10,ó­©Ä¼‰i£Èœš!7@-%,I Óûñ6F>(04-->ô"áH{dTFlA0Mið†Nl²‹¨µÍò-KÆÀ®ŒÆÝÀ¶‘cˆ«¶³Ìµœ„w}p]LJFŒÌèHÎûSÈÿÏ×Û×ÆH>üÖÆ¿ç úúß­™½À¿°›wkµx0)”éÚöýÛê߸¨¯ÎêÒÂÃÔÜØ´è· §z[~‡¡ÅØåêÔÄ»Àº¼.~ÒÈæÇÞL‰¶”›®›œ¡®¯º¶±ºÔáäáÁ¬–ÊæàÙÅÙÚí%"#D”¡¾ÝÙÌèÿìæú0*.r„…H+V8;$ÿú*(ÔÉÙ¯aJ‡¸È-´/<FQ4%!øîù(C249:2Jkã–B•›{Xc‹…Z4$7õ,|†dÞÎ×Ü -H?󧲣…sÁùÔЫ•½µ—›µ¬™‡soqŒ^UI”¿ìRÒV(‚Dµ®À×ÔüA;ãʵÈëöãÊŸ‹¦¦—Š{ί§âS£=6F=-ÿâ½£‹¸ÆÙÖÝÖÙϺ©òÄ°)®n{‡°½¶¦¨ÁÝàȯÔÞ|Ûç$—¸/½ ¯ªŸ·ÐÑÞÀ¸º¶»ÞÊÀÒx˳i0 \¤±êR„Ý›dš²ÂÎƤ¬²öA\‚¢½™r4"•nnö0 !!3CÑ»fdd—¸ ¬D+_y:*ýè5.).üAVenqÜ”Y‡ ‰žª­o4+óh²º`cKSkQû°•‹trØýâÍ¿¯»º¥ ˜— zsk}…hf}°¥’q?Ný|rÔX“™ªÓÒô %ØÉàâûóæËŸŒ••¡ŽŽ‚šÞ—« bCY`5îǸž‹—²×Ó¶ÊÔãïãÅ¥þÞ,ŒM‚Ž–›œ³ÙñûÚº§·Já®!óQÌÈŸ„‹¤µ¹ËÎ⣘’œ³æ<Ép!\ýoö°|û?WÂ|U”Ãå×Æ°¬×3`Nr¬àïמMY$´éù24 - -/]ª‡šq‚é+Ÿ}; /au3"!ùÝK1$19+:YLc<lV8ꌰ¡Ž—¨ƒ\.UûXMxÞôaAâ½u'·u…™Ôíͳ­µÅϼº±À´š””~l›Ëô†Ü˜ê&·-CÕa’ÈÛéõ  éÞù þöȯ¦§Ä»§±ÚEÙ<#·C$-2¾¥ª˜ªÃÈÉæåЭ§Û -Ūèß1VÑuür‚œ¾Øóù²‘ÁÿgÚ±lwÃyæzfz¡´ÄÆâ(ôŠ…’ãúŒWÑÁ;†Ñ!oC†ÏB¼Þ0…’··ÎÝìæ FSrÅåç'«h·Ì¯ÑÈàF@ 5>96ü•Ž³§{Z€¤ÉW`4>R#7:1ôúFUNF@ 0B<#êM9ß}™^6;ViŸ“u©E„V¼zÀ[qhæGÐií—ŠŸ³ÝüÔ¬µÁã÷ ïáãÜÕÄÍäòÚú!pSËQËJ§Ð•ÛÃêüñû#*éó#èй¹ÒÞÚÁÁ½Ýüõ>V`0èä鳫ÇÏÙûåÆÅÉÉ«¢ï Å¿æÛQ"Lõ¨Œ‚…§Ôá朎ؙqdx<ûkÉ~i~¤«ü'¼–—ɈþTMÆÊ°4}UáÏ/7hÈý×…ˆz°Þ6TXX“{‚0ðèÄŠžK]èȧÁÕB"7F'õ‡ƒµ¥€w©ÕX%â58. 7S5!öý'gb^R ù'D-î·Îe# -tn† “ú»p¡oÂ,b‰ Å;(जÃü úçùxä—}uà¼ÙÿtÚ"zÉÏ+ýôìëý.ýÊÊ:)åæÚÕÜßͽÁ¹¸ÌÑþ -ìõж¾ÅÄÂÏÚïáÐÀµÀ·Àø(üÆÆúŽ˜[ÌŸ‹˜•Ÿµñÿ¹‘KÉ7è´Q‘™Ò‹‰‚x}“à<'Ò¥¨ SL«ü½´Õ5œ­õÈþv@ÛbšÊÛßuÒÖˆ½˜¼Hy· —ššà-)92-þ ‘³§†…wV’ñ|~*$é DNQD(+Nj:눰ž·æOú&.  -v7ìÚ\æƒð€6ê£ îÙøŠ»jÊ–ž¸ð!=2ðôyÉíò÷‰‰_ÿ? ¡ç]ØU -à¿»Ûö æ¶Ú4^/ëõéæëëѧ®ÎÝÊ°×üþüôöͦ®®¤ º×ÖßÕÔ¿ÍÓä2ø·È+?¢ïd 䲜‰{®¿Ž•/‘M¬3>õ2ó¹“kie‡¡µ Þ©²1Õëñ!!c¼Ä¨ˆ©Ø3;¿‡„mKTxÍÿæóL‰¥§Aæ~jwuxŽ¡¯Ú*>7?-LQׂ¦‹‡k?fµ ·Óõ2%ý ä?5.AE.MR:Ëusu¯ì/@*0 îxA‡kË»U•`ñÉ+—©âevã«£ÏØ(34ßÅ·ÏV³!}¯@*í42”4$°jÝóºÐíýüéâD\ÌÝËÜþýÊ¢±ÒØ»²â.àÍ´¨¦±³¹ÕØìîçÙöûþ#)å—¾T—Èó*à 껶³«z{ƒ…e´-‹³…·œ_0,Ö¶ ‚w‡¢­¨¾ëæÈÂSáÒT1Ì?åÅÓá4¹ÓŒ€–£~©çò4)Ú¦œºû4h€‡êQ™‰[kœ™¢ËýRpsKJQL%÷¯««jQ98ŒÈÒoî^üG;?67 -,I>71%8BñGŠ.cSý5'DO+/xØË'Š8X‹õÑ -&ÙÈÃì3«;UðÍÇ´Èò#üÙý •¾ï]·—|=]%Tp" åÕðÔÂÀêûþôêü1e¶¨¯Ù د²ÄÀ©Æ8.Öƾ½¿ã÷ùðöéâè  -ïÿË“½oÕýANðòÑÀÀ»’yxÒÛÕ‹0jˆ¦‰Ü<ðͪ¯­˜¨³µ›”½Î¤˜u^´ÏÿŸ ý³Åëáá;„‘pZ4;„Þó íŠo–¾äò`þ‡Âª‡vŸ³ÂÐä~S3DVH%5ÎÆŒaMN‡Ô̾”QÿNQ]\+*Vz_N7-29 ×OÊ4é»%M[O89/TqQÑ€J¡ê;ñA¸·¢$ìãݶ§½øòÍÀ¿µ˜xŸê ºjÉk-<ÕÞ:ï û óª²ÍÜßåùæA¯•£»'⪞±¯±Ù7O#øÕÍÞÔØïúÿ-(4EâÐæûáÑÙŽîeúÓæ¿æè·ŸŸ›—Àjðq¨©`ù©²KÃ¥¾ÉÕÍ´©—™Žx„yM¢G?í兩ØàÆÉø29E0 -ñX˜±Ÿ„iŠ·ÜòÚ™göÍ»‰m°õôÿ-;x”p+I__-S>âÓ®xg{Ây ƒÉQWTraAR‡oX@D6"-Û5Òxhwp.#6WP$:0 ìãã& <ù#,­~f¦¯äH¯oå»Å¨Ç";Óš›Ÿ‹ŸÅÜLØZSûÛpr$8 ö³¨´¿èôïÏÐþëͳ°¢3ô³¥¼ãæ -, ùïÕÉ×êîðßôV“­­ˆ6ãÇì -üöИ"[AÌš«µëëО¦·ÉòôÕo*p£ž…L‚è÷Õ–§Õ --À¬’•†psƒ¤c™é_s›ñÇÓů­Ÿ«Æûëåãì>_^7=aqŸº¸©R(Ü+Ì΢µ?6^xœtS{›„SGpaAþ²’©¸]%y Öžsð-MRof3 :Z,ÛÈ+sM¼ßá0ø3M@áè";'' "(:ú æ+Ï™¶ÄÞPX< DkzQê–‰ª´—‹œ—ñZ¼ƒpP¾B .ùıÈóõæ¡¢¼ßðÚ¥“¹óíÙä,3 ÑÏîñØÎÌÅ»ï?}¯ÙãÀ†,ñê" ðÝ¡Qbüž€”î+ÔÆÌÄÿìlK””_×}›1¬§ãUÝ’ú¯¥±¤~…žÕ"À9JÅI  XZ÷‹}š§¹¯µµ¿Ùþ:3EY`x}fE >³Ùñ(`rjs~‡ÙðØù ùóñõá±…T îäÊ|`±‡ì„Ü4œ×:4öÅ×Ý Újõø߆oqà9FWL"ô -#.! -"(̧œ¯J -°…‡’ ìÖ¬ÍO§V…ÚÂ=Ú»©ª¥“Ⱥ9MÁµ…TŸ†>HWS0&?Gî·Á×ç軤±àëÑ š¯ß0Tqw-ѵÒ÷á±¥²uÛ æ³€b7ë÷'ìÐÓñàm.Óžv„HON)ðÑÄ°ñÐj÷Í2ý„§/z¸¦± ðR¹¾= þ  --& óêý-ŠŒüŒ„š¬¸ª¨Íòê&$6AEuqP$@€}¨æ1®8?ÒsVl³$‚ENHh52A1*$Ýk)õÁ•§RC« |$LWп͆<ôÇÍÜi)-×Ì#X;0<@%2+ìåýúï¯++öB‘_G6-9ž‚ -FQ÷ÎP€Á´Ÿ¯IY" 7×jz -ë"”b0(a?ó°´ÆßáË¥ªÜîßÇÈß83Iª£SûļÌÐËÝ$¥*ïŠF øöÛÌû 즄–û3¢ä¹—uU/Öµ­Åá]ŽÚÜkºÅµÛ˜zl¼ñl¯“Ÿl˜«£©²†#кÂÜ - -GDû ‡zœÒãØÕÚæïîáû Cx_2p޳ŋX%`œÊ Î\Š_:]g1üõ0u~u´YÓ»¬% -]ž%—i0B%ì"ýæÚâ°”ªÌøÇò3E:B2.û¼¼Ýÿÿ÷¬Àâ #ÊLÛ°¿ÊQ‰&ÑúˆÖ¹æ0³óŠþAwDß¼öoѪK5È°±¨ÇæÔ©³Úõõÿ41G—Ò}¼¾ÔOŒÍ ôÀu(éÑÅÅÆÑÛÕ£uŒª0k«öÛªTú¼¨œ¯Öì'¥r&fp·*詈`J”{I ”pn2a€w¬ tæãíçìø‰xp˜ý -úùôåÏĹßñî 89›ö®Ýkã­ß1IF^rRçÔʽÚ07q±dë†-û¾^O…”«ï³\®£™¼ÚÝè̆iS3Ïå)lR?2þø¼¿Õåôü÷§ÔDÀ <9ápù~±Â {;EìÓ(òã%¶-ÒEíõ% äå4¤õ¹8 3ײ® µßêÌÉ÷  ':èãäÿY–PòÑáA°Êf3÷е¶¾È¹ÂÊ~¤ÂÓZ¨±ãöÜŪëض™ªÈì÷Y³ã¬1Ö“‡dh{€-ý…T­¥žµ½ù3è/áÐη‡s†­ãæøïåÞÁ§´Ö -ûúõãóõÞ#îPÏ{œª€ý­„WN8#ðÚÌͱ‡¨ÖÖæ$\z‡dÄ8á{o¢–f‚p+TŽY]ˆ½¼»³€þëÆî:yˆ4 2!ö¾ªÖíâÜéöþ…¹"ÿÜž=lr #›ÍKà×½tci­8ÕÛùŠòà^±Š,'PU,~ÕÞŒ09bIðÂ¥§Îýàøçø'ÜàÔÔùïÊÚÛï,ªÿñiâË´·½ÊÓÑÚ‚s²êøŽÖ ¶ÏÓÁ¶ÎÒÈ·µª¤­¼ÆÓÝûûı§„qa–¹jnCAHIk}ìÄ¡Bþþû×›yx¡åñȸÀÆÁ¹Íö'3(âî)>Þsw,ê¢ÀDò ÙŒjEùÅÕϵª»®”—¯¾’²ØÙÿfDZ'½qi‚aO[Q?ˆ‹B=ŒÍÊÉÓ}|oÔÅÖP}Z Ò”®æìÎÒéåÑp¿@79܃X-lJSˆú.¹Ýøιuêa·áßÝó@]bJëú,ÝéžuvRôµ²ÂçõéûèáâùæÅиº»žÅôìóGyp& -âÛ³®ÀÐÒÖÉ‹“ÁÞúà -—®Ãĺ¯¡±»ÏËƧ—ÅÙØÝ;Á½È«{f˜»ÞÌe>hrVbÖ¶)äÒòퟩ·ÒƲ£¡Òò GUGöü_‘}0UqÄûúÇÄ@=j‹zMý¬–Á¾‡~·Å¹¼Ý´‡“®›® `{Ùo¡i¢T<qF…š[W£×ÌŽ"±íÈÁÚÝ)%þæĤ¦×Ó˵ÝòÝÎoíw_Ž¨é%"5tü¤t°m„ï3®Ú=Né|Ù”ÞAaI/âàôêå6Æá…EøѺÐÙÞð þöïÝð б­©ªš•¢Ôö¦³/’˜X(ÈÀÃÏÙɳžªÀÌì>ÊҿƱ™qÁÞÚ¿¢›œ°ÀËÞéâÜâãí¾~i‘¼ãáŽ9%a‹xG`ÃrZÒ¸Òò óÿ橸¼Ã¸»Ôê*kn@ùÆìHˆd%#ÆãXp·@µi@X^7Û·§¸É°rn˜²ÍÞÓ¶“…™ÅÎ’Ÿë5ŠM0¦ W0drNo™qd¨¸¬’{¨[ÖÓÞåÛÌàäàÀ­¿ÎìÎÆ¿ÎËÀìˆò£¦ÓÜÊF16aʧõ¬Å*®‡™9ø0$Ç×ÚÈÁé.!æÆÁÌÓßóu%²zÛ!šš¬ÂÚÐÐòÿññýççóÛ±¯®¨²¶¿Ôß¿‹|¥æLŒ•t1÷ßÝëñß³»Ü(/Eàüñå¯}k…ºÚйµ»­ÇÑØÖåìíöûá¼…o‡“ÅÍ”fOe¹6=â€Ñ1»µÏÇâö¶¡ºÊÒÝÓØúPœeϬ JNC!*P€ªƒƒÿ|ov= -ÀÎÜÏÜáÃŽ}„¡ÂÛĹ€ƒµÅ~[»‰¶ö2Ó—ˆ|j{ v}šŠv2ZVäÛÛÔ»·¾ëíÍÍçýìß±°´¼À ˆÝžœÊØÒBžiN¿×àÇþF.ŽÒãI¶lÄ%¾—çêÃðá³­·²ÈÚJ;QéÇp–w±ðüà ñÒÏÖÈÒ˼°ÀÛáÉÚÞáÚ¾¨™”®Ôö?p“f+ùõ௨¬¾Óêq¢vâôƒ™—¦¼Ç¿¶¸µÓÛççõöôÕÀÁpWj² ]u™êdcÒ:ö À¸»ÁÐû ùàĨ­µèêí låØSîËÀ×þ( %Ràûðƒ[î…QOÁ®èüû -ÌŽq€¨ª½¿¯Ž‘®—sqÞC¤œíᲉˆ€“vj…{ú'¿ÀÑžƒ–ÙþöÊãçÅ®Œ™¬©½ Ê}r®²ÁmýÙçË5:! Í(º”3Ò¨­ÁïúñÕÎßÕ°¤±µ½ðè|¹þ¶ý怒à$G<óÁš¡§ÁÌ­¥°Ðþ( -)ß¹¢­°µ×ç 1N?! -äãÛÇÖãÚòµ³&#º„ ¥­º¿¹¯³¹ËËë÷óèЭš•­±SdÖXÐR”‘ :Ž%îôÛÏ×ÞÞôùíÉ»¶“”Œ¦*£äâ÷ý ó-t 1%µ£' é¼ÆÞáε¥š´µ¥¯¨£µÀœW)M»õõ3j’J¾-«…grv€}}ˆY®ŸÙŠ»Ý£sŸÜñåÍÞñ¾’‚~„£¡»ú{¤E8:Lƒprç*]öÉÖ>jUë€'Ç€“ÕôñÚËÂÝéÿñ¾š£²¬÷pT>w<D;Û˜¹ú:?ܲ¢–•ª«¤µÀÝ$Mi_I×ÁµÂ±µËáïäÚÞùõÐßñõñÉOÝ - ê•ÆÝÛÕÍ®§´À´°Èëáδ§x†’rrîÊõË6¿9ê#¾š°ÊØØãäëùùôãÈ»' Àöè×—Ò.Ûâüûý ó4Xà;žEÚNßE÷м¹¬Ëûé¯ÁìîÄ´«œ£Á¤dJ?fÕôßð2vWŒÃ›¤‰^?‰‰ˆ~_*XS®¡Òß¡jŠ½À³ÄÓ×–zzj~‡¤îi…× uŒ ¾µÍühUµµ0Œ ¥ŒœÐáëÔÅÖóóûñÃ…ƒ‹ñ¡z0\ê&;ü¿¦¿ðüÙ»Ê×аœ™˜±ÁÍìE†™m!áºÎÈÌ©¥¸¿ÐË£¦ÉðÞÙïàèýÚº;ˆ ÿóùü¿ˆ‰øñÓ§¥¯ÉÏƦ©®ÂÂÉΰ‘ŽœšŠý5²¤çÿ"óµÿËX|œ»ÚØÏÙùñçëØÅÇêx [€F šÁ+üÿò÷ßí ù@OËPóšmõLëÎ’|¦Òÿ¨€¯íêųŠz™²whn†´äÍ~å^—ô¶¶¥]5i„‡’ˆ++±ãÛ¹|~±ª­½Í¶‘j|€ki‹Ê!§›Óa7gñCDŒ´›ÞÓkz¾ú c–å—¯Øõ÷õÑÝôéÛá¶|p{vìVÞ¬áWûµ#ñš˜²áÖÌìä­“—¢ÄÅÔ Gw„S𤦽ÇÇ©š¹ÛßÅÁÈÜâÐßêÉÀÀ©Çi¾ËâØí÷Ñ›‘åѽ•Ÿ©°ºÃÇ¿šÀøÚ¸˜­»“‡,Ñi06Sž·üœ ¼É¿¸ÍçöúëʵÙý5ñ~s-Û’@ãáØàûøáHoç^åƒOÁHä®}nžÙï±z¦ÞãË—ƒ|…`hl•””¥’_\®¡;5Ó¬®€GQs”¨– þÿ½Ô¹Š~Ž‘µ´²Ç˱›xq€{{Ý"R¹q™¸È3Hµp¤¼L7Žð%…’ꛌ³ë÷öóßðçáÍ´º—Š‰}ã«”Yw¤¥ -ö妚Ííàéï缡™§¹ÅÊè13ú¨~µÆÖá½ãýðîþðݾÕδ¤—ŽÖœæÊÙê!öDZºœz‚¦¸¬ ¦·°¶°ÉæùþöûÔ»¹¥“SDßM^F<dôWz§–®¼Ã³ÊæþèÖÆâøáò)+3* ÷ÒÑç÷öøÝÈÖIgÙaê/¡%´…–‹Å‰x«åÝЬ‘zfE_w‰½¼’ŽšfQ“o4ƒ ¹­šig|¢Ù¯ã¸Ù”™y‰•ˆ“¡ÅÂȹ ˆŽ“£ß MNdù’_e/pßÔácU‘Ué³UÇ—àŒ¬ð40ýÞÏɯ»¸š‰Ÿâ<¦øêI½¿Í×îâö øÓ²¼­¦¬¯¹°Ú,#èʶ¢·½Õϼ­´ððÿ年Ǻ”|…¦ 2àü(#çÉ¥€€‘”­½­¡œ¸ÃÃÅÔâéÛáëÞ¼½Ÿ¡pU -okhWn,Š~˜»ÊØÖÔ&øÓ»­»ÏßÔ¼±Öÿæ¿ÕØÌÉËãÐÀ¿¿èINŒsŠ«#¢ªzyŽeŒŸpw Å¿Í·¾‘47z±Üâ¨otŽYeª %IíLðÚË–ŒÄû´¹e› ‚˜”‡Ÿ®ª²œ©Í¼¬Åï91%”p܈ƒÁT;ñKþD`ŽµØ•‹ÁM¬h%3#鸳¨­°è/BLCă­Ïáü$?aU!Û˜˜˜±¨”ºÿ#òɶ¯·Ú뺴·°©ðúâ×⺫Àȱ£žÐKlçõÿÿç̸ƒi}£ÆÁ®§³ÉÆ´ÃÖÖË»³µµ­¡Ç“f"…`RUƒ3‚ƒšu™¹Ôæê Ha ±™›Ÿ¸åݾ½¾ß×ÏÞÒÁ³ÅÅ´°½äWKEï"c¦£pTYh€ŠqŽ¬Çª€™¬“Q_¯Þá§zlsqJqêû÷[.{ñ ’Ââ€0ˆš‘Á¹””–¥¦ ÄñÝÌè ä×çAÝ“±þ+ÓÐì:q¤–S˯-o‹4åã—¥ÄÛm0OBÙ££¿×û_œf#þÞѾÍàê<n†|EÔ¶µ¤µ¬ó[BéÒÉÊàò±§£À5ÝÀ¶¾ÎÅÁ½ËßÐæáu³•ÀÎÐÆñ¨•š•‘¡¸Á³«ª·ÑÂÎâÖÔÊœ’‹‘¦Ðžjü|jSQH¡4‰ªtxžÌ×åúG†#®œ»¸›¨°ÉŽ¼êèÁÌÚãÉ·¸ÄAL9À´Ú8øµ‚a^s†Ÿ€™ÔÜ®mŽª»ƒ°Ì¬‡~•Ž~c§ðÚîB/fûýéâµÌfx#ŽŸ¥¤µÉ͹Ž¸º­³î ãÎÑâþáÝЀ:Œ*ŸD︡ˆrŒëé7Š}=©Ä&–„; ëÒÉØÔÃã7á‘2 óáîäÚÜn±Þ%ý®l8 -î‰å¢C"ýÝÚçßËÌÅ°¤Î;×ÊÕßÓ²ÄåãÌ·â©ð›·ËËØßƪŸ±¦¤«²´ÃÀ»´ÀâñåÝØê켄‚„¥¹…ë\<3îšÞ±g±¢ÁƵ­Ò8´Éο“~–½ÉÉËr½‘ÒÙÙàÀ¿ª²5rcÈl…ògáŒlwŽšª·Ì®©yžÄÌŽx™ƒŽ†¾©…”¨Ï¼¹Ø/&Ž%,èÀÙävpƒ¹ÅÐÒâéͤÍç¼Ñú úÜÌÇãóÖß ^Ó/8þ¶Tþͯ±«±²©iüã.ÉàÆô#K5ùåËÅÙèÈ·ÂRMuÙ8ßÞóÜŽÑùTÆ"ŠëüðÇrÞÜghÓžaQ= ûRvEÎèóÚ·ÃäÙ¦¦Ýîaèàñïðö¢{u®·¼Å¼ÄÂÅÄÊÞãøóÒÅßüï«œžš£òÎîUgo¯Ý–±ºÇµ›˜³æúÝâܾ£¬ÌàÖ±£û¯G@ïÝÙÝÕ̹¾eZÄR6ãÝ@½iiSG^¡Çüϧ„xŒ³ØÔ¦—‹_ƒºÈ£qåϸ¯Æ-€€=cNöÞ p3£ìõÞ¾¼ÒÝÇÊéøçϲ¼ºÑÎæ)^ ùï„ á¦Ñè -øÄÇbÈÙ…=°Éé-Y'çØÉÃ˽°¡Átz¡»ÕÃÞÞ±©~{ÝO¸”$Ž ì©ÔñÒ—o\G/鯜¹ÁËÈÄÓ´g""òÔÖÉ»¢kÊ -ùÑæ¼w]oÆÆžÅÃÇÈÊÝèÙÚÓ²Íîï×Çɺ§‹×€BÆú½#˜.¢®¬«š“«ÄãîéÒÄÇÈÖ6韄åWð ŠäÙèÞÙÐÜ„¯eÙXÞwÀF²_Q?Aq ºáâΛ—¶Ê½ÎýŒ‚¬ß·ˆ±ÀÄ·ºÑ=°VŒ>YY ôòó[ÙA`>Ý‘Š¬¹®»ÕèãèÜÚƲ¾Ôý'+#Hš¸uï˹¥Çò,#ý?`jzm@»¸Õ&W+ÜÇ°¨¾³©³ÉZÿïHßÈ¢ƒ‡m•w¦Û…o5Å~sMù©¤¬³™taA#?FP1øŸM=Wk9õäέ¦¥ºaÛ×áúêÖ½›r“£ÎÙÙ̱³»¿Öéèʺ¹µ¸ÂÉäâäÝÖɵœ³õCˆPáÛÑ»¡†‚’·ÖàâÝÜÒÎÐæÿöÚÇ®¸ª÷iÓ¤ÕÚ××ÈÆì¼åpÇ)Ÿ2‘.©aMWsªÚÚâÈÂÁŸ·•‹€—Ö͉šÍÕ°­Æ¸™Èµ­´qž3VR*ñÑD£ÆCNêvµ¯°ÍòýöýûýëÎÍÂàñ¶¦Ù%3/ -ûÏ´‘¡Ò#ÿÿ“‡‹ŽèÀÂð(5õàÏÑÈʪ¥â+B;âµ›yy~“ê{±\"X È+àöeòÝúþÛÚ÷è¦];pŽgõÒ Ž“Ó²8úèÞíÈšŠ›¯œÃÍÍ·¨¤´ÙõÝŸº½«±ÏâîöúñØѺ§£ÝöÍÃÀÒµ’šš±ÒȺá×ÎÏÔÎͻɲš -¤–ÖÇØÊ·¡Ð×v®óe u½•wcyÆÊÀÌ®¦ÅáâctÈõÒ²¿äêⲞ¦ªŽ¬¢ßÔ>:HîɯT'wl¼TEàÚ翯ãý ïÒÄ̬vlžä -õɸ¼¾ØôêÊøžyšì)«ÀGW@"ÿÒ½£ˆ“Î3˜t¼†–‡‡®OÕÇ)ÙÞ*ׄ˜ã£ï/”R;HM*1WK6!?r{@ -H9#È•~Ÿõ#Œáଞ™Ž~¾®®ª¡­¹ÔåèîêßÕÍ੯Éè'²×îûöÖ® ªŸŠ™±¦“¢±Ànjå©´¹ÐÚ×Ø̽´ëd{Ý¿ÊŶœÈÈ‚´ÍA€@óÉtY†ÆÂÁ±Š…Ýá«‘ÁìÿóêçóôÅœš¢‰ ÏÏÔE¡-ø$í¿¯V`ruÉ"I>óéÞøâëêðå×æݽÁ­œ€… Ôú# ñýùÞ¿ÏíÔËÀú–:nÛª±ï<O) öäÊǯ„xÂ|ÕA°}Ž™ÉXÃŽáò7¦v®*x̨°¿ÈÎÍìÛÙ, ðÜÏåõµ™œÆ]–­ -¾y–šˆ¹¦¢¬ ­·ËÌËÓáßÕÑØ»¤²Ëæß’·ú(貕—š™‹„ŒŽ›´Â˜‚í©ÌãðøùåÌÒ -e.Ûļ»¡«G¿ËŸ2"CÎGA¡ÉÚ½˜—š¯ÈÔÆÌìåöõ -ü¹œž¯ÁÏÒ¸ õÇ 4ܼbz;…¦ü)ûX‰†dOñõíÚè -ôÄ·º·°© Û,RhS936þ˼ÅïèÅ£Æe+9¢ªÁðíÜÙÌ«¼ÂƈrÞ¼OCŒØ–ˆ›Ó(e]* þ%OT…µ†,Ñ|‚¤ÆÜ×ðÛ¾ÔîúøßÉÚÞý㟣¯ü¾Ü²%ˆ]Û—¬¶®®«®Ÿ¢¤¯¸²®ºÈÏØÈÂÊÔÔÉ×ÓìÿÞÂœ§Â.Ó§¤°³¥ž†gyš­º¹ÀØ þ£™ÜðóößÜï3UÚØÞ¼…¸ož®·›WDkï—Bo²ÑëωÀÑÝÛÙñó - - ðþÏ–’±Êº¡¬r ±%ÙțЌ¥«ø Ø¿¥ôÀ ¿õ§:2D#ç×Ò¯ žÆ%šœ¡˜c6*þžÝÙä˸±ð“Õ­šµËÕ×Ðä¢ÅÀkÕÔ¹Ó)¨‘žµØ0ZS8ôðôÉÁÅ8 Ë·ÎÓØÍÖÛÚåÔÎÄ°Ûý îæãÛÞà´‘¶+øÀ"»óæÕ´šŠ©©³´ÇÒÀ¯Æ½¶¼Àº»®±ÚçìÝãÎÀ²¤±×ùóÇ°ÇÆŵªŸ¦²¾¾»¦ µÃ¨”Ì4/æؽÃîæÖãИ€âþE÷ø°Ä¢^Бax¢ÔïÙ¥§¸Öëõæäÿ÷çíåüåÀ Àͼ¡¿s2sóòùÌΦ -ÈĤÒáÌ¡©GÅÔÇ¡át™>2dcëÚǾúH“Œa$ÿ÷ØÖÖÎÏÎÕÃÎ#jJè©©ÃÅÓ×ÌÈ®‰¡¯”qÀë'_˜†̪¸Ùàç.PPDæØÀ®™•Øÿîåü 乲þµ—¸ìåÒêðêãƶ¬›†¿oª¬ƒ†¨øJ⹧sW¢ÇÌËÞåãÖľ¤«¨¶­®½ÏÞðáºÅ¹–‚‹˜µÈÀÐäá͸¸æñ»¥ž£¢¯·Åßçõ"É¿º±Âß÷ÙÍÊ£„„g‰Î¥¡÷Óš²&Àœ‰Œ ÅÕÀ¥¢½ÕÖðÜâÿ÷ðöõÓæóÜÊÌÊÈÞlYÂ&þļ¶E/½¨Áº­ÀRldÛŒåos¯¬’s<-óÒ&7y[õþëäÖÁÈÝíÙÒç'1 -ϾÊÄ´¦±ÎÛ¥—r¸èRÉà!ÐÁ·ÖÝ<HG»¯¥—£­Ð'-üË°©ª¢¹óãÇÌÖιšš±¤˜ùN$Ë*`ò ‹‚S4Âð±ÀéìÊ ¦¤š¨²ÂÈÕ××Ī·¹½—‰˜Ÿ¨»ËÉÒÀ¸²ÕSUË›¢¯®ÅÙÅ»»Ñ¾µµ¾§²½ÑÓØÝÖ¾—º_–‡²±ß=…š=Ô×™™ÂÃ÷ÁÓ䞢¶ð$>'÷ÞÓ̳Ïüÿòæêî dzùg&>ʹ²}†x礞¹àõ ùX鉦?Wîš”> -ëÔëòÉ¢èdr&÷ýÜÙãÄÇáß¼¦Ìþê³¼šŒéÜ«–¢ª“ȧø‘il岬Íéý3/ñÀ«§»ÅÇÛîÿ õà瘟Š"ৢ°¿»¯­£«°ÀT¢£«áZZÇ‚qzˆžó‰‹ž´œš²°ººÁÙéÚɦŽ©ÁÓãÛÙÒ¿ÑÑÁ­ žÂóEmIÛ·˜”§»ÌÔ»¿ÃÁ ¶Ã½··ÑÅÒçÙ³¯úÍ韻Ճ"suDüÒ»­¾ÙØÕû ÿ²Ž‡•Ú ðè×ŧÈ0 ý3,k§"~6/ðÒÀ½—ßÒ‡±(çÎâç'Æ‹w›á39 óð¨ÄО{Èr·FûýêäòÈȵ˜„ÕÛðëÌÈÓ»§ÅÝÏ—…«¦Å[¦3¢í®Ààëâî -×ÈÈËØä×¹½ºËíñúýç°§ÑJ)àÒǨ®¬²Á»•Œ®óÕáýèûøRL¹…z¹áĪw\h‘¯µ¥¼ÈÓõ·ÓÖ®©µ¥¤»ø42æÎÊݸÂÞ>+ íÖ½ÇÓÊÃŲ±¿æÇÂÂ×âÊÍŲµÏÞÚÍåcT=œÀÏ%ÀOdIN*ýÞèñî'öíº¢Žh8v¤ÐÝûÿûáìArY/6<4]Çd-Ô§ÀÆ[A"—yÙ½ÁÖÁ¹µ«½ÛØ´¼Ëó¿“„šÄ½‘Sˆ`öÃwJ(üîÞ¿³˜xy‘Âë úݱ›«´ÚÊ–Ž”¬¯3u•sÇݹÁÕǼáéàÚÒÐÖÚÅ­œ³õ òÓ­¸fGóÒÍàæÆœ–Ÿ¶²“Š¹Bw‘[v 121´‡x‹»ä®°Œl†È÷àèæá×ĵ§ª§š ²½ÁË/mYîÕÌÑèôÉÁìáÏÚ -âÜÁ§¼ù=gLøÑͽ±²Â»ÅÞÚÕ w–§Â)îwqpnM3 - .0ᢀvd[5DÑ&33Sz|jP,B?SÀ»()çŒx§ðÒÃh°¢õ#ǾÝƦx‘ÀÙ׿¨±çß©Œ•µÈ¸‰Lwy•Äi¿,ÝÌǾ³žz{¨Õ D0ѱ¡¤³½¶§š¶'NÉy¬ ÚëáÓ¾ªÊûòàãÎÀ¶Á»˜žÈ"îÅ¥ÀÚ"<Ú¼Äà⹎Œ°¯»±¹ã¦ïûìÐ.j=÷Æžv•¾Àˆ¤ÉÄè õãöÛ²«º«žª°ž°¼ÇÓP6êÈÆÏë"'ëÅ×èÞ¾µÍ8íÎŶ¦Ò7÷]ù­§©ª¤¶ÐÍôëãqœlŠ€…Æ>ýtˆ©‘waB ùô'U@êœv[YYEDšõúþ2G†žbLWfERK#A¿¤àg\Hö¶äößÕ®ÝòÈ¿ÉÒ¦ÊÏÌÚ»¹¸ÇÃÆÏÞàÅŠ€»Ô=ÏVB9®²ÊÚÏ» ª×ó#8ôѼª¡©«« ¢¦¶)ü#ÇY7XôÜ̳ºÙìó㻶³ÏãݺÀéÉœ ÐôüòïÚüêàÈ°±ÊǾÆ$2^c…(w-ÄãÉ’ˆ—ˆ“¦òÿ.h`Ʋ³«©­ ¤»¿¬µÇÀ»ÝâÏ×ÉÂÃœ4òØßÔÉØá÷ûÓÀ¨¸¯«Á8/ª( «¨°¦¶ÊÖÜÜ-!²Úó9kÈ%ck}vƒlþïÝôOK齇‘Š”ÝñÛù"RŒ|D(891g€In´…×€ŸÙ³k9Á<IL¶´ÚçËÈÞÓ¶©¦°°³ÍÅ­¡ªÊ¸Sà}הʢÎê îÚÏΫ¤ª«­´ÖðßÓ€ |‘„2üâÝÄÇÉÊÑØ´³ÐþíÀ¸Ýô³”²ÎääçôØÀ×ÙÜäÞÑÉÒ¾Âà£áÜÖë1A¬u̪}€~—˜¡¶Ôî€Ãj皧´§“‹§ÇÄÃäÒų³²¼» ¼.±¨)ÚÙ̹¹ÖßàÛȧ¡¥°§üÕjº¾Æ··Ìåݿա¾YžÒÿƉ‡ó6:lœ©0äÐÐÞ,3! øêáS.úõðH_A;,5;J‹»µ´£-ãÙ/,°wⵓޠ±Ë·ÁÞ÷æ¹¢²°¹ÚϤ†—èI\äÔ­¸8¥>·fjÔñ4E@ñÇÕØÚòîéÛ¿¸²µ¿ç.8àê4‘›6àÏÀº­ªÈéïÞ×ÜîëÞÕ·è"µ“¢¤ÊàòèëáÒºåóñíáÛÊÞFOf->OQXÚÝbÇ“de‡¬£¨€‰¹ïy壜• »½¦{ˆÂÕäúê;·¬y|´?<Ô®³ª­ª¨ËÎá²®¦œ¢±³ösÜÉ!´ÙÝÁ·Íîïâ)ùþúÔAk#v cj¬Øº€,ï×ÔÑÕìôÚ2àêÙç* îùûP^UYyŽäé–ÿÞgɺž…3ü°Q±‚¨¹¬ÅãíÌÚÖÙÊ©¥¼ÝDzÜ«†–0ÏSàŸôšOñ ùÈ¿ËÙðþäÕÏÓÜ×ü*>%ÝÕö()@¬Ò*¶–ª¹çèǽÎóá»Ííµ šªµÓÚá ãÍòù÷úíÆà¤Î´ÀW…Ü“@™gn€„‹”¬†u“×;Œ\ó˜–­ÈÕȲÌâÊâ÷Я†v}¥ÌãéØ­­²¶´§¶ÍÒÉÄÄÐÕùùÿ/vqµ½Ó°Ÿ²à¤g,Ö2A)ʹ&—¥ãêªqEH5ÝÇÛÖûó‘n‚…~o‡ªÝïøø\¤—do`œÏa§T«Œ:õΦ>ï¹E²Ë×g’‘šÙíüÄ®ù8J‚”Kð°Ž|€vì¼æRí¤ ðÌ×Í°¿ÔøööëÎÌÀâøAB ¹Ù!)R{Löª|“’¥Âìòôþà»±ÐßÝ·Ëà຺²¯¥°Ìÿ1P1$  ÷íÄ­,?ó*=."Î’îwZˆ¬uWw² ¥¤´êôÍÄÊ¿áóôæŶ¾Ç¹ÑÞÀ¶¨­´»¿ÜþÜ ƒ §£´³µ±Ñãê>0öêH'Ĥª•ªÅåö=âΚ;Ï";,'Všøë¢|WVwh0ÚÇ×ÙjV[.ûüVÍ$~ÄÈ—c@S–w”3Å©¨4á”ÝEOqv€¦å  -üúôÝ),:~ U×z´ÐpšÈ)ôÒ4ô²š¨µ¬¸Æã÷ðÞóëÓºÒÏïWb+åóÒØ -4̸¨«µÅÙèñøø½ËÙÑÃÃÇðúή¹¿«°É)l» j5$ -ã­Ÿ¹šÑžZÂTõZôòM”n|¡œQS¬ª¯ºÉæõÜÐàÛÈÀðñÚ÷º­½´Ÿ‹¼ÌØÙÜõýâ©‹•©¸Á©š³Â߀™EðÕÈ÷bo󫨲ÍïL$ï‰õk›W KœÉšlojm`‚©cÍMùG[+ñÅö?g³ò±~A8‡Ù1KÆ¿… þ 0àYÿÅRÑà꓈Š²ÚõûðßÐÆÕéêÙŠÍ‘¸•œŸçˆ˜’Òwš¨À‹„´ÒÉÄÝãáé&$þϧ§íVwåÕåÚ±ÁÛîڼǺ²º®¾ãáÒÕÜÕϽ¸¹âëÕÆÃÄ¥Ð6‡¬’y`A²šœOkòÔžµÓ~‚ £‚fŽÁ»±¦°ÙúÙéáǧ²ÛþñêâÕ»²²­€„¤µÁ®¦¶ÊÙÚ¯©ÂÚÆœ§Ãåð+z|άÀ›£+ËÆØÝàÚ¦€Pø¯@.ïïTǾ8÷x‰ql_vÐ+nåEãÐQx@ñF], y@¯9%m¹*ú¥y\ñÍÏú& ñµ8UJ—‘®¶ÌçñâÅÂÊÌºÌ šðÁbÿåÞêH­O‰oÙ/ª‡y…—·ãÓÌÝöäûKHûÇ«§ïV`×ÜèÈ’·ñüÕü­¤£½Ï¸Ðïëà×Úé -ïÉ«¶ÀÑ>#9NGωàŒËº©ÕˆûÌ iʶŸŸŠ¬ÎüŸƒ‹Ø"úÔéÜÁ¬¾Øñäéë¹»ÈÀ´•€v‰”¡¬©®Ãåÿ þìÛ˱¯Ïç -:Y-⣅—ôƒ¹`ûóÖÏ!rù­H3øÿ™ÏDŽˆ%‘|YT¶^’ÈÂ!äÔè -NgN) -/R ¤¯°Æ`¦ *÷rÀÁñ0 ¹? ân¾¿㮺®¢ºãäÑÍÒÞà7ÀàŽC  0Z‰£†¨‹|xŽ¹ÐÒÈÉåûíÙ_(δ·â%n6åññÒ¨¡ÕóŨ­µ«Œ¶Öãèþûø÷ýãÙÜݲ£¼¹Ó  çêÓ¡†‰÷  ‹aÊ>´VÁ¨“yz£ÅÄ· \ No newline at end of file diff --git a/build/lib/WORC/resources/fastr_tools/elastix4.8/testdata/input/slice091.mhd b/build/lib/WORC/resources/fastr_tools/elastix4.8/testdata/input/slice091.mhd deleted file mode 100644 index 1e68f3e0..00000000 --- a/build/lib/WORC/resources/fastr_tools/elastix4.8/testdata/input/slice091.mhd +++ /dev/null @@ -1,13 +0,0 @@ -ObjectType = Image -NDims = 2 -BinaryData = True -BinaryDataByteOrderMSB = False -CompressedData = False -TransformMatrix = 1 0 0 1 -Offset = -67.6484 -265.368 -CenterOfRotation = 0 0 -ElementSpacing = 0.703125 0.703125 -DimSize = 256 256 -AnatomicalOrientation = ?? -ElementType = MET_SHORT -ElementDataFile = slice091.raw diff --git a/build/lib/WORC/resources/fastr_tools/elastix4.8/testdata/input/slice091.raw b/build/lib/WORC/resources/fastr_tools/elastix4.8/testdata/input/slice091.raw deleted file mode 100644 index 66907f6a..00000000 --- a/build/lib/WORC/resources/fastr_tools/elastix4.8/testdata/input/slice091.raw +++ /dev/null @@ -1,190 +0,0 @@ -m}xgt„„yzŒŸ££’•Ž”’„‚œª¥„v«ª­ž†pz”™”—£ŽŠ¡¤Ž‚™žžš~ˆ{|xvix‹£œ¥—‡¤¾²”Œ‘Œ‘”¥£ ˜œž˜™’Š~€“”rs|”—‹‡”’……s–ˆ†‰”“ŽŽ¨Ÿƒ¥¶§°°­©ˆgoxŠ˜„‘›’}vm‡²£ƒ‡‹‡‹…Š•µ¡€Œ¶®š—œ£™˜˜§ “†€’š”–¬²»³µ±¡¥À¸ª²¯œœ’„”Ž—»Ê´¯­Â±¦ªš–žŸŠ`¢¤¥ €wƒŸ¾«€~š†Ž¢¯©Œˆ¡§–’“ ·±–qu—‘t‹|mmltˆr”–”‰z¡›Š‡‚‚™©’pmˆ¥¦­˜|…‘‹Žœª£Ž‘ µµ¥¢¥ ’Ž”‹Š~whk‰¨©žœ—‰™ž¯£¢¡|z‡”Š‰†|†‡}|ˆœ„kƒ˜}ˆ–™› {z‚ƒ”’˜™˜„Š¢œ‘¡Ÿ¥¬°¦˜¤¡‘•’’rZllt‹“‰œœ†vo’»ºŸ——‰—¦•‡„‹›‡ƒ~ƒŸ¨ž– š‰ˆ™£ —ˆœ²µ¼¼­©¯¿°¥¡°–”¢©¢¡•“’š¬ÆÌǽ¯›˜¡•‰‡“‚rj‡¡¶»–‘”³Éµ‰ˆ”˜‰Ž¼Æ‘ŽŸœ ¢•‹†…¢­Ÿrzšš®›¦›Žtel†…‚–œ‘Š‚—®‘x€…’¢ytsz‹¨‘‹vŒ›˜‰ƒƒ–©£‘‰“š••¢£ƒpk€†ŽpxŽ“‚…›©©¢}dfx‡‹‡‚‹zy‡ ™Œ—¯£„”™–˜“‚lky—Ÿ—•‰†Ÿ³¬¦¥ª¡™•™¦¢Šƒ‡„wŽ•ž¤¦Ÿ¸Ç¬˜–«Åꧦ¥ª¿¾¢†‡’š››­½³£¸³©œšŸ«¼¹“‡‘²¼ÈÄ´°¥«Ÿ™¤¥žŠ–­§’”§®¿Óƽ·®••–„‡†’†n‚–›¤ÂÆ©””©Å¶“­ª›žÌÈ‘‹•™³ž€‰Š©´|Ž˜Î¶ ´¦~jx„‚us}‡”ª–v}|~”ž‡x„‹|zž—“™Žƒ‚˜Šƒz‘–’˜™¡˜—”šŸ¨šŒ†€w‚—“‰€„‚’•¤\_hxƒƒ‡—Œ‡ou†œ™£¬´©…p{‚ŠŒŒ‰vo}”¡Ÿ¦¨¬¿­¢ ”“‡™ŽŠzƒ”™ž­°¥µººÃÂŽ»°¬¥¾Á«®¬¤©º ”¢°£¬°¥´À¿Ã¨–ª±­§°›z…ŽŸ´®©±¨’ˆ~z—¯ ž‚‘±°œ¤­­´Ð²˜¥²¦œ–’‡˜Ž~ ¹©©¦§¬¡ŸÀȽ˜šª¨˜¸±”‹œ¬ —‘~vž¹¥‰ˆ Ë¿µ«–€†Œƒ~……ƒvˆ‡–¤§…tvwŒ—‚vŠŒ„pˆŒƒšƒ{{ƒ‹‚‘{s|‡ˆ‚‰†q«±žvgƒw|~‰“‚‡˜wfd}vƒŒ‚‡Œš{›‡¤¦“‚xuƒ–Ÿ˜’‡•…›³¬¸Æ¶³¹­¤›‚ukv‹Œ’Š‚xŠ’–£œ›°¬œ›†x”¯¤«••š£””š›€‡¡¥—›£”…—œ‘~–›Ž•¥†ˆ‰šš—›yxx• ŸŸ‰yˆª™‹‰›¨¯ª”›««§¢©–›‡ª®™©¯ž•–«±³–ˆ™˜š´±†…ŽŒƒ€Š¦¢ŠŒ†Œª †„¤¯­¢‡twŠšŒ”““ˆ–›Œ˜–|…“¡ Œun{ˆƒƒmŽ­£Œ‚‚uwrcy†‡˜ˆs‚’Ž€v}rx{ukv”“‰‹{€x…~‰Œ‹š”ƒw†vx‚Žˆ‹‹‡‡™ª¦£§·¥›¤š”ž™ˆ€„„ƒyvn„ˆˆŠ‡{Œ™‰€}†‰Ÿ–ƒ‡‡x„œ˜¦§‰†’’Œ‡€‹žˆ{¥’”š“‘ˆ}’¡–”¡“‹—’“Ž}ˆt¢–ty›–•…yq{ƒˆ…w‘––£¡œ‘·»™“Ž‘£…ƒ £ƒ}¢ª©…i–|‚¦šyy|Š‘zo–¨£Ÿ¤›…˜Ÿ•~…‡ ¨’}€†‡‹‰„‹’«›“—Š|Š~‘œ¤ŸŠ||”™‰znz‡™²¨‡‡™Ž™œŽyq€Ž“‘„Ž‹›Š„…€†ŒˆŽ¡´«“Ž…‰£ ‘”™–ª¢˜Ž„}u€ƒ•‡…†˜¡ £¤š‰‡}€yz|€Š‰ˆ~‡…ˆš¯šƒ†‚{…”°¡”Žšž¸¾¸™†€”Žy{¦€¯«¦˜š£ž¤ª±š‹‰”œ––”‚wy{­£ˆ‘}Š˜Š—˜™Ž~}‹¤¤¡•’¡Ÿ•‡—´¢“„ƒž¦€mw“š…q}¡¸¥}}‘ŠŒ”’zŒªª„„«¤ž¨¸¿› ¶±š”†ž§ž¤Ÿ‡†’Ÿ„}’ªœŽ~sir}{„—¢™ˆŽ‰ƒ…xwv—§“‹§¯§¹¶¡Š|’š›š•™­®˜‘Ÿ š¢Ÿž®±¬ž«µ¸®¥ª¡¢¢¶²•’‡Š©§—»¾«–‰Žytsywyust„ˆ‚ §µ°¥Ÿ˜˜—‹yŒŸ‘xu}~Š†•’—¦±« ¹¥¨²¾¶¡žš£­£•¦¬“”§³µ ¦©”ž¦Œww›ª£¬œ€w„ž¢¦žŸ¯¦ˆ˜¤¤°­š—°Ÿ—§©˜”Žªªž  §¡„€Ž™’}t‘·¸›™ŸŒ‡•’”£¤ª³ž°¿À²¢¾¤ˆ|—›• ©¥¦®¡˜—–’‘¢¯§Œƒpu„ƒ†– ž”“™¡²¨¶«¢ƒ„˜ª²Æ¿±º¬¯¤’Ž£©£…¤± –˜¡ž›š‚’­¶¤™©¦ž§ž§›‹}r}|q‰Ž‡¤´—‹¦»¾¡‰Š‹wso|” ™‹ŽŽŠ ©¶¬®¨ž”“yrx“…|}†„~›¦Ÿ Ÿ¡©´¦›”š˜—Ÿœ’£°Œ†ˆxzƒx€t|‰ƒŽz|§ž£±‹bu€¡š‘ž²¤’Œ…‡„™¬¨Œ‡”¢‘€’ ••“©¦Ÿ”¡›‚ƒ¨„œ‰‡€«¸¤¦ž„ƒª«™”’‰”ªŸ‰‘—Ž“§±}rš’¡˜¦£–™±¢³¿½½­¦¶®£ £’™™«ÈÓĵÀ²ÃÔÁ³·«–u†›¹Å·®§¥²–ŒŠ¦¡‡‚’£²·¥‘“«©žœ©©›ˆ€„†‚€‰†‚zqilmk€{hu“ˆ‚…ƒ’œ““™‘sˆž§¬±©ž’§¥Š…€‹ž—Œˆ‹Œ{ƒ†‰˜˜—’‹—¨¡£©²¾¯ ¥–…{tˆŠ…„™˜ˆ~‚px”Š€{‡Ž–“¨¡†’¢u^czžŠ’ž¬—•š”yuª´¢†œŒ{v‚Žv’™ˆš‹qˆ –¡Ž„‹Š†“©°°›¤¾À¥…ƒ€’¬•~“ŠŽ›­¤“‹|·®£œ¢¢’—›­§½ÃÁ»­¦°°¢©¬•ˆ™§ÏâÛ²š—¥¥¢••—‘‡wmk»¬˜…‹•ˆ‹{‚¢““•›¬©ŒŽ¤°®¡YPN\j†“Ž|rqvreudYlˆ‹‹€€{†Œœž£™‰’œ©¤”ˆƒ—¡‚te|šµ ˆŠŽš©žŠ…€‹Š’—’‹ œ¥ŸŒ‹–”‰€ˆŸ™‘œ‘“’‚‹‹°¤™’¡ª¡¤—¢ –…nduŒŽ’•™”“–Ÿ™qŸ´Ÿtu‘Š~zclƒ„nz•–žšœ”–˜¤œ¡®”‡˜›’‰¤º«™¦°¤‡€…ƒ¨¯™˜™Œ{›­–—¤›Êº£™œž§œ“œŸ•¦­‘ £–›ŸŸ˜‚ƒ’§Åµ¡””œš˜”†yn~‘„}wv|‡Ÿˆt†”†„€ ³ª¬“‘Œ’”Ÿœž¤›Ÿž™Œ‹Š‹€ˆ†€yˆ™—š˜Ž}‘~olu„‡l^m‡‘Œ”„¥«ˆ…”šœ®­¡ˆ†„€|‚uiu{‚‚†{y€ˆ£›™«¹°«¢§¤¥‹|ƒœ˜”……ˆp„ž•’Œ™„~ƒ’”ut{‘¤¢ž§¢§œx‡Ÿ¤ˆb\{‹ƒn~xtƒ“¥‰‰¥—™ª¨‡ ¢‘§¤™ž‡†£Á¶¤µ°“…ƒ––œ§“¨ž›~†’†…––~³´»§’ƒ†ŽŽƒŸ‘‰’ ¥«¤‘‰ƒoh”¦§ž”˜ƒ‹‘›—ŽbiŠœ’Šzlt„‡mh|y“—«¯œœ¤¼ÁÁ¿º²£š¢œ—¨°£¬­Ÿ‰†’—Š ¥¡š‡nu…{omw{}x~­¡†‹”‘¢¦…‘‰Ž—“…}™œ}zƒ“zƒ‹Š“ª¯˜ž§¤œŒž«¦˜“¨®’}gYN[ktxyx•ng•—‘‰ˆ”«§¹¾­’Œ©¤‚˜¶¯¨‡všžŠ‰¥šŠ‘ž™ƒp–³›­˜ˆš£œ—‘£•²¼½´½¥‘w‰ŸŽ¤Ÿª´»¿®› xt‰„Š—“‡±«‰nu~…’|uŒ•œ¥˜“š¢•‡{zs{‰‘†‰ž}„•™¥©©™|˜£´£Œ}}…„‰q…–š„•š«¦“ «­¢¶«£‚|’¥¦¢­´¢{X]Ž~pŒ”ŒŒ”œ„™«¢”ƒ Ÿ¡£ ¡œ•š’”œŒŒ’‰“‚}‹”—›šŸ›­ªž‘˜›šŽš¦™‘”Œ…v’”‹˜¥«›’Ž‘“‹—›’—«’u¤¨±œ“¡¹¾²Œ­°¨¤¬¸¾·¡‹Ž‘¦ºÌù§»¹™z¦±«©’–œ§µ­‘—¥¦¡š¦£Œ‡–ˆ­¨¯ÎÄǸ¸É±‡ ¨±°…†–£–|x“‹y‚Œ}rm‘—¨˜mRdroŠ‰}‡“‚zƒ¡ …wŠ ¦’–­§ŠŠ“¨ª”Ž¨­©†“  –ˆ“ˆ ­•„yŒ¬—‚ss…ž–ž©¨žsyx~„¬¥‹€’ ˜–”›¯£|Ž’†›ª‹„‰…‡‚’’’¨¤ Ž‚~ŽŽ‡}|lm„–‘‹…–“’u~zl‚’Žš¡¯¸¿À¾¿µª£˜½Í­š˜°Á´¤€ˆ£¨¹Ç¿¤«»¡¡¢¬ªœ¨–‰…‚ ´Â̺“™¥–Š…€‰€ˆžŽ„zfu„“ƒˆ›–‡•‘››†¢©­ÎßÀ·¤¸Å°•ŒŽ´½¢‘‚Š‹’¡›˜‹vz‡ˆ~|…”•”y_HK_†Š™˜€gŠ¬˜ˆƒŒ~z“¢™‰­° ¦ÇÆ´“ˆ£¬›~‡Šƒ„¥©“‹~Š…ˆbc—–£©¦¬¨š™Œ–±³Ÿ—›š‹n—‹z…„vds˜^bix‚‰~uz‰‹‘—œ–š˜Š†qqr^YWdrv€Ž—£­©›–’›™«¶´§¢ ›™¸º¥˜•®ËôÓÅÃËÔÖļÇÝåáÜã̹ÇÕ×ÛÛݹ®«±µ´´·ÆÉ®sjŽ£›|gl||{{‡liy‚Ž”¨Ž‹ˆ‚€—Ÿ‘›œ–š³Å¼±ª­·½±Ÿ‹£¹¤u}ƒ|}„œ–ŠŒrax”ŽŽ~x„¡›™†xicpŽ‚}•±‹rrŸ¦£›ƒƒ~v…Ž§³§Ïǧ¨¬´¦‹vv‰•˜‘—’Š–”xi|u}|}{ƒ‹ƒ]nq{‹‘†›œ„yy~‡ ¨«Ÿ€wy”“™ „q^xŸ {^z™–”‘|‘šŸŸŸžš˜¢—”•­¶¯«—¤¬¥ºËâæãÙÁª¢¡«¹¥Š’Ž”®ÃÁËÓ½ÛõàÝôÿçô åÛÎ×  í×ÜïüøöáÜö µ©ª™}€~†šœ’“Œ…Ÿ–š¯ „‰xz“¡˜©ŽŒœ¡†…—š£¯­ ¦©¦¥xqƒ™šŽƒ‹Ž•…‚˜¢§­£’“›Ÿ ˜x{~™›–œ²¹©ª®¢¤¥œš•Š––ª¸­©«“€}ˆ{w}–œ´»¶®Œž›|evwƒ‚Š™•–¤•x…ˆ‘„€“ s‚›Ÿ…™°²‘Œ‘†~Š‘£˜ˆxe£š’„˜£š¥’”‹˜‘›’w{–—”²ÚøðîÒÌáêíè÷ -îûèÈ¿ÔÜÌÌÂÏ×æ%þ 2"ñûù -=;63$æßÜǺÙèèô % ÜÂÛçÝƸ™ˆ{„‹‹¥±§ªš’”¥¡““§»©’‚yˆ‘šš›œŠwŽšª»®Î¾½Ñ­‡tx~}}–Ÿžz{Š’›†š¤™¤®•ƒŠŸ¢›ˆ„„››˜œ²Ê¼Íϱ¦¤¦•“Ÿš”˜~vŽŠ“š”–Ÿ›©°·¹Ã£š¯·¤Š–§°«¯« ³¯”žŸ™–™¬±¸›ƒ ¬ŠfxŒw…‘–†{„™œ†vŒ‰}ˆ‹’„†sovwy„Œ’§»ÉØôíðýû - þÿ "#$*1þ$úõêìñ4+îÖØÍÒ¸ž¤½ØÎáø "3,àÏåíåȦ—„‡Ÿ“œ¸¯›‘ˆ–£ª¤˜‡›¤•‚…u†‘’œ’}‡—¶Ã¯³Àº¾ ”¤¨Ÿm_xˆ{‚…{uxš¤£œ£¢¦š– ³´œ’™£È˸ÂÓæØßÝñáØÌÆÍÉÈÀÄËÜÚæÚÌÑÉÏÃÈÙȶ¼´©µÊ½±Í¾µ¬§¶±‘œ›³¿°«ÄºŸ¦½¹ÃÇœ£Á¿«§¬©¢œˆp‹®ºœ—¡´º¤‹‘ ™žª¢™˜Ÿ—’Žš¡©¼®ÆÝ÷òú320:,+).8>HA2=4,' ýóñö"$ ëúôïáßêÜÞøë³½ÈȸµÊÚëþò÷ì#23<&ýÖÙèÝ©Ÿ¿Â¶ž ¡–€“—•¤¢ƒ‹’z†¨§•”Žˆ„‘™ªŸ’²¿ªŸ´ÂÊÌ”txz‰‘žš¬¹ÆÁ¨­»ºÈäûæÙæêûëþüóú  "5<Þàðþíì -!õïÔÞÖı§ ”—›‰‘|ˆ¦¶§µ®•–šž±¢¡¹Íº³Á°¥µ§Š—–§“¡­´ž~œž—ÄÀ´´¿»­Ž’›³¼×ãþ  09CKFAJKCFIHGB9=*(*ôåàÛÒÜ÷ õñøòûû÷úöëëúþý15!Nb\X?*þïܹ¶ñðÊŽ‘™™«®³™…Š˜™ŠŽ¨¥´¿­Œ‚ŠŽ‚˜¨¡¤–‘“ľ±°³ÀÆÇ©’…“š“’ž®³Èº»ËÕêÝÎÝèòü0"û &'*373<6>8991+,>CB<$+%46" ðüøÙÀ¢˜™„‚{p†“Ž‰…‹Ÿž£©ª­žˆ•°´™Œ•’xŽ–—˜‡st†•œ…}~¢Â¿µ¾Úªœ£Åéü73!,1$#$'$2IN<DXWW>94 üÿ '-2&,)($)"$7;4<7956>]iY?,Or^D!AT/ùðýƤ–žž“—¦°¡zsƒ—’ˆ‹©¼Âɤ†ŽŽ~•ºÂ°|…¡´¿¸²³ÆÝÒ»¨šœ²ÀºÕòùúùìèëôýðããäèô+ö -!(/)4:--<EG1'+/5=E3A[mcUC-6<<2 %&'%?5ôçÙ‚Ž— žŒ–Ÿ«°—ŒŒ„vƒ˜˜€zqyœ¡ŒŒ…~€ˆ£´®‘€¡ÊÎÁÑðßÉÏØ "[inEøÙÏÝîöB7.8?>-7@MM9;>&%#(:DG?Wql>EWI:;@5*AIScp©ÁǼš‰s|~\O95fkT4/SkZ0%IY2øĹ»¶°Œ•—Ÿ—yr‘‘’Š ½»™xˆ««¨Í¦†“‚w‘ ¹³¬¿Ô⵹˷Óï ÷åãæðõîæØã'!*/&@J! +.%$4>.ìçßèü!+BTK! à· –——§§v‡‘›€{ŠŒŠ‡{m^{——Œ™¬Ÿ•š­½ÓäÒ°Åßêðìôïßæ"'QQM$íÓÀÁÜõü7X]8>E3-02Ngr`H2GUUKVeij|nZ]rh^]NGCNY„»é8£×ºs¿‰u^RWPIo…\TKVh|\>a}gEÙÈÍǶ¯°œ“Œœ…Œ‡¢³´Ž}™±µ¥›œXU|zw‚™«ž°¼–~Þ -)$  ûøöòñôùìðA5&+8C5!2<3;DA(  õÑÀÛÿ üàÙÜçðøü/:5@>ß¹’“‘–”œ©—uyz†–šœŽŽ— —£ª¨°­Ÿ±·ºº·±‘‘§¡§¦ª©›”§ÒìøøéÛÕäÿì÷ðâν®«Äí/RbcZRQF?R[yƒZVCQcWNf‡—ŠrgYVtcz›ŸŸ—Ály³H ‰­™`VS]u{;)MWKA%Nk^E;1ÿèàçßÜ»ž˜”©ž‰ssš””¨¨€‹‘‹¦£Œfbu–“ƒ{—¯ž§Žˆ)2  1AD<@PH8+'?auuwnj„…‡odfylG:@/ÿñÞÈËÙíéìýþýøöè ÿ -ñÛ¿£Š}€…x€––{…•š¨©›“ ©¤ž ¹À·«ž š‡‘•‹““Š…””„w™ÃÃÍØÏÎáôæ××»½Ÿ§ã" )N_nxfYdioy‚–qr\NgXNp›» {YX\cl«å..$Q¼ÝškS:þÖŽ[ˆµšueuxzf6:LF45Z[ZZQRE@DA'ò¶¨°¨§‹q_m’•|q¨‰›ˆŠ¦¬}€sŒ™¬€—œŽ„Š—øý 'NTXZkqqTZWNXfŒƒ“§ËßóóÔ¿™r{†„gVBFTXCàÞæìþ÷êÐåÜÎÒäðí  âò+&$)" ñ¿§~„~‰Ÿž—‹€–¢¡¬¬Ÿ¤§¦Ÿ‹“•Œ››¬Á¯–—œœ­ ”—Îݾ¿âôü -û㬼»¿Ô(ST\dq~Œslzq ÇßͶ×ÅŽ~pg“¿íÓ}S^ab’á0O|Áìú5â>̃XDS57sÄË™ˆl]n])@aY[ajdqƒpt’¾¨‹vC˧´­’|yuŠ£‡{{ŠŸ£±ŸŠ ‰s•Žc{š©¥–ŸªŒy–­ +.,@8/&198XbcXQVbbZRaq›Ìô>žÜϤl É xbhlzpXE?IZFý ëáá϶±Æá -ìÜõù -úø *õîϲ¦¢©›¢¬˜‹¡³±¥¡¢°£‰|~‰˜”‹¥¤ƒˆ«™˜©®š‘µêðÀÓð øûøËŽƒ•¨·Èï Gn‡}_fvyoeijr²=*1˜Îw뚪ÑåðòÍbXfÈ*H.K¿N‹uï<Π|‰˜qkœáÌ‘f?KcQ:BMc]FANb~›Êö×¹¥œv#Æ¥Ÿš—«¥ˆ„‘ˆfx¥¬¬§’”‘‹•|rsr §Ÿžs~Šž[RO[MV\\H<DIHS]P>>UbVV€ ÙLÞ‚Ã$°;ˇk`W@QVTNDFioM242A/ýÿê¿À·®ÙõúïÑ¶Þ  0ùÜÕ¿«££„‡¬¹œ‡™Ã¼»³š‘‰}sxƒlm–§«£³«©Æãëú) þøÕ­œ«º»Àå+]r}z`VpcI,<ZŠÖC…tV£A&iÓ´Ê´¡Åóâ‚d›5±rþd*Ž{<î£|K%ðØÐÑ“S$(<>@HDKY:%+;j¥Æ²‹’¹­‘‹ §³’±ÕΟ…•™†ª¼¿·²¦‹”€‡™‚er‘¤œ†’—RGhufUcm_OZ`TMUYSJPa–£µÃÛlÊûÑZksmb??KKGCPkƒtS:32,/.ëÒ¯¦¼ÜA7óÊÀÒéÿòêýê̳µ¢‹ƒ›˜‹tyœ¢®Âª‘›“vmhx‚ƒŽ±¶®ÐÛë#Zc’©»4þÇ‹Ÿž’›Ð -!IVYec\>).CÑ8 ž õ%Ûš•‚~¼èÜ•c»‹—gµ!èéÓÓ¦m1ÛÃŽ]+ !2!)'->))+s©»ËžrAJTGXzŒ•}²¤ÉÊÁ¥“…—Ÿž«¶®™jwx‰’{‡„‘|‰•¯™‰Anz„zietigrqbb_eenv¯æÝÀ¬óþ˦j8)CYv‘x|~|pVc€q\8?D* -ïðÞÑÆÊû93Э¡ºÈë!fsueUF "#㶳 Œ‚–Ÿž“‘‰kv Ž¡®”rkt¡˜¢Ãæ]“¼ã ;Z\>¬Ë…r‘‚x¹ .+=;%)IE</"AQHxÁ+À b-ÍW³x‰ŒŽ¯¼²ˆfýÎŽ¬‹‰TÁFûìÜÊ¿©¥™”ˆs^/ " -/:W®Ó˧n:4Sd\m{†Hå½¾¯¯±Ÿ°£™ƒ˜®˜smvvŸš™”“€–ˆ˜š‘Zkowy`e„Š…x_gqyr‡´áô¿b7461% ðßû#i¹ñ61 Ñ¥zM^ow~h<?MA&êãØD:ýÑ´©ÖÛIJ˜›¥ªÿ“WxlC -¿’AìÖ»ÂÛßÑÙÖ¦}œ¸¬ÀÖÖßÙÚÑú+X”Ì>~˜‚Z, ŸÞ™pnn€Ê@Sp_NZn\Q]FDje^vº•÷¬Mž’ïnJh‡{v^XVUdѱs‹^à1¥PYga^grfebfdB+((08<9;h”Èêã–U?M7J€ƒn„†qKîν¸±¸Èª“”…|‚Š—•‘¬¢››‘rb‡…z„zpo„’…w}‘—›x^\€‰‚ŽÃíÆ‚[9÷âåçèíéÝÌÜå$¥BÚd\¦Ü]bS9E[B.,3+öÞáN<ýÔ¦‰|—«¨£¨¤° ë+/3?ae0!ôä¼vF//-òîøìï 4Xb“Þ&7FEG7 ĸšwlˆ¨iÆ”|{x˜ÔRp~„•´±†a^`QZUUU]“í0  Ö€fpvz~kM[yxmr»hnH,FZ^TP^WcYTcSED";VqZ)!b›¿Íùà“a{og‚„{xpU55ìÔÇÄĽ¶¯¨}˜®²¥ž–£®³››vWX|œ†p‚…Š„{y†‰a<@Ydjl`_y…™ê -¬F -ò÷"½äèØè»*p?=M?NaSH4õëÒã -븘—wTdƒ„|‹—ähž€z µÄâ#'0ØÃŶŒ_QPF3-=d‡¡È$\[OG0ßͳ•~_+)G`v’Z©‰’¦£±í'Ve`j™Ç™T26;YMFCGEqy…‰|{{‰›yw{bia\Š£„G,/:LQ>FNTPNVF9=+'@M-+{±ÇÐÓ°[HMGD#1TG3-9üåÕι®À»µ¦¤®°ÀºŽ‘¦ŸŒ‹…ksŒ”~˜‘{{j]^V:"8DY]X8Ep¬(WÖ0êñKX>+):RipoU‹û«fÞ6í!7A;.'ÐËÅÏð#Þ¬ž¢‹jep€jYk{žóS„oH+)9i ª£ ¨ÅÒÞ !÷èåÝèú "B\|«–J×¹‡UCB<<B43@hšœuØ©|x©­Ã/VYJO†³¸—T=9Y`WR[]jtbL[hv}uuv€dRE1%)4%/2#.@!+&  ùöþäÔïGw—Šs)ßœ`C*&‹âÿ  ïèèÍ°œ±½Â²©™Ÿ´±˜vwyuyfr}Ž€si_RNGGSC5:7'60(*f¸=€*‰;²è'2TŒ’Po»ñÎýyTâÙÜßìþÞÈÐåò¿¹·‡^Wiˆ„gi§ËnAäê 3NSs~…³ã@F/$ ÿîÝ°rP5  +<@)(=h†¹¡5׺­Š’¬¼ÒK_cKFn¦°€_YlhtslLCZmWHL=BB1 þëÕäæçóþåâåêóôãÉð"ææîÔ¦™¥‹hg]4.p«Àá"û˜%ˆêÊ¥™ÕsúK”±ÅÅÓîíÓ¯­ÀØÊ»±ˆŒ¡¨¤|kbˆzqykd…t\_QJ88=?Re`E."+0-+:e¦âÝ°|‘éXÉï -242ÃW³…¬ÃÈà1ÙÞòò'6-'=4÷ðûÜË×ã­ecr„‘¥¥°ÊØû]•iëÜèôýC_r_LaŒº¾ÃÓëݶ›Œ~|mWO%þ  ìñXŸ±g𨚞Ÿš¤¶Õ#m{‚saz–­Œkƒ¤™¨£~PC]}aJ0îÚÀÓåáÛáø ðâØÚÔàÍ¿ÒÜéèÔµ­…\ćdNKE2:}Á<º‘ÿ=‡-ù׿åbÙ-ƒà<}¿éáÙÔÑÍÌ°•Ž¡­ÑÙ·€ƒ“…’‚v€ŒŠt~‡(+?HQLPR>,$*40*!Dr”ÄKg¯Ë÷ ü­ugq 1€'ùý9WU)10;4÷ÿ+6κÔäÁqbo‰š·ÑîöþT£„Aô -ErjT`vp[f`bNJB4CO+1)úNF-dœ¥QÒ¤³ºÃ¹«¼ñ3vš–uˆŸ³®‘¦¸ÁšŒc=`~•’…K ùÔ¶¸Õë$-,=9 þóìÞ×ÇÁ³žž yZZa)Än9<8FMEO‚ÞCÁ9u =^îÕË̽¶©Ï3‚ö¥D®åõ ×½ÅÈ϶Ÿ£±Ûðç½´«± zrŒš›£­,+#3HS23PM:2$+8D7& -6f¢«®Ÿ€jRT[:$Ïži5üþ($ õððð7D(åÅ··´ …“¬µ­¤¾ÕáòA»¤Q  -:ppYl}qiQE!&òñóÿ"C!ü DG'</)>¬t¸·ÌàÞؽΠ-C‡ª¥zpicmxpz„zQ8 :m’ÄÉ‚ìÒ·°Û%9JK4/ üæâÔÕ³³ª‰l{g) -âI¨4í¾±·Ã±±áA½X#z|㵬Õü´²˜—”Ÿ¡ÃzT²@2óÐÕáâÛº²¹ÏÜäûÝÍÏ«Šz‡š©°·¤N2%A\TGA?@0")AQ8,-CW“ÔÊ¢ƒkVD-"<'ýàÈÔêîÊÇÞû'Pbe]TMGHJ3 -ïó¶°”Œ“¢’ˆšµÂÜ;É߀)!ýøJptgqsshFóñúÝæáàûú%; %+t¨–Mæ±­·¿Ï¢¿ñ0Smh\UWFNQa^WGJ/ATšï¿L寱Éó#ü ÜÈÉɽ¬Ÿ¬š¢›zog5 þàožǨ«µ¸’¶ð6­FÝËßµ²ÖÜʸ•…w††q~¹Iê½ =ûí÷èÚÓßæòù÷âÉœ•¤›˜ ž$ûßçúîËËÑÑÓÒ×Þ6A-ìîòÞÐÔýøÚÀ¯¾Ýîì6@;Pry\ejRK3ø íÓÊÊ¥Ž•·²”Ž²¾Ì'¿ð¢I3"ÿ;z“wUUU5ÿæ÷úÚÌü*/$<;)@’½‹)å¿¢»À°¥©ºÐ %6GLScdq`TXI.CZPI2X®Ì¨CÛµÀʺÌàÖÉÆ®‘€Š}k{}{|yn4H@4Íb﹡ªª¹þ5G|ªõŽ­ù©­ÁËÈʸ ™µ¿¡—­›÷ÕÛ˜þ÷ïãÝÚÏñóáÐ͸œŠq–«qT çÝ˼µµÀËÕø -`ƒ‹—šš£­µÀÖïïæºÀºÉÓÑÉÑàíú8 ³‹Q=6# &)êÒÆÏúóÛÞ庪ÈÐÄ£±®¤ûˆ«v0'1&:^[H>=9"ù  õôB@þû -*/(-\“Ä+Ýк¾Æ½¥¸ÖÜ1:SSS^JG>&(.<?Kóþ $Ù¡„…‹„±Ë¾™Žjo‚z—š“—„Š‰@R}wrvLå<•-åËÓVt–ú‘_¥±¹·±œ±ËÂÈçàÃÈÔ¤r‹×Ì™û ôÜØËÄÆÆÝêñÇ’‡ˆ~hiTúðÙŸŒ›«¯£–³ØÞâû'MdlsªµÊè Hffnƒ˜¥±¨©·Þñø¥*£2#ÿêË·œ´ì úêîþ궬ÂÜÐÅ­§éeœl4þÿ&BA)/5.5&  ùü$þâçÿ&5)5:XÀ‹,êÊÇ˽´¸Ìôò>OCN<.üúðëóîɺÀ×Ѳœš‹°­°®Ãµ™†vo—š³¥“–{qd|–‹…Šn -}Ìd^¶âÔšQeÉ'Ź¯¨˜ÂäÔÕÞÉÀÐÉ–‹ŸýÌÞ§ ù㲫µ£¼ÙÙÚÓ•¦Ž[].   ô,KF7)-.FNSe€’‘‘ªá - Nržâ'RmŠ¦¾Ò›>;„åÝùîíÔ¬‰†€™ÈÖçêÚ˽º¾¬˜»Ý÷ᬧçwÀŒG#>[U#ý$8 )9H7ó05ÿÛêUS5,=hš¾–RëÎÍÌÅÀÂêù 5:+ÜÁÁ³·½·¨Èϳ¡¤¦¢¿¶”•´ºÂ´§ª Š’Ž˜±­ž«¶ª’—š{{‡”“„‰‰noQþ»l]{’“Éhf›RíÉ˸šÅûéÀª±Á¶¥—€”¹Üëªÿ - - -ß°ÆƯž³ÊÎÛ¶¨ Œ‡•œ¡±¶¾Øìæì  ûÔÜÏÛìîù ìêç÷/7S™Ù‚íGlš½º¶'°¯àþñÜÊ­“~‘­´¦Ÿœ¤œ‡¨ª¤ÍâÚÅ·ål¿|7#>9AV3"#.N=:8++]” ”wš¾”vS&,P_MQo™Ü¥*äʽºàëãîìÞó!,×¼§Œ‹‹¡›†„¢’’—¢¨°ª}†›””¦—œ€•²¯µ«›˜µº´·¥Œ•—›¤›–¥°aM@##2Vtc5ßX½Y!âäïþë° ª´¯®š…£§.!Í"3þßàôóìÚ¤¡Æ¼»Íº¡¨œ—›¦µ·­ÆÖÑÙÖÅÉáÛÝðͶÌòüßʼ¹Âàêúýøþ(sõˆðGŠµá츣žÈÝßÉ»­¢†‰{z„§¶¯œœ˜³¯¡°½»¾¾çdÏ XQ|ƒvr\==k…zz—¾ÄÎÝñû%VoX>4íêôâÁÏÌçñëÿ05®íÚ×ÇÜüùëнæýá¿Ä̪­¡š¥•‰¡¬®´¯©©œ€›…y’”™¡¨Á§›´ÔÆ¡–€—œ®¶ª”zx•¤£…x¦ª§œry„j^kdp…†yM»€e[Aä̲±£Ÿƒ‰§¸·»ÃÏU%ã-)ÿêó -üöɶžœ¡ÚÜↂÙÛÛÛº¢«¸ÆÓÒÔÄ»Üý˲¡¿î÷Ù¼¸ÁÖüüûñÞ({ý¸Jƒ‹€††žª«ª Ž’’‹n|‰Œ‰Ÿ­²ª¢¦¢´»¶«¥¡¤µïeçÕ¿ßþ/*$DsxJ2').)OBý LL+0 -¾7à˼±ÏìûùóÛÎÈëüùïÐÔÚÚÑË»®¿»®ÇÍÕ¼´Æ§¤²¥—¢¶º½ÍÛàËÃÄÑË¥••²¬‡˜‚xx‹˜¨™z~„¡®’mfxnzj_iŒ§£¦ž‡0¼c õÒ’@üôÙŘy›ÎìþðàÈìj>?1)öõòؤœªÐÖÀ‚‡ÞßçãÏ¢•¡®ÊâëÞÄà"ÔÆÐÌ®’ªÊÙÖÙÌÊÜíÔËõ òÉÇä0Ù¼c†sq€†‘ž¡‰–j›Ÿ‘„ ª¨«Ÿ††ƒ…ƒ‰¡ ±ï3+/J;íÑ×æÄb"6<8<OlnH3Gq¢Ÿ›€iZ@'Û¹¯ª™¨ÆæàåâáÔÏÚåèñ'å¼À¿»»ÓáÞÉÆÜÁ§°¿»¥ª³ØãèáÜéêÖØæ×˨Ą̀Ÿ«°¥«´»Äº³¯£˜¥q}€€‚pdr‘Šš²¹Ÿn-䪠i¬TSN$üÞ×ö8Q ÷ÜÐüŠsn -8ù -òÖ¼©³½«ž„}Ѳ½áä°³¿£¡ÆäáÒñOJ⤫®¿¹©£²çÿòðÙº®¨¶í!õãèâ1þŠ™•„lˆ”«§§ ”q\t„lguvˆ±ªsnwzfjhm®FVYuxpo€ˆa/&2.È·ÝãåðöèÒêâìö)  èàèÒ²®±­¶«±ÈÕàݸ°½âþ!F+ÕÆÈÑÌËÙéÓÒÐʼ¬¯»²¯­°Â¼º·¶ÅàÎÐÛôìĺ¿áÑÁÛÅÌàåìÝ×åມŸš—¶É»ª˜œ›´»Ã«›„N8=øŠ'˧‹_43?>HRC,óãÚ®—oè ü& Ô¶ž¬¤˜‘–¿±¸Ñåöëä°Æѵû€föáâÛéÝÁ»³Ñöòïýõ˜ÝXŸq.òö’¥m™¢«ˆq{–ŸŸ©®¢ˆw†£§„{“š…‰“‘’’–’{Šˆwš±Éäüõêêö ï¾ÅÔÇ·´º¿ÁÑãáùúïæìðß²ÅÕèàÍÓÜüóéíàÔÀ°·¶›¬Æèܼ©ŸÄíúü æÙÈÃÛàÔâòéÖ¼¬­¸½¿¶ª°°«¨ ²£˜ ®²ÊÒË©Á#G)öÆÀ×ÝÜæñÿñÈù¶ÒÚâ׳«¾¹¹±¸À¾º¹­KÙoφU116,5=(ôïÖÆÁîu:Æ  øà úà·—Ÿ«¯³ѹ°¾(å«®ÛÙÏ^ƒýÓ²¯¾ßûÑ´Ï6—nâäîi†g›¥©„g\f‡‹‹‘ž£ªÑÖÀ©©ÌÇ­–‰Ž¦·°Ž¿ÃÌÈÇ­§¹¹ÑôÓ½ÈÐÃÁ¾ÆÓÌÃÜãéäÞßçïÍ¥’¢Âʶ¥§ÌÌ´¹ÌÀ²¡›¤ŸÑïßʶ¥ž®¾ÂÛß¾²®™›ÁοÑÞ¯–¢¶¥ƒŽªµ­‘˜±€Š—•›§Ä³³¨Ö–Üʼ±¶à;+êÈÓÛËØѶ§£§¸£›’¤¨®ÁÂœaìQñ£N ôäñàõôØÒǽ³–‚ÁWÛŸôý -ò÷û縣µ¿¨­¸Ùα¹ë$<C1ÛÑÑã<¹è£;îÄÇËÐû -íßÝÕÚ÷ 𺥤¿!.­­£†bXQTtynv{ƒ—¨º¾¨’¬É»¨Šš§ÄΕš±µÌѨš³¸¶Ç¹¾ÃËÕäÕ¼ØÔÄÃÂÈÒÈÂÁÚçÙŨ°ÃÑÀ˜°¾²‘Š›“Š•±Ä¾Á½¡³©¡{•°Ã²¢–…‹¥·¢¨²±¢¡°¡¥¢‹§­—‰˜¯«¥¥¤®²ÁÓ±·Qêï›"æÆ¢Œ· G&-×Õм¯˜‚ƒ‘“˜šŒ­ž—š‘j(ŒØs#ⶦ¯§­ÓãѺ  ¥ª’•Ï½¦kï%  øó -óÎÁÔÜÀªÀÌÀ²ž§á4pwÝì*¢ÝÁUþê;â 0ßÒÞ!öÔÎËÎÏ̪†€„y꡾“¼Ì¼£Œ}„€•„lUINiw^Yd…š–w“¡Ž€¥É¸§­›´Ç¡¬À¹¶¥ª·ÄæèàçØÙν¸£––”Ÿ¼ÇÔÄùž´ÜãÁ¬ºÍ³¥§Å·Ž¯Ä—š¶¥š›¢’l|~‡‡‰‘’¢®£š²Â¯ÆÙɨ›”ˆ§ ©¡«·±¥¶Ã¿»Éá@¿¸T亜–ž·Æð÷Ƶ¨ž’€ŽŒŒ‘“£«•†{{\ÓPì©Ž™…€ƒ‘«ÆæÌ®¬¥¡¥¡sŸé‹n3Î4, àÅÝåÓÇÇȨ›’‘”ÖO«ucÇÞ¤0ãÀ ¯Èb#?àêûóÍ£‰ŒŒ£¯Á”“•ÁQibÅÕж“¨ª•™±²·˜uqoa>YewŠ••njŒ£’Ž¿ÔÓ×Á«¥§©¾Ë¸µ¹ÈÜéëâòêͲ±©¶¢Œ¬ºÚÔµ· •µÇÁ£º®¢¹ÙÈsŽ l…Ư‘šž¨¦‹~{‹—ŸŽƒ›ª°¢¬¤ª³Å½¢ˆ“›¡š§°º± ž¡»¨ª»öC, ò϶¯¢»Ê£™ÕÜÉ·©›w»­¢¦”“Œ’–~q|†X•‘䣅„€nwwƒŒ»èòÍ«™Š†˜yp€¡í}*ö³  ñóäÁÃÔøìº̼¡™—ŸÄ§á®ÕøÖ¹­˜–˜ãÿÔ‘ÙÀ¶¿¾¥®º¡•¿áÖ¤°½´ÝÛ -¤Ä±”€•­¬¶ãÛ¶ª©§›—w‚› ¡°§Œ„‡ª¶Âɽ©­¡£›œÁ·ÌÛÏÏËÜÔÚßßÃÉÙâ´—¥§¶Ä¸»±”«ºÀ©¢ª©”—·¢mwŒ†‹¦©¥Ž¶È·¦—ªµ°ŒŸ«˜”„€v~zy~‡·¸ª™•¦´­°›Ž¨v¡·ÏÝæබ¨£ªÀ¥ˆÀáȼÓÀ©“·ÙÁ¹Á°œ˜œ™}“‹[‡O»•xns`V^n­íêÚ¬’zxƒ{vžÅÍ£ˆîïø ô¶¸Óïá½±¸Â«›ž«ãr ë{ö¾Ã¸´²Œ…Óú³[²’‰˜¸ÇÚúíÇ«ÅÖɨ°½À×›žjÁ¼ªš–¨®Çéƨ’’°Ì¹’œ£´µÄÓÊ´‹tp–¬—®¦ ¾ÅæÕ½ÆÉØÖØÀ¬¨¾ÆÉËßÜÐÚÛÞÌ£–²²««¸¨”¨ÎѲ­Áªœ™Ž—­«ÉàÔ§Œ¼ß×”qs˜š£­·£¤¯ ”„”‡„ƒ›ÄÏ·Ÿ–›—…w†¬©¨›~u…¤½¶¾¶¥ Ž’–¯´¬ÌÝÔ×ǵ¢®ÚϾ¸½¯°¬¥œ˜žwÅq¼¤Œri^OVYb‘ÏÕÈÅ´¡™•Œ€w|†‘ŸÛ•˜oÞþýýÝËãòðÙ«Åéѯ˜—³?EÎ ­™§½ÍÀ´«½b¨Γƒœ¦Ãæáð»Å°¡¤Î -FÒ›(}†Žˆ–›š—¼ç÷ɦŠ‘ÃÚÇ·®ª¬¿ÙÒË̬•ˆŸ¬®´ºÇÛýôÙÝðíÞÙ¹˜›­ÌÀ¢¯ÆâüæÜÖØÆÏÊÎÑÊ·‘œ¹ÄÑÓËØǬ®±®¹á×µ°·©›šŸÒûìÀvt“²Ë³¡ÆØØÅ¥˜™³³¥«£°³¬Œtao™¼ÐÓ°Ÿ¥š²å׸« “˜©«¾Óα¾ØÉ·›“ÀçϽƩœ µ®©§¢—šŒÀÍ€jrˆŽŒ‡ll‹«¬ª³¾»®Œz‰†khŠ}ŠÜ–‹]Û úõþô¼ýb:¡¿J!9zòÁªµÀÎÓƶ±þ?û¥ «¬«±´ÀÕÀ¸¿ÄÀ’‘Ã4³ÛáhßXŽ¦¯¯’±êþàÃ¥ƒ ³ÈÉ·¢§¤˜¤²¼¸±¢¥¯Â»·¼ðõÛÁÖâËÏëÞÆÌÙÛ¾»ÆâöèãúòïííïÙªŸª¥¼ÛéèêÒÎàßÀÊ×Ò¯Ž–¢­Åå >M73 Ò¥œ£½ÐÈÌãîÒµª¶ÁÀ² ‡œÊݦ‚§¶¼¹ÓáÛÌÑÜãÍÝðþûóùùçØÆÑÔ¿¨¯ÏÔħ°°ž”´½´¹°—ªÁ],qx©ÊÉ¥¡œ‹‘¬³¯À®…€~rju…“’‹¸dT`ø!íàù6Ê‹WÒ²œ¤M6#KÒ¹±¤‡ºÝÊ«¿ïÙ•“«¹¾¼·Ç´Ÿ•£±²¶äXÐ ÞŠ^“iYÅÜÉ©›š´ÝêÞµ™††•¶¿³©´©„o„—¥¡›²±£¾âݲ©·ÃÆåõÞÍÜüøÚÁÓôôßßàüüöÏ¿±©»Üò # íäÏÌΰœ¡®¯î?n‘«¯‡F#èÒ»³ÎC/çÑÏÉÄÅêôñóøþäç :DDcumI/SF3(''#õÜÚãçΤŽ‹Ž—·É®Ÿ£š«Ôš¸l‹l€´îéÒúÛ™«ÉÈΛuŠ}–¡«¹ ze¯VsŒ  óñêé´è Ñ›€~ü× µ›•‚wy ÖöέÂÀ¡”¡±³—¤¡y“¶Ì ¨¡TÛõ@ë㽓¢¾Äŵ¡Œ“®¶»¨šžˆ‰Œ€ÉÌÅ°—–Ž˜·ê多»ßìåÞ×ÑßâÚÎÐÙêçåëóèöø  ñÙßó5h^YNàÄÊÛÙº²ÃÄÞ*ŽßøÏ­{ø -&Tj’¸àÈ”>0R±@)" ]cj¡Á¨¸¨—†p[ku{gBGKF9<G,'2!ÿо½³›ªÏ­—¥¯¦©µ¶-ë¿VoŸÎáJ<ñ¯“®²–pda}šÅÚÔáâ”t|™Åjœ{ßÿìÞäÿ—²­}iz~çˆ|õ¶²§ª™ÄãêëЭ¬­ºÑÎų£¤¤¢Ýˆ]2ͺ­ÖŸ -ã -⻕‘£ÄŹª›œ“¡ž¥¼Æ¦” ÆÙ¿¯–’ØýñæÌÁª¥µèäè¶ÇÐÌ»»ÁÂâàÏų¹ñ!) ú'J©Å±¬e3þÓØëÏÛçûK©ö2îÜ—mzšª´Äçùðì»xŒ¡Ò÷̬‡cW}©”¡ÌëÃœ•Žl_{œŽgdvV;;NJgyR1* ô±˜‘´È¸µ·®jn>mŒ™Û+YNט–^Kpruº73ûÇ”šªªÍ“°¥ÿò “ °°¯œ’©åHDóÅ·¼·ª¤¹ÙèíĨ‡œÇè÷ú@WNjµ.sE°Ĭª©ÀŽè©ÕDz€¦ºÁ¦‰}’¥®¤šÄÜ»­À½µ®¶©“­ÔúÝÒ²­ÞòÞ×Í£©³˜˜·ÈÍÙáÖåûBtvƒ]?:IbO[œ·­º®«„=ãßï75<fÏ' (äÁÄÌÓ÷ÐðüáûðÐã0&-ç~•w©Àį‘Š}{ƒi^kzqdf^KHC@Z|u\H7GGTN7 Ý·°ÆÔÞæʵƒ›€˜Öñ3Œ¤kè•udl{‚‹£-†Z÷ £§ÝëÃ'!œ“ª© ±è. -ѵ´²§©¬³ÏðóÔ¬”†–°áFö‘½BåÉ›NõÉ ˆÃÂþ…˜»ÆžŠ¯Äµ•‘€‰§¼ÆÁÀ ´ÎÔ³¡±¼Ë°®Øåѻ¶­ÐáËÍëÕ·¸šŽ£ºÙÿ4Oƒ”elšš‡ˆ†ƒ„y©ª¨­›“‰Y ý!Qdc{Ëöþ ,<ëÈÙáÑÊ×ÔëçƳÕû!C770駘“‚q–ª’£œshzpOXe_OhWIKUZZbdIQJ5TOO[D0$ ÿúùøÉ®›æÃ榥£¶å4“ÑcÂ|{‰Ÿ™š§‰LñòФ’§ž«üÜ4ˆŽŒ„„œ££ßëʾÇáäÈÔ',Ï»¶¤‘œ´  [JŠ!ÿ\þûÎ’|d‚2jV—‰šµ²•¥®»µ§›†¶½º¯¢Ÿ¼Ò¹¡¤ÇÒÕÄÃĺ­¦­žÄÉÔòä²¹¸Æáõý6i{„°¶}„}nr}¢­Žyˆ§«³¯¦¡»˜nK>Zn^mŒ—£ÅÁ¿ÒúûêÓÓÈÃȱ¹ÕáßÛÜš…šÛ#:=+$à”™Œr}zv„rSc‡`ESd^hoo]B^umYD=LT_I6KZI?:JN* ÷ÍÁ´o ‹赨½ÍÓ*ªœ¹›“Š~}¥÷>ïÌ®Œ““™”œ ú» ‹‹—§²Š‘Ì'bVE`‰{iSH4沺·¬¯Ò1Õ²iÝ¡Óʽ¨¬›£š£Î‡]H£º«‘šÁ¶·Á»´™“°°š’ŸÄµ„p°Åº´ÈÇÇÖÙ­Ž °¤Žž¯¯ÏÒÃÍÌä]}’Œxe‡² }y„zyv‰¡–©©ª®­®´ËØѳ¨u[Zz¥®ž”Ÿ¯ÉÝÏÑŸƒ”¯À¾§¶Éº¯©Ÿ…Š£Åøæͳž—knr[OYX@9SjkMTZLT{‡jZB[ujONVYQ[F:LW<1=QVZ=ñɽª®¨)!#ª­½²ÅýNŒc䧂_QhªàõÓ™z|Œ“‰–”…‡œ0'Ùþ˜½êÓ¨‘ÎlõÉ’–”ŠMñãÛÊ»¿ÌÝ bÓ5¾PèµÆÉȺµ§®%‹Éͽ¦˜£ ¡¸«š†„¥¢Ž—™³¿dmœÃßÜÏìٹ㈑•®Ã½²•±ÆÛê÷Ees|yNi¤©Šf`y„‹|y—³°¿»¶®¶ÅáЯœŠA/Š½±·Æ¿½áâàÕ²—ŸŽ ¦«µ··¢…}¤ÉÂÍÑô”ygw‹]ASH;QZFJbtiUurQ^sbEC^d^I2RjlP\kl_80PaOVpMïÐÁÅÐÀ‚Ğͮ¯¶±»ìa5Ù oMoÀõò­|{™†”§´¶ÆÀ]\TÜ’žÚü̲ßS̺[ù- ÑÔäòäüêê#85í˜ÈáÒé;úï^ ÕÞÑÅ®¨›‰•œ£œ¤ˆ‚Œ˜…‡ž½ÀƵ¬¦©ÓÕ¶ÇäÒ¹´©››¾ßÓÁ§ÃÚÝü#Qkup]f~ŸÁª“zƒŒ“‡vˆ‹†¢­±‡…žš™´¸›£´})>›¾ÓáîÞßßÕÙÓª§š†šœwp| ªŒq—×Ú¹Ÿ¢‹v]gn]ODRQl…|†qUAXf^UHH;NJKFD}f_pY<7GVI9?W7 ñÝÞßÐÌfncŨ¬œ«â%\wZÁš‘äò¤‹–‚­»ÀÌåá³Þuli¨£±ÛíåÓÕàù âÕþоÞíø)qnÜØçé°£À¼›µ½Ë¶ßb5­ÀÆØñØ°´¿ª}‰Ÿ™‹«œ”Ÿ›•†¨«¡¿ÒÍÞÞØçÝ¿ÁáÓ̵¥¹¿ØüûËÏó÷4`wŠ¢›–xq‰žŸ—’•…yxt~ƒ†Œ™˜Š‰Ž¦‘~¡·²ƒN=l¾ðÝÜÐÇÍż¦™›±½Ä‰c`|£“¥ÄÏŸ€…–|gwbem‚bZn‹§ŒŠaJDH[O@FGTK8)(pŒkF30HRG=58A-56"ÝÔÔÚÄ+Ÿ€‘±Úélôdä/á™…uÏÚÔÊâùϽë¤Ì¬§¥½ÐÔáìåÙÔÝÜÇÅîË´ÂÝòY>íÑÚ×À‘yŒ¼ÒÌÊÄýŠuL±Ë»©¦­¶¬¨½º™—ŸŒŒ˜†”¢¡—§¥™¼ÉÇëÝàèíØá×µ–ŒÍâû'.Serw}‹ƒŒ‡mˆƒˆ‹Š•‘zv„ƒ~—Œ‰–’…mc®µ‹ejkŸáâÙÙÊÀ𬧘—¾Ú¿xŸ¬ž‚k}ws—¥ˆgfs’ˆfOy©ba…ƒohKOqmaI8XXOHKd ³µÜ½LCLYmdLIdX;KJSÜÊ»Ê׶ƒ¾‚}•°±·…ÖÛ—}xn"É¡…˜ËÓÕ¹­á -Ç°¸Ñˆ–›¸ÏÞèáÛÓ°¨¦¹çïÌÁÑÞêøãÍÁÎÈ´’“ ÍÝÕøw8äË­«¬‘’«¾µ°½ž‘ªŒ˜™‰¢»¤}w ÆÃÝܵ±·ºÖèæîÚª›»ü+?PRrvujhkgdf{tw„sy‘ytzs‰•…w‡nz¨®•œ²Ÿ¡¯£g[|›×øèàվľŸŠ˜ˆƒ®Ô¾™rm‚ŽlUE8T_q~V?T|——lAWyeBI^]P`]ev’›zfbpr¡Õû%48V3º[ZbrfT]ggXPgw6ï¿ËÏæÐA&sŒ}¢ÊõL¼&àl붮¿ÊÒ©šÙA'ßÅ·±ÿ–¤¯¬±ÆÛéÞÖ¸½º§ ÐæäâÑÓÄÌÈ¿¬°¶¦™¦¼Çá0Õ¨^¦ÈÊ¿¯´´±¨·ÊµŸµœ‰‘™—ŸÃÍƼ¼¸³ÊÒÐé»ÃÑêè÷ðÉÕñ(Yeusˆ«“€˜mr‹€xƒ’”‚ypdqŽª‡|€jZxš¢›²Ìɾ²¯¨¥¹º‰gvŠŸÂêëïÀŸ­š–¢–“¬Âº²|FXy€baC9?/23?OK]‚‘qJMkjODH=68Sr~¨ÏìàÝó#Olahq“–M§`Z[NRGSrqvdeR -ÿøÚ…µ‘µŒ† ¦¡§ë`ã?{lÁ¿ÇÏÞÉŽzƒÙ2/ Äœ©ÄÆËÉ»ÌɾÈƳ¿ÎÏÀ´´Á±°ÄÌØÁ¹À¼§¡–†›³Ô4ÿ­ðØ°²¨©±¶°±Àž¤«¬¯©•œ°Èѳ¢°ÅÈÚÜŲÒîãÍÑåô8$)Lˆ›Ÿ“¡¼¹¯¼£pRe’œ«¦µ®›’”„Š§«’ŠswŽž ¢¢¥ÍÃúÁÊÖß™z_x’ºàÇ¡»¸´®¥¥«´¶¿IM‚yvsNA>%&:Os~wzsKT{tYD-5Df¨Åñ-IOaˆÇÒ´Ž‚ˆŸÄˉå}e]:,8”|_ZmL>/óÌ»O^Cž|”ÃrÄD‘,I×ÒëîÉ”„•èA=£›Ÿ·¹¾·´º¯«¹ÉÀ³ÊðìÒ³¡—¢ªËíõãäÝÀ²¹¬§Ê: ÆßĹ£“’Ž”«ª›·Æ½·±¹È¾¸œŠpŠ¾Â«°Éàóã°¼ÐÓ¾×-Q^AhŠ—¢µ»£°ÃÔÚ·’i\O[}”¤—zŠ˜¾È±—s“¤£ž’š¢£³ÃçóÖÖ椛”yxfTˆÄ³°ÐÔµŽ}ab^…’†ehƒ‹Ž¡¨rPR[wtlrib`U[gt^ZW[Vo¬Ôü!Utx”§®ÛàÒ¶¸¤ãë¤Ø¥uL2)P‹™qUSbR:O+úãÓ  ìçˆqx‚{·öŒ(OªÛúõ嶴ëA1àϽýž–¡¬ ¨¹¶Á»¯°Âí÷á³›š›‘žÃäûèÅ«¯É¿Í8*r¬±¦¦›Žœ¢Ÿ¯«Ž™´º²¶¿Ã°š´¹†|­¼ÒÛëÚÛúç×ëÌÁÛà(cy—§x ÓÑŸœ»Ð¼«ÇÅ—‰€„pfmvš£€‡¦©¶Á¶i{ž›±Çµ ¢¸Ÿ¬ÒÕÑáÒÍ¿‰†|£žqz–—¹½˜gXNINs†t}”¤‹~—lMPt¬°r\VXgv‹‰n¥š‚®öL‰«¹ÌÚÅ­ºØÍÇ»¨ÀÔ¦W;¥\2Eo‡yKFO]HDP2+òφ d¤l~Šoe›·¤®‡ûËàõ÷æܾ¼æ4ßÇı¢ÉÈȶ¯¦§°·¬®©ºÚÝÓÏÆ»«¨¦œ·ô»¡¢½Ù-ƒš“‡™µÈȬœ¯½³«¶Æ­›ªµ«‘š¬–š¡§ÎâÒÃÆ×ÖÎ÷êÅé'ƒ´­³¹¸¼°Ÿ}…ÃÚ½—–¦Œ‘Œwsu½Â‡ˆ«ÃÒ«‘y¥¡–x^cm‘«›©µ——°»¥£¹™…”“—Ÿ—›—œ¸Ã¯“€v^Y}sz’£›n_I=Iˆµ¸‚kw¡£¥‰€ ×ýóëÿ:b”²¯ÂÜä꾺¯±¹Èų¥»Â¯šü|B]shI67SaU>>HJ?)Ô8 —‰†{ƒ—ž£¾Õ)³Ú^êÌÎãÛÍèü&,ñѱ½ïÔȱ¨±´³¿Æ½¹ÏÕÆÀº°µ´¥¥Ô=3îåÜæ?"µª™…‘®ÎÕ«Ž¢³¦œºÂ§¡®°¦¦Ÿ³•›¬²¶¹¨š«Þò¶¿ÞØÿVž¾±Â̺®ƒt[_˜Â´ƒjnlqv‹~z¿ë¸³ª‹‡pY¡ŠoZaz‡‚Ÿ©®´µÊÚÛÒÙµ“”x˜¤¹°ËÕзa>NfmMbmu€—€h]aZˆ›w{©ÈÛæÿͬîR@(&(d–—‘°ÆÏð뼯³¸¹«µ±ÌòêШ'z˜ƒXJ(*OR8BbXOT/ý¤áÄöŽ ³±­³½ùb_ ÛÅÈïëÙÓÅÅô×ÒÑ×ʹÙëÛÅ£¥Â¿¬­®¬®¯½sþ÷7ü´ÁÁ¼¸¶²š¯Ã¹·Åºš—®´ºª¢¥ª¡—¥°¦³ÄÄÀÆ´©ÝôÐÞ'MlŒ¡»©´ÓÐÓ¤|›ÁÄ¢v~sxz€—Ÿž—’²ÒàŠ{§È¥ow„”—‡•¢©v|¡µÕãÏÚç×˧zu‰iXa”ËÐØçฟeSCh˜‚y–|_la}’’Ž–˜› ¤¬× al*û@oF..+s”tVS‡´Áßص±Éž¦ÂÊåûã«<ºŠŒ„S3+JA,"<TSSWR$ág}fÀ ¯··¥” ³Æ=-Þ»Ù,h:ÔÂÔòèÑïìÓÏæïÚæáäöÜ«™¢·µ½¯¢¥«†§DÒÛ?ú§Ç«ËÙÊÀ²›­²°ÀÙëË­„‹¥±Ÿ˜»Á¦†ž¸ª§²ÃÍßïëÛÒÈÒB”ËÆ´­´Å¼®²¬’ƒ§¸¢‘•}’•} š”of~¬É {¡ÊÙ³˜nrŠ{}‡‡ukw–²«¼ÈÀÁÔšp]n_B^ªÖÕÅÑзœ‚Z-T—¤¡ÀŸv_ZSp’|›µÈµ®ìYP"olomQCVYC _­ÓÇ´³°Ä¶¢ËÚÜíù÷ñÊvùÀ§´Áf6"2IQHNWGRYBý½" ¤®¨™°ÊÑãñêÁÒCœgíʹÏöýâÎÙØÍÑßôùÚÏÖàϲ›˜¤Ÿ“‹ÅeÔƒî²òµ§¬º¸¨Ÿ’™šª¥¤­Ó嶛‚‡°À¯ÆÕÝÀ­°¥­¾ÎÄÅÇËÝ×âî#…Ì׸¦€x’³œ{v—“m}’Ž‚—s›”xfy…¥¾¥Œ‹xr’º¢l'/XŠ¥•a^‚™š“¶È¼°¥›gWE=Tv¶Í¾¦Àɦ‡mWP¨Ž¨Á¤|jeNO~·Ä×íçßÙ6‚4G^Wœ½® €V8zÀæÓ»Ëͼ¹ÔîæÑÜÎÖïÚDê77 2Ja[emdeh9暸†Ì®Ÿ|‚ ¼ôõ®ÑèضÈIµëØϺÏáØÈÙÔÇÅÖñ÷íб¼ËÀ«¢¨¿¸°¶ó^‘(ÃÉ‘ßµÙ·µÅ«ƒƒqsjZm}™ÁÔű¦¦®º ’£® ¢¾µ©´´¤Ÿ…Š¿Ïû(w±³›ŽŠƒx¥²ƒ_v¦™•Škr–ˆtƒ‰‚Š~±ÎŸ|“¡—„ª^0qœžqx¨”Š©°££Œy~o`UHV‹ÂÓÏƲµµˆch•±²¯§¨žyrgp—ãB…H"R¯iNx]G‰µÈͤnG1e©°ÕåöûÛ¹ÁÙç˼§š«ÏÉÃ}%MnQÈp[L<Q]it|nYNòáe[V¹ƒƒ“®Ñññ¼·ÂDzœËB³‡ôïßÆÂÙæÄÓØÉËÓÚëâÖÀ¶ÆÊ¿¹ËÑÞÚúß³®%P_°“š±´««‘}e[€˜©ËâÔ¾¨Š“Žrxz†•ÌíÁ®¨‹ƒƒu¦Êå#|¼´™“˜š•Š˜up’ž”’Š“®®Š‘‘•Ž’£–t‡ÂÊŠo‡’ˆ||s`ŠŸ‘‚yœ¼Ô·Š®ÄÀ˜“”_KafQHŠÆÒà»’±Ë®hi’¬™¡ ­Æ’b_jÍ2«wDVƒµÍÍÓÆ —•Œš¨¢¹µ”{Š·¿²Ðúï¤ÀϹ§©š¯Ï×Ú¶J5Yl6ÔcVPSNXme[pI Ñ¿뫨µËÐ×ìãÒÆ š°Åk]öÖËÌÑÓÂÉÐÁÂÍÉɽ¶»ÁÕÝäÑÎÛÖáGd掀ý!¤¸Á’¥µÒÝØ´™– §¹¸Éè“–¨”{‡–ŽŽºþûÔÒÀ«¦§ÇãÞøG¸©¨›„z“°Ÿµ›†„„©«©•”¤›’­­Ç½€h´°|›Š†Ž‡™£–~•Àͺ¯­‘Ÿ°™wŠyx{u^\o©àК€±»‡|‡ŠcO{–É›t^P›Fˆf^›Üר­È½§Áʽ¯°¸²±¸¸½¼çöЯ©´·¼¶¾ÕìôÓÖéàÚ’[ZJõ–e_S]K4FkjEOrj'êá]12Å·ºÊ´¸ãûíʬ°²Åå"óÛÙÁµÈ¤¤¿ÉÈ×ϱ¬Ÿ¸À¼ÏÕØÕÊÎý{iß‘ÏÃã…¼ÌÛǯ¨ ÃÞèØȱ™¡ª®“ºÝÊ©¨  Á»¬²¶´µÚ÷ö÷ØÛѼÑáÞý0„¼µÆ“hv‘–°©¥Žmw}…ŠŽ†§¢•¥ªÐÍ¿‹ÇÊžž¾²}™­¢„dŠÎƘ~‡šŠš‹ic‹”„rt”µ¹¦´Ë¡xs{i]T,8s˜œ’ˆ‡³ &HxŠw“áÓ¥}”ª·ÎÐÖÑ·»¾¶¿¨­ËÃ훉¦Ã±¢¨Àù$ -Ú¿ÁÇÇÁŒl8×qRX^U10EbY[ljZèÚ–a¾—Ÿ§¡Ãø - íÎÃÌËÊ»ÞëżÌÔè´©¼ÆÓïéÈÒμ±¯°»ÃªžºýO5¹¶b©†§¢ÂÜÔº¢š¯¶ÄËíŠv‚•Ø÷Û«’»Ï¿¦¯§—¥ÇÈÀ¾ÓίºáèüåÅ l‰°´l|“˜Ÿ¥‘{s›£€~ž•Œ‘¡‰xq‰ž«¾µÆª–¢¬{cxš ²¢„›£­¨˜‹­¯›˜„UVx‚pŒ©¯¾Ñܵ™‡cep„™qS~–°»·±ÑEw‚•pxÆø悔âØßøʺ¿°¤¯ÆÏÄ¿©­¹°£¬Í÷ó⬴¶½_¥c]_gjA@OKf‡qT:)ÙÂÇÝ™«±³ÒïèÅÅÌÊĸ°¸ÆÄ¥—²ØçãºÁÉÔÍÓóóòÜ¿œœ¢´º¥ ¤Á¦ÿ/i˸ž ÇÏ×¹ª³¶²º¾³¦¶ÉÔÔëÿÿ÷æǽÇƪœ¬”~„¨¾µ«À˹°ÄÊñìÎ7]‡‹…´º©œ ¤–Ÿ¬†h„v—²Y_†˜¢¿¬•Ž’¨¨•jYMqƒˆ‹™¢¨˜›ž“›£¼™u]_‡…wcªÅ²¬§‡kszlq“kh‚’¹¹°ÏA¾ÌÓ³š¢§Æ鼦±»Ó¾àüлȸ®ÂØÚÅ®¡¨·É¾³Çåò¼²Ù½«·¬€3ɘƒfFafOQIXW[PQQEº¶‡k-ÁÃËÈÁ¿°–°ÏÄ«´±««Ÿ˜£¼ØäÝ×¾ØÜÐÏÎáÖȾ£‰“¶Â´ ¡§Ç×á•õ·»È¯œ¦´È¼¢¼Ì̯©Ÿ§Ö1EQBûéæ×½¼±˜°¥—•¯ÚÕ¼¿¾·½ÕÞþÞ×ò2WmƒŸ›—¹Ð͵Á©t‚‚{¾¯Œ ¿¿¹¤z|˜¬¸°§”v_sqhxsjqŸ¦³›š®Ä®’z‡›”~h•ÂÁ¸ŒkejTKuq_irwœ{‹¿¸µÅ -”Ê×­ȶª¼±ÛãÌÄ©¸ÙƳ´»­®½ÝâÞDzÀÕε¸åôɤßÖÈؾUöÕ¾½¸”`UWOKKJ.)KZeA﨣Ÿû¹êË»¼¤›Œ™Äи³½§§À»¼ÌÝôûàÅìèË·¹¿­ Ÿ¡¡œ›£»µ«ª±´ÄcŽiš™¤®—¡‘›®¦¨ÈÖͽµÈ·å)%ï°ºÃÆ¢’’ŸÏÀ­›¡Ëðß³·ÁÛòÞäôïñïïï +Mh•²Áº¯¼»Ÿ¦ ‡–·¶´×ÒÛË“e„™¢›ÈÓ¹§¤}^VZWdu’¶Ç¿­½ÑÔ·ta‹¡¦£¢¤±–dvz†rz_ay£ºÉ«¤åÐÎê'¾Ú×»ÐÔÕħ¶ÙÞͳ°Èµ«³¬¬¨«ÕÊ¿µ¸¿ÄÐÉÑáÚ¹¦»êöͪgÖÜãçÞ›hajTI4(>VaZ6ë¹ÄÉqT&»½Ä²²¸ÂÐÖÙظ¬ÄÔÖÑàïùðåäçàØ̬¦¡®³±³½Ã³³Áº³ÇÕÝ:š¨’Œ«ºµ›­ÀººØòäÏÆ°Ëèæäçѳ«¬¬°©§£Ïаž¨µÔÞÍâÕØåÙáòîèàÎÙîâIƒŒ“’¬¯¼ÍÆÀ°À¼¯ÃÔØÇ¥–§Œ •žÕÔÒÅ”be–±²°Ãļ²Õáñ×°€`‹´¼¿©{xtkjx€wylbŠŽ¥©Ò¦Ãèè=yžèðÖàôᯉ”¡¼Ñ²¬³ª¾Â¹«µÜÄ”¡¬«žÂúáÌÄ´·¾ÆáÒ£§„1 ¥ks}_B5Pawtl3éÀÂݾºRÀÀǾ¸ÊàéëûäÉ×è"û÷âÍÑîßÞãÛ˹©§¹À¿Èì¸ÙÒÑèùÎ ÌÁ§§š²¼ÐºÁÏ»¯Ó×ʵ›£Ÿ ¢±¿±Œ~¹·¯©¬¾Ì©©Á¾ÆéëóôîèÒÊ×ëßÇÅÕ ÿý?_v‰²»§«¶ºÌÙŸœ¤¸³¯»¿±©¸„®ª˜È¿® |fm±ÏÅÈÆнÌäÒ zIg¯³§‘}tNYZtm_Ee™º²Œ‹ŽØ -õ*a¦ÂöðÔìñÏ­¥°­Á°¯´ÁÑÊÂÊ®¶ä©}™¨¼ÄËàع±Ã¿®¬²Âµ¡±{B@H) šeeS\USapsfP.õÒÏÛÕöŒͲÆÚßÝðçÜêáå/n¶’ ѱ¯ÎõãâøùÝàÜ·¥ºÆÀ Œ­ÔÕÐì|´ªåƶÀ¸º°­ÃȽ®Ÿ±Á¾¼¶³¬š¦©›r~ÃâËүµïêÕáéóûôôåìäæéé ,,8p­¿×¶©½¿º¸™¡Àį½ÀÁ¬™ž“¥¨¬²©©Œ€†bPcŠ¼¹ÐìݧŠµ²…kEo¬´« ˜Œ`bŽ{MVm¯Ç†Š´§„¯ñâu´ÂÜÕεÙãÁ±µ¥“·µÀ¸¹Ó¿ÇÖĤŷ—•¸åÔ¾¸²¯§ÍÞ¬–¨ÂÔשfOs}Y3¢zpXX_gr\WI?/èìè×;ÏàÀÜ÷ØÂÂÉû!pŽ@Ë°Ãìî×èýöô䟡¿Ì½¼ÀÀÉÓá97eº¶Æ± ž¢’™®·«³§šœ½ØÀÖǾÏд{‰†´åÙϲ²Ï·¥ÉçѹËßÌÓåèõïÉÉÆááØïñ $'=‡¹Ö¤ËëÓĪ’¥ÄÐÖóΞ‘†‡‰¬¶¬  ŽdRa‹v}Áäï⻟Ãß´‰‚t~¯Ã§€‰––…g_r—¦ž…ªïÓÎÙÝÖn©ÕÈ´ÖѲ¹Àº Œ«©·ÈÁºÁÀÀ®›¬Ë¼Ä×ØÕÉѸ©‘ÏùàÅÐäÑÆŒm‚¦Y鼜”vYHmxYAHI>÷Í«bàÏú;Ë©µÆúºÈ4piîÉêäãô÷êî¼ÎÕåßÎÅ¿ëÃȳ®¾žŽ–šž–£­½ÑÄŽŠÃÓÓµ¶ËÚлÉÚÝö ìàß®šµ †¨¸ÊÊ͸ÔèâñèÞÝ̾µ»ÁÐ P¸Â£ÔñÝÕŶ¥´Ï«“œ‚u~ifw±›ˆ‹mh„‡³ÕùÛ˦™ÈÓ{IF®Ía\|rhŒˆv„¬×³s•òß­š½Ø sš¼›œÈΖŽ®Å±ª³¯´´ÍÍ°¢®·Í¿“œ²ÁÉ°³¼²±¢žÌðèâëÛ³¯œ‹ºÈ‚:úÍÈ¥Œ†gr‰jG)GX[0öÊ —zp8Öæ&VÜÁÌì 1æëD‡1.$úç # øáÄÛÌǼ°Ç¾ýwÖ¹ÃÙº¢´ÄÁòµÓàÚ©›ÃÊÉËÁÌé !(%-ì×¼¯Ã£¥ªª¦‘²íêßúÿûöãɯ¶Ï÷ó2ƒ–’½ÕËÂÆǯ±Œm}W^r‰™y†”•ª™†¶Â‰kz¤Â˾§—ws:C_vJ Nobegeaa›¡†ÂئWb±ãõËÎÚòX ‹‰…®ÜÉ®¢¨ÄÚëѯÕžͭž¤¸ÌÈ¥±¾¶£©Æƶ²£™ª¹ÍØáØż¹À̯c'Þª½Ê²‡\gpI56K[I×È¢¢—âŒåó.X0áÚÙâùKÊ’ùŠº;ü?%ò1íáܹ¬³Ãþ«ßÜÓÓäݾÂÕ×ØáéèçåлÁ¦Áêù_oJ69꼑x•¦½Ô·Ÿ«¬«½ëêÉÏÈ°ÆÙå ÷ѹ¸Ýòéåû$Mfy ÆÝÙ¤‰ž°¶¥xzPTs¨Ãžˆ¦¨¬®²¬œ‹‘¤´µ†oW#Sao]E?:@QV]`v”›½®Ÿ•—˜× ++D„±› ­çèíÜÞ±¸ÄÍȬº›°°¥ž¾ÙÑʹ¤”¹ìݰ¹£©ÛéιÃÃÊ»¢ƒr: éôê©R?CXbcz€Päß×Á«)4!Dp^ ÝÓÌé.Zm¦$Hê„-M,æþþõÝÖÍ¿ÎàPˆ²ïïëäÖÀÇßçò5ÿêʶ±³Åú5PTS1æÙØÀ¡«­Úôí¬£ÇÙ̾ÉÊÉõÄâÁÊàÒÅÉ©ªÓàÑÒôT˜¤¹³™–Œ”¤ ‰‡‰ntŠ¦¸˜Ž›„œÉ¶¤®¾Ÿ¯¶¦Žƒwe6(LcdspgccXEUy}y’¤¨­ykŒËÕÈ$HQL‚¡ÃÔÓçÔÆÄïÒ˜™­»¸´´ÌÒÆͧ¬ÉËÍôªÃĸ¯ÒçÕ¾¿àÞ§°½¸©™›—Ÿk8; ¶]]J==b}}“Œ_@ ͸¬¤ÀÔsXOXøѼâ:]Øã¿]BPM@M<ðÆïëéØÄÔû 4Ä%ü  -ÿÚÖàîû"CXbCB4ÿÞàâìï$;㬮âãÑɾÆñ÷Ï´ÂØ俸ÏÒÝãÿúµ³¯ž¹ÊÊÙÜäç÷ 9kˆ¢¶Ä˨…Š•–°²ŽŒ¡Å¦°¥£Ÿš¹µ©µ¾²´§‡j~iMrxh ¦–š”‰‹“šŒ—˹†F9ƒÌÖá>XRP¸ÚÕ±«›´Ú´ÍÛÌÂËò ÚÆÛª£¶Â¾²ª¯ÔÕ¬»¹ÓÔÀ´ÉÈ´´ËÁº¬œ›ÀÇžXCÿ‹W[YSNV`€Š€xGú°•¡Ž/ªT2,æÎÙìæÙ\³œbj)TmFñþéïøòÔÑ&}}ÿ2F0#,)(A_wŽ˜“’`øîı¿ÆìñÜÞ¹Ž…ÂìéÜ̯ÕéÇ©³©¢¹®³¼Áã÷ö)àÚ³®¼ÅÑòéÊÈEB&p‚—Ç¿µž–—š¬´²–¨Ç®­Ì©‰žµ»“œº½ÃÐÌÌ”l‡•‘­¥¤Ó»£¢’‹¤ÅDz«¸ºŒa[iÀÈÄ×éz v†‘§ëå´©¶¦™¬ µ÷ ã˼ÍÔ»Ãβ–º¸–‘ºæ÷ߺÑØ÷¨»Ã¼¸×ÓÖçÓ¥”ÍáÊtí«vƒ‚pi_W\txdA²Ž§±¨]nuàÏ×áññÖÏÁHQEt­ª9^io:#Í»ÃÛÒÝÿ&Ëç"\ˆŽ˜–meHNxŠŠaz‡H缚™¦É¿°±¦™”¤×òäÜÅ´ÐÚ±½¯–´µ¢µ½ÈÕÇ. ûÖ¼ÊÛѦ¤Õ0  AC^‹¦¤±³µ¡ª³´Çµ’ŽfǸ’“¥Öûß;fc‰‘pn{•ºà«š•{±¡µ¼ª¬³ˆŽ®ºËÀ¼Ø¢¿¼­¬¬¾Ñɯ»Ï¿§¯¢ÄùýÚµª¶½ÞÕ¿¿Ú·’©æÿûé¹¾¾­£¾áÒº¾¯¬ÝòÁ¦¯ÔäÁx=ðš‡r_g[I\mhI>â»ÐÌ °¢þåëÑÙýêù£»æ;?Vhf*L\v}cS?ù©Œ¦ß  nf†5\•ÆÀ¯¦‹jdE@nk\aJ\gW?íÁœ™¡·¨ºÅÒÀ²¿Ì×òí¿«¹®ÈßÝϽ¢¡¦¢¸®ä-:5JêÏ»¤–¢¸Êé!,hŠ‹ ¿«¶­š‡›ŸŠ‘pbÈÖÅÉÖ÷ûÔ³‚KZibP?Y…†|o–›€‹Š†”{w‡žÂÚÈ»7²£žŽy›º«¦¼Ôê°–µ¹œ¬êåÉÄÉÊÎɼÇÑÙ°ÂïÛÖåгɿÈâèðáÚ˜Œ¯¼¥ÃǺù†sÊ¢ˆcXM@7AUPD8Ï®»ÖÙ¸!V Ûµ¶Æ­¢®½í .. ýSbšáÃxBݾ¾^A¶þûTmxˆµ¶ŒpdXa`YyqcleZ^]fH!趖Â̯Áâƨ¹½¦¶Íϸ£…—Âϸ´¹È®¸¤•Ùï $&^g!öÑ°¹µÒ0Wƒ}•—®¶“}š¤·«¼¯™Ÿ²½¶Õîåν»¯qQIBPJWsNU~xii‰¨¬š{kf]?T®8ìÌI£¤‡he¦ÕžÎçÝÆÔÓÛ´ç°¥åõèÚÅ·ÚÕ½ ™Óáι×Ö·ØïôóìÔ˜z…‡­Ò¶µÊÀœz"Ñ©”sR?=,&-P`[:ç¹±ÂçßjNt6àÅÆ»¬´²«Ìù8ò -'qŸõãm+îÛë,UK$‡L³Í¸“Ÿ‚†ƒzlƒ ©’yQ;IQH1þ¹—£º¾ÞÔª–™œœ¬­—ª­‹xª¶¬«ÎÝѶ—‚‘½ç T…k, -çðáÙÏÍã×Ë?PxtdOkŽ›£Šµ´©—´¿ªˆ„€w™É¼µ¥­žfK;Jensp}}io‹¡¯§™§ŠaRJR|ÊKr/6|¢Á³f\£½Çß̸•Íýâ³Ä벉™þ×ÛǶËÉ«“ªÑáèij©Ÿ»ñÿåÁ¹¿²°ž£À¿’ž™Š˜y3¾•{G<KVI5Hiu3ÿÈ©¹Þç…f§„/ÙÚéÒ»º¿¾Ñæ7!ø /%)~È“¡x$çÄÉý$U‘ ¿ë÷Ï~™²©¦œ€`’Ÿ¡›Žq^Q8:3ëͱ¾ÕÖǧ«§¨¡Ÿ›Œ‘®ÐÁ¦†“»­Ÿ¾Óáά›šªÊ{¿j -Ú¼ÞûäÜíðÇ¿î"BKE@HRfdh†ž­¨¤¢œ}r—’qs½À‹xw”Žr_Vg€¨²™iU†µ·‹Œ••ƒvmp¡²Q’’¨¨›|ƒ²¡¬¹¡“™Èôس߽š´õÓ´ÄͶ¯§²¬¹Ûþ碢§ÍóË¿Ÿ‘´´ÍƺÚà±bTYm|,軩rJMj{†jguf7þÔÏËÛÑrº‘3éÿíÈÀ¹»ÓëK%öß¹[i}QíÀÚ'¿1nêÝÝ´™‡¤¢¥’xw”‹‰—¢›~^]E2*õÚÐË˸¿¼»¹‹nrŠ©¶©•’£Ãª¥ÅÙßûǺÈu¨dæ#$ 6;BR@5GQifDZizhi‡¤— —¥£Š—¯q€ˆƒpltxy¦ƒ‚tªÑÔ°¦Ÿ‚®ª™«Ú{¢upif‚™¹ÛÅ Ÿ½×òêؠ͵³ïÿËÒÆÄÒ®µÑË®ØúÄxƒ²ÑñßÅ»’œÕÞâëßçÑ{2#BhQñÅ»°oYf—Œˆ}ul3êÙÜϺ™¶ÄLüøôâËÒÕÎÑèø,aGõý•,%…Q„jÉÜ0FXVȘÿ©˜ŠxŠ‰}~†‰‚…Œ{}€€udKõËÌÖëßÓÏȦœ£¬£§žª­ž˜Žª ©µ·ÉÉö2aG(.Q^71[iw‘œ®¡š€‰„v[?aƒj@Ov€˜š¨®§™{ŒB#?a`jˆp_l™›—›«˜omuˆ›ŽŒ¡Êô$KDCoWYx”½ãÕ¯²¤ÃçßПª½üØôÝʶ”ÈáÍ­Êʧ‚–ÎØÔ®²©›ÈÞÓÏÓØÊ“IêºôᲩ“lfxbHSbgfp8ꪤÈÔʯõÇø - -õâäã××ßD{i+ò ¹q¯ëx‚…LüþHU~Å4ÜÕº³¤š‚rt—›œ„qbekgWNu•zfA6þà̲¶ÚÄ°“Œ“µãéƦ­®£•”Š˜™«ËÈÞü/0:80jxr¥óøõö÷&%)V_:(ç©|€kf?&.*`Žœ–Šfl‡b8;]ustzˆhi}vvŽ{mS.S‹š„Ž‘‡¨Øï÷"hxo”²ÏÓÉÈ»²Åá¼¾×Ǽ®Éñ¸»åÚÞ¯yÏ秡þ¶·½àƨ¡­©É嶕°ÊðÚwNá•Ëòìô·€†Škmd> P[rp£x˜Ëáη á+ ø÷ýîÙÌÖÖò_h;# pºX¢“|C -7G·@ä躨¨¥•‡sou„gOQTdl^_Š­¸ª…XB!ú˨¦¼Äªš°¨›ÅÑöºÅ±«¹¤Ÿ®­¹ÎÄÉÙ',=ZQKo¬ô7}˜ Ÿ›¬±¡©äÈ’¼Ï¸8Þo)'34G„¢¤pjO]TF€•ŸŠgbhus‹™ƒj•zVT|²³Žy›ƒ›Ùüô (ORe”üݲ¡¶¿ÚØÁ›“—§Þñô㨗±¼ÔÀ¯Öº§¬ÊÛÖÀ®³µ·±››ÂÇ› ¿èãp?Ù¢ËëéÓš{‚s^]baD0ALic¥›«ÃãÒª*(OßôßÊ¿ÂËóE`%ö)¢‚7e­è½\ ïàø*l2œ™¯Í½¨„lQGY^LSbea‚…zn‚™žw\L'ÿåÛÔÜØßÉǨƒ‰”›´ÓÒ¾ÁâÌ´Æ´¢²´Áß"BBT}§æ+pƒ²ÉÒðä»ÞÍŽ±ÞçÍ{—;ÿ0*=E/,*G: X­Ê”e^]h}ˆ ¤†tpqu²¸›`f€‹ÅNTjyeÕò󺔉ŠžÒáëקp–Òòõ綖~ˆ|—Ð×ÒÈÜÛÛÑ “’³ÆÈ¡¢©¾ÄáþýÀ_ݽÚëÝαŸ‡VDVgbWGNTL9ÒÌ·»àűlw^âËÝк½µ·Û 0øîýõ sËö¯£¿ôÊXèͺÐG”Ð.Px©È´‰Š‡|e42Qiaftqx{€yk_gfc|pCà¾ÂËååÄ£€~ŸœªºÁ°¹Ñáʺҵ­Àñ.Uqbiy’ÒQ¶½Ç¾ÙÜüîðùéÄÖòñ÷úð½jÎáø ÝÔ.0XY_xš ¡‚eqxYz‰yrw‹»‹zuW[–›©÷x¾®—¤×úÇc~”±É³ØòÆ¡ÁÉ­ªÄö–crÎ üäâÙƹ¸«¡°Ä°­·ÂÜïÝæõâ‹1 ûÕ½Ó×öðÌ‚JAQ^TQahREJ'àÄÁËÛÚì¾ÉŸýæ¯ÀÑÍÚñöÍÅâø?ÝE§Ñ¤ÖÂNñÕÑè©ä>€œŒ“‰ZG\qbHRaPIjŽƒwwXIQ[{ƒ…‰` ËǾ¬ÓçÙ¸” ´¬¨¡·¶¤›¹¼ÖòSt‰o‚Ö<u ÙÝÿÿôëÚ÷ñĶÃüùíáøõt¨!þøïò19:\}ƒeZm›¿À§ˆ˜–o‚’§Â–qYa†®ÅüqÄèíÉ«£‘™}jdqºÌ¾½Æ×·¸¸®žˆ¡¶´ÔÃ…¡âîýôÖùÙâÄ¿¶³ÚÿôöæÏÑ®|2÷èÓËíõÔ€SgiWTd_nwlb*Ó¢µìïüÏ ú,åлÌïøüêÍÐ>ÈY±"†&̹•Fñ×Ò Nå;o†rb57hŠtZzŽ…ŒžlQ9TjzqMEPÓÔÛÑ¿Á¾±®¤¡ž¤~‚‘|»Üù<Z=:Od}ªü\®êúÿô÷ûúÊÑêÑ¿¯ÅâìùôüêÙøëZ—' åóã D@V]XW:NjŒ‡œ»¤˜®©xt‚š¤Ÿ›™£Çè=²Úöѽ¾§‰…‰‘´¹Ç¾ÃÜÈžž£¦¢™®¾Á•¦¾àôÞÈûúçåξßìʼ×ú ãÓÕãäÊ¿«DÙÈÙâø æ‘ikvfS_gOWzyXÄ£°ËÜæåÖ]XköÓÃÐó êÖùMÁH„äL£IäÀ¦nõÖÖ@zû&Mx’‘Š”`&Fhš·¬” ¯¢”–‘t]`OeeSb\KaS×ÊÉɶ²®­—Š˜‹{qŒœ¸ÔÒàïd…¬Òò#HÁñ121ø÷íð¾Ñ׿åùåâÚÚÛÀµÌÜדþhÏ×!<?_o^NGLxr_v¤¼¢ —¡žnA<_Œ¦±ž£åP›˜½áÔ;º´®ÆÇÀ¼·µ¼Ìœ®Â¤¢Åé ²ˆœÍ  -î··çàÓÏÉàèе¸ÌÒØ×ÍÕÚÁ¼³D×¼ÊÁÏåòÃ|en]ce`ZYgr{] -Á®¼ÙÑÈÒ‡ˆœ/þöçü  ÿ{m’nýYžFæÄÆ‘ ûþJ„¤ 6\y•ˆ³²’y‚†ªº«§«ž‹‡š‹‚l‚~jz—†poRô¹°°ª¦¥šœ¨¨¢««¾¿ÏÜÌÙY¨Û6k¢äìëð&úðåáֺʷäùîìû$äΨŽv‰´±Òø¼j“ &C/JXO]i‚‡yŒ„€nœ®™–“ˆŒptdb|…Ž›º`“¸Ä» ÄáØÓʹÍΓžÆÙĵ±¶¡³õ°¡Öó欱ª–¢²½ÆàÒij©›ŸÖåäÔÆ®½¿MÈ’•¨Þ龄ts`l{ebl|YmOö¥”–¤µ·¸Á–Ç¥S07=`k@=¢JƶIÞrŸPèíÞ€A†ëè(c‚u_Rt¡œƒ{ek‹˜¡ ‰šŽ—–“Œ‡‘Ÿ”Ž‡jqxB䶼·« •°ÃÌÓÓÉÌû +e¸ñ'g‘ºíëéñûøàÄÊÍ°¨½ÉÍÜÜÁ¼Èçà­£§¶žœ¾Å×ׄn…˜†rQg‰oI`oƒ³®qhlqz|‚”‘•~°š‰[SƒÇ?¥ËÚáĤ˜½Ðට¹ÁÁëòϽ̮¶»ÀßìÔÑßíź֞™ ÇÒ¯®±¾Ï¾°ÁÐßѱª³ÖâÚÍåíS°szˆ°èÞ¼Œrqbd{s_^x[WBÝwyš§·ÅÏʲVæBa»âÝ -¼Ê]×ýf¦N\ŸdJûÅn4Í"pŽ’†rm]^{sjhdDIVhˆˆŽ’¢–uo~Ž„|UI`wpààεƔ‘¥ÃòèÑ·ÂùDƒÜ5iŽÉ¿ºØæÍÈ·¼ÚÝÖÕâáËЊš¹É¹¥¯Â·³ÐÙÏÚàÆ´‡†’Cºq‰…‘mcfX^«¯gM`iH^Ž•—…›£iŠw-xîcÃöíÿ²»ÞÕ¥’¤¿ù&ûº½Æ»¿ÏäèÅÁÊÕûÆ™¡°ÁÐãïéËÍêÕغ¼ÕÞèùଗßæÑòê>ÔÂÀÉ -ùÎJ68Js`EC[PN+ÒŽ¥»¹·ÉÚïÇ]Ç’²3–‘¥žyÎ2{Ç,C›kDÚ¤ôÌiƒ]t%nŽ†Š’›„|{ˆ}inib[W€u~ˆ”›my‚bEXlg9ôƸ¯† ªÐË¥—µðlä[±Î×ÖÓëÿή¶¿­ÞìÔôÞÚ¨Ž›¬×ñѽ¹ÃËÝëíòܼÆáàÉ­‡È`¦Ú°…m‚’œŽ—V=spGHmŸ˜fe¢²wvxVT©o¥Àʶ¿ÛÌÉèÔµ¦„®åÏŶ´ÄóÚ­·x™ÁĤŒš»ÃâêðÝÏÅÍøãÅ¿îØǽÅÙÕ´ÜÿÏ-ì÷æ£Ñ ×l26V{n06Gjs\ ʬ³Â̺Ìàè¡êQ#è²$î1JKoÄŠáëJ -ýë5v ÿš_ÚÉeå êG_…‹„yƒ…ƒphu’‹lAF`mcl†‹’§—Œsfp†„z}uD æÁ¤jkˆ–‡yx{–Õ.³L—âýêéèü áºÐç““ÃÑêåò.ûÃœ¬ÌÍÑË¿½áåüùâêøøÙΛä5©†ˆ¢u_Z5toUs˜»™PdˆªŒŠ§˜›´à:€ž›žÇ­ÏñÙÉÆŽx Ÿ¿ÞËãõͽ¬q\«Õ¦u‹ËÓÏáÞ¿›ÀßÙˬ¿Ý÷Öº­ªÄÑÖõÿ-žïìíÞéó·uSi‡V/Ht|[ -ȨŒ•¨¸¹À¯éNá‹‚Æ6XK?]ûœñ=ÒÜ{(¼Ã¡Rs'YZt‚z‚‹•Š}}˜‘ƒ‹sHMe_h‚€r¨km{”™Œi8ùܶ°›€u`€¥Æ†ëêÛâàÙñ϶¹Ä²˜Æó ñê+þàѸ¼ÆéîÕØÓØÚ¼ºáòû âïãEÛHY"Ý«”|U[bi—¦–¬©£t]‚r€}‚œ®àôõ<v©Æ¬’¦±Æçר¢¤‹£±åôʾ³¸áÒbcº¹£ªàÓ°¢±½œ±Ï˺«·°ÅÖÅÈÉÕÎáøúëuÛÛôÚ±‹€|H'T`if\3üÍ’gj‡¨¾«¬œGÌmd×p #­®3ïït–ä¾ë}¡±±‹‹$~—¦¶¿ ¤ÀÁ¯œ´‘ƒuŽž‡vvhT]u—•ˆv‚Œ…hU=&ê͸µÄ»±´È¢°ê6pòs¦ÏÎì×âñéÁ°½¹ÉÁÆßøøÙ·¾ÉÎÔÍÚêáÓÁÇ⩨¿ÞïDã+o¥YÂvwo{›À£«½§€mKwŸƒq˜¯Í+ll ®Å´¨¹½Å³µÈ zƒ²ÔÞçϭöÏþÞ–¡ÒÁÒΨš£­¨ª¢˜¦·Ã¿±àçîöÚÑÝìý - ÆNàµâýóÁsXfeQ#RfF.2ù¸ukb¼È°¼»Hã§qS¾8ø“_?ÄÙuTßܟЫ嚯³¨œ!šÍÑÏÂÀ”“˜–”~_j{~|„„{‡€]px„g^lc\erf\ed@þâÆÁÅÊÅÅàßã0· -€Ü¼§­ÂçÔØãïÒºÌÅƸª¼´ÊøÚ´»ÛåþغÑáÅÔÛ®³ãêÔ£¤Òýô×\ïbåâÖ¹‚'ªrˆœ£¢’©©Šfh^ŒŠt‡³â<´´Á¯­»ÇÍÄÁÇkˆºâþæºÍØØÇÎÄÌ×Ñíò ï¾›¬»ËÊ´”£¾ÂÈÈçãÙ÷â¶Ê×ÕÒø¦¸¯âñɪ¯›L;G[KBG]tA8>ߊ\jm¦ÕؽÏÅ 3§‡|oËQµ`Õ=)/ôÎõ›ÁcɃ¾ËТŠ²¼¯“£ž†–¡zzx}}€_Vs‡p\hnTAT]Q_smbnvd)ïÛ²«¶–‰«Õ]ù‰ÍóçôÙÚîîûÿäÆÇØóÿÓº·ÙÖïòåùûõ؆Œ›— ²¢¿óãÉ©¿ÖÏ¿²e+§ ôíÎpǶÐÊ®ˆª‘sy‹qhx£¡¤Ú'¥É¼Àɶ²›•ÈÑÚɱ°~’¿çåÀ·ÉÑÊ®²«¥ÊãÕ£ ³ÕÚåçÕ–ÇÆÑÖÏ¿Òå×ÔçäØÞ⸊ -´¹Ùššmd\[Va‚pT5Ú”qz¦ØïàÛÙ« 1³§ªÎ¼§º‡Š6ÞÞö1ßò±ZǘöïÀy—”šyrux…~ˆ}xyzqw|wy„r^\mgVaqhkneCQchN³›˜ª¢‘¬ñ;‹+Áóû üí þ -ýÜÓ - ÙÑÝóþþþçÕÖœn™®¥¦¢À¼¸Ñðâã̪¤@BÑçêæ²™x,æÕÌšŒ³¼¿µ¦ˆƒªüúó\¶ ˜Á°¢ÀÉÊÀ¹¹¯ ©¸ÅûüЭ¦®ëÿ -Ú¦žš¡ÃÀ¥›ŸÈèí¼¼°™ Úèú渻ç̽øúØèé­•|ÿµÒÔ Ÿ¦—žyeIU_o¥¡œ‹^' -ݬ”žÌ -ÖÀ«˜%[öÙÙ;R׶–ùÕâðh«Ò{È¥;½ž9’—‡iih_y€xqavŒœ›”}mf]kdkokbhsTW{tVUQId1͹¯¬ÄãøNˆ,¹êéÔæâåâ×¾º»ØèÒÖãìØäÝÏÛØÚàâ囤½ÑŤ½ÕæÈËýܳšrpªü÷äýÌ·¨vG#ïÇÁÆöúëÛãJ‚\VPky~¦¯Âµ¡¼½³¬ª³µ¥°ÏéëéǯÏÎÒòâÁÓȼ¯ÉË»ŽÔçáĤªÊ¿æ÷ïÓ¼ÅÓ±ÇÕËáøж¾£Øð¿”¼ÅÌ„RH6MwŸ£rB7Ä´¸Ãâù¿´œœ@dèÁØx¾À7=}íÚü - -ÈMl£¸O-LÝÎw ¤®¦€›Ÿ‘«“•……‰­µ—sp~¢ªœ~xhXQ\\_rntb>G'íÓŶºßýV¨3ËŹ½Õùþÿ굯½¼Å•šÛßáÏĦ•›ÃãéÌ™‰™ÖòÚ´»×ßÏд­²¶?\Ó ÷üÊÝëþڲňSPHYq^cw™Ö¼ž‰ehŠƒˆ­ãµš¦ÂÕ¨¥²¶°¶Îé·¨´ÈïðÛвœ¦ÏÎËËáϲžÃèÓÒÎë¾ÅƼ²Ìâ׻ˮ­æùÑô´# Љ£ÜÕŒ\SD^”‡k]MG\Á³´«ÇêÍ¢—œ§'4»±æ´J~¯Häå $"-¬°)²ÌCB¢ ß’ÃÁàÛ¸¯©“¥¬·´¡‡zŽ¡±©‡” sZDC>UiokUWiŠhBíº»¾Á¹Þ!¥ÒÚñÞÝè ß¿« ¶¯µæçîêÑÊÜÔÈÎòÎÌÇ­ÜĺÂÊâØÅÇÕŸ0RÁ×ÞËãé $àÈÇ®—·ÞÜÖɳºÓਥ¼‘“‹z“ìê¢l…·ž±ÂÀÃÑ®Žlƒ´ÔÞ×ÚÇœ¶È¾Ä·ÉøÖ¯ÁèÖž£­ÀÓÞר‚Ž»ËäïÎΩ™¿áó)§2 㸳Íûõ¶~YY‰œ˜e<Efbý¢±µªÏãÈ¡š µ)AÑŸóëmFöcl -( ×®K*™»+:×¹aª®·Æ®ˆ†ƒs~¬®°¢›”„ŸÈ¯scmYQ=DDfoUmoYWx~a;%û½¬²²Ô/Ô_©ÌÝï÷ÛÈÃÖêÜÓ¿•ªÚÕÉÊÖêââýçÖÞ³®Ôó$ÝçðÚÁÓã¾Eõ6òì×ý?öøèol–ÉàËɾ¾Å·©›´¾žn‡Ç˺æÓ˜~™¹ËòÃÂ\h˜¸¢¸ÔÔ®¦ÒöÑÃÀô åôúÓˆ„£¬Ãñýߨ©Âº®ÉàÒÈ˸¾Ö1 š4 Û³Áå§}`y™˜{NR_‚…"Ç‘Š€©ë褨³»ŸƒÉãp —]!|<$ /5 úëb‘}Þý;Ât¦Œjw©¡¡sok‚‚’ ©¦œŠ¢”\@`]R6EUjw\m•U]‰‰^ ýÇœ¥¹øQò‡¹êìÑÅÒàÀÐèÌÃöÑ¥ÄàÆÐÉÑÐËáõâÈàÚµÇòÿöÚËÎïÛ½Ž¤ŒP DËøîÊß×ÎÓÔ³šjv ¥œž­¹Þº‡›Ã½´“Š¾üëƦ€q¶«¢ÂÝÁ¥ÄÓ™e€°‘l“ÊËž²ÜÿêÀÈàçò﯋š¾ÎßãñØÏÅËÎÌø·ÇÓáÞî üì–2 -íÕì'Úžmn‹†ƒmaYYi[úÈž|q£Ðñö×ÆÒ»½§rvÑîI¬þÊåp< (#ÿ «šÖ¨ûróGÒÒ og«¨ ~ikR?BK‹¶|ijfQNFG4?\p‡…isA6Jw‡ZµˆzŸæ5¤D›Ãèóôßîä¿Ëš—ôÒÉåìÊ¿¸ËÖØîО­Ü´¿ÜÕÁË´µãÓ“_xm´£0’¿ÞÛàíÄ®­¹´˜r–ÁãÒ°„Š¦Ýïʺõêδj´×ÊŸšŸ¤ßé¾Ðã¸ÍߪŽ«¿°“¾êËžÀøöή¸¹¿äóã¹µÔñæåþéÛËÌØƸ»»ÇÒßâôí¾˜E* -6ß™yqoq}ynuN[j;óʯ¨ŸšªËâã”jpcÓâØL`È}Jÿ+Xøù³ß;ãÂóÀ·Üö⨉„{˜˜Šw^OPLq¥¦nkn_Q]ƒ•|lv|sgE&(Ng^0ß›€ªô9¸G¢ÁÆîöîĸ앶éÀ»ÛÚÕÙ͸¹ÒÒº˜¥Öر¼¸½àòãÉ‘F-QEüˆ ÒèÉÕçνÝÉŸªžË ⽞¥ÝçÜÜíÄ©­…pž²Ã³ÌÔÇèí¿ÏÄ­°³Ýø×ÙüÕ«¥ØμÂÍÓÍÿòíÞÉÓðÉÑ÷åÚƸ½¼ÒÒÝéÓÂýÿçÍœ^9;9$îšk{^dr‚ogkm<𼤧š´·ÚöøÍ@(xˆÚÃ{†û`ý»¥yA&o´ûËž=7EA ðÿïÕ½¯”}—¤Íª}hhms{x‚|qn]Zj—¨zTbK9<<5##% í£¤Èí•4˜ËÅ´±ÇÀ¦³Çèì»°µ¤¶ÑßçýÖË¡¶¨ÓìÇ¸Ö -ÖI.UfVÞ¯ºßßؽ²´áòÔÑßÎêñš–¼¿ÍÎÐÌØ«›®¦›˜¡ ÂØüÜ ‹¼ãȱîð·µêãÀÔß»±’‹”˜ÒòâÑäïÇÊÄÂÅÕðËÁââçâÁÌìÓØÇÎåÝ×ÞÐÏȲƒ=G*á¿~we7Dr¡‡{‡}u/Ì‘‘”—¹áïÞçéË™y–í¡HYø¹¡žUéŠX|©ûí4Ô]ûFTp)ñʼ¿§¨Ž…–¾¹„qkyˆlV]nnjmfxjhrZCGKSTD ÅÈôî鵮 -bÇI¸ðýÙȸ µÅØËÓÔýÚºÇ×ãòïüÜÁÊ¿×ýûÜñéé˘îÚ’'":cž­HÕÿx•›¸ÏÏßÚàÓÁ¸‘€¡‡’›µÒ¼Îèϵ®Í®­²´¯ª®é ç°•¦ËÑÌÍȹ¬©ž°´®·½¸¯†êݯ¶ÓÕÍÅ›ž‘Ÿ¸Á½ÊÕ÷ÝÙøÇ®¯ÎÍÎßöçÖÀŽ\\5å°dS\>@t—‰}Škµ™¬©§ÉøýÚÍÜƦv˜ÆQƒxŽÙðÑdÐJô»yÿøLÚKèAROøË㲟”|…iz¦¸±˜†{}Ž€aZho‡}cxYZŒm=QaaT:öÌÉí/øéå?vÒO¹ò  íÆËãÇÌÇ1ùÈÏàæÙ·ÝþïÖÍâÜ¥ÌÛ¾£Ë×£‚d`z•®{D+7€ÆèãÇÔܹ~|š¢ËÏ™¤©£¶ÑÈåëÀ¬¸ÀÉ¢ž˜ ¤ÅƯ™¢Ä§¦˜~y¯áÎÉѶ±Ú܉~¼Ö÷×Á½”u¼ÎÉÁ×ÒåàÖÍÆÀìÚ´Ô÷Ô°£« u7ß“[Z|„mqZS[oyb6ý¿•¨©¥È÷ÀÈé³¼Éxf{#ÙxíB¨üõŸüCn¹oàûùócå1 -ó«ŒÁÀ©¤œ{syž­˜—‡iL]pvg\_c[DDR[bYEYrd]C"# ( *qÚEŠÜ ûìÛÜű×öìñÓÜûð̵¶ÞÛÌƾÏ×ÕÂÏÜàüϬëÞÙο¼Ÿ‡r._ÌöôÊÇл ˆ˜°´¬ÈûÜ–Æɯ§´À¬°¤¡¯ÇÊ•€uv€´Â¶•§²­¯‚†ŸÉ¹‘š±» ©ßÖ¥•¹ÕãÔ±½Õˬž«ÑÙÙ³±²´¯·ÙçÝåÜÕÔÞ¿•’ž«ŠQ -Ñ’jr‚„g^GDS_d.ôÄ™›·¼û1ïµÎî…k|93…3 ÿ}ðLrc]X > /ºÓøõüdå2¾õ¼sQn­¶¦ˆ„palesŠŒ}S>^lin]ODB78?Ah~‹†ŽnCDöÞô[³x¤Úèãßýќ£áå»´Ø貇’ºêÜÏÕÎÕäïâçôï¼µé ÷ÒüùãÃ’ŠcL|ÐóëÑ‘†œ¬½«”ºóßÀÇúÙªœª©Œ½×ØÈ»ÀÆ¡˜‘ºà­Š²µ‘m‰¸ÕžPlÇÈ¥ˆ¶ê»¢©¯ßÌ‹y£Ö½±ÂËÓϹ¾½Ÿ«¶²¿èñâÓмƾ²›„N Öo\dc\ppupxSù½“™»Ý #úÏÙÎ* d)4–HSG¹Kk 7y ÚÂðîê~Xî2ÿdþCPUeWj€ƒv]`~d(,CIT^RQ[PANZƒ£‹•˜‘™q/ìåãüøiéc‹¾ý üþç×Í¡ÝΚ•ßÑŸšÍùÐÀÌÀâõäƸ«ªÂ®»ÍÕøüÓ²©Žs-ä5¦Ô¾›«¦“Ÿ¾ª›¯ÒäïØÍ™•³¯·½¤ ×Ü®¶³¯¯½ÉÑ¡j‚›‡ŠÍéÜ—MS~’—ÔÍÈ毟šŠ¡éöÔÛæÍÃ˨¦¹ºËÑ·¬³×íØÝÙßú¬‚ySÜ¡lNLU]`kvk]9 -Ø¥ž§ÌôõޣȼI,3‚(ûä=™à(A ŽçPÀ’äéï¥-bŽÎ!ë,Ze|”©¥~dc`^eEG_bBI_ggt~v}‡zŠƒ†¥w:& æÙë4œ(zßüþÍÀÐßò´ÂÍ×ÙìôȤ«Óýí¼¿ÏÒȳŸ¨­ÎƹÊÇÀÖäí˲ˆŒY ~³¦¡±˜–ØÚ¥·ËßçÇ‚…´Â˺̨»¸š–Œ‹ÉæÉÀÌ …—y¦éúܯtM).`‘Õö½´Ì¤¤¯‹•è6üºÚ×¥Êê´ºôÿäÖ°™ÇÛÅÒÊÕ -ÂrPRHÅŠxnnbU^sZ720Ñ´ºÈÚúÖÞíÃdWf0 A»L~‹Ð4ÕõÇn­CÖ|à«=m­Ï7\ž¨«¥†Š´¹Ÿwfed^Sg~rMBUn„‡¡„“ˆ~TfŸˆf>0/+ õíý 4Š|ß  óÌÆ·¸ëóß²°ÑùðÍïò¿¡¹à×Âáåɳ’·í -ÜÎäÞʱáìÅ“¹Ý«[T•¥‰‡Š€ªÐ縲ɺ¸¹Ÿ–ÈéÜÌÊÒ§®µ…„–²÷ùÎÊÓɿѱ•»Þת‡UGWØÊ™´¿¹¦­ áÊÌÀªìðÓÒôùýýß¹´¸É×£«Ä§Rú°t†Œƒ‰†bSR9.B%÷áÃÒù#í»ÀÇ  -êXCK$.‰Ý½‡©é+Lgm;ö͘_HÛóÚˆZu•Iæ9¡¬À›‚t‘£˜†hZzkEM]yxdWz“‘”•‘ƒa4:PGVL;?*"&•c´òû¦‘ª¿ËáìÊ»ÌéÓœÌðà®ÈÒ¤•Ï͹»È½°ÙîÍÓ×ñóÏòè´Ãú¾sbhŒ¦®‹z”¡¾ÞÕÍÔÁ¨¾çùûäÐÖ²·²”ÃÌÀéñ¸š·¿Æ»æÃÄáDz¦ºÂ†¦ž±Ñçñ×ÁÀƶǹÌîæÕÐÊÅñòðεÏÞη¼Êç±v‡ •K ýùìÈ‹„yf…`;96G["ðÞÐþ[©ˆÅ¨–n¹ÈiO1&?„o!ú&7?TlhWHF&ö¨áȨ—uÍ]_”۹Ѵ’†|„y_Rku[6Ch‘~p~z‚€‡oOH;DJ-;LB5(!+& -pÅxÛñÁ·ÊàÙÆûáÆÎ̱‹ˆÀÏÀ¿ÏÜÀ¾æÑ´ÀÜÅ“ÆáÿîÔéæÍÄÅÝûå´…b+e¾ÃÁª³ÆÜóæàüáÚÈËÕÉóýÙ×Ϻ¢Ý -èÉw%Bk„{«åÎѸ©¼Ÿ¨¸¶µ ›œ¨£³À¸£²äÞïéÎÒÃËäý úཫÆϼ¾Úä™miûêëﶢHI>LJI8Kcm×ÌÓ3Ëžû …Z…Ò‰B++IT&Þ¾°ÊÈÄî#, -‚e³¸½Äš±-¿ -èiÀÞ¿žz}r|r[\L><@c|z‡~un^XaYYrb_bhmcM>$!+×éY©ê>˜ÑßÙÜøøÉÑ÷÷óÖ–•©¹ÈÅȳ¥©Ë×¼ÄÝÙ¾ÅüòÖæð¾´¬ ¢¼ì׌iMàj¿Ùþ æÞÅæìáÍÆ¡“Äýè­¹ÔÐĨhû;KQo¶ò¼®´¸»´´®©¯§¢´®…¬Ò°·éôàú϶ÐÅ×åîÝÀ¾Â»Ï·˜³ï Ζ¾”ÚÑÇÛÝ«„zW?UPQDMTx…^ƸÍ%¤¹FË´¼I^Ü•M0HQ&äÕØÇÀ×ÁÝóöùöîåð]I…Ë·µáùÓ×9ÙZÂÙÙĨ«¯|P/,.1%&*3Yc]e^jM;NWqog^ƒ¢¥–}oJ!óÒç`£À^èÝæòøèÞñę̀£ÅÁµÍÚÝ«•µÚßÄÃÊ´ÅÆÝÅ¢ÂÊž¹½¬°Ÿµ±ˆEé ˜æãñìáÖ½î÷Îëã×Þ¼‘ Ì!ÝÊÏ¡£ƒI ö#~|s£àÑs˜ÇÁ´ÆÇ¡µÀ»¯®²¹õÙ¡¿èýþèÍźÐÁº¥¥¦¯À¡¶»²Í2ú®¨±´MêÑÉÁÂÌ›qOE`wne_ft{xUú´­Ñ=+ѨßùÄ:@Ã}2)A2îÃÑáêûîÏ·Ìæ! ULìî—¦¢ÖóîˆÖ7­ÑââÊÕÅŸw,ý)GTZV\K+EVHMwˆ€‹»Å«–pcFüøh†‡¥Û_¬Ëà×òûÕãáûÒúÌ­Å˽¹ÂÐÎöÕ¤¯ÛèÃÔȳ’ˆ§µ²Ñ¼¡|dWr½ÀîÖ»ÔØ·Èß¹äñå¼£ÎîÙä÷Á¯€”gR ?}†±æ¿“Ãϧ»Þ¿£À¯¦Á®£Ûñ³¹çǾÑÔ¥‹®äÔ¥ƒ‚¦Èª¶ÈÞ"`?쮜‡Eî×Ƴ†_E@eZ>SgzŒt@×½ÉÄÖÿüÒêéÉ)2§`AB<ýÓÏËã×¥“•Ç%Ú‹¢å\žÚ:OÞýÿŵ±ÇÅçiÿíûA}}vtnA+naVUl“˜‹Ž™Œt„xi\A3_rWOfÀòc¸ÒéîßåàíóñöàÇÓÁ²ÇàÉ«ó6úÎÕÕܪ¤Å¯Ÿœ·ÝÖÐÀ“xcüZ€{¨æÇ¥”°¦¸ÝÝáܾÌÇÚáƳ‚vteWŒ™‹^7Hqh{•›ª²ÈÝÒ¯³Ï¾¾›^“Ëη·¦Ÿæýßâûͬ§¤œž~x¯³ÇÑµß íí#úÕ¿€=# <(ïâ­qaOOrJMPeŠˆq4÷ÉÌ»«ÌåâÔéäÖ¾û'¹gm=ÝÍëé÷¹~‡¯Üî*ÍŽQ€ÞÙÈ›ÑU;ñoµª¬¼Êã¾]üèå$Iwi^fP=5%7giYbib]xxl{š€`J._[õ–àã$…ÀçÖÓÎÑèåÎÑøüñÙãíçÊþ þÛÙÏÝßÏ·—ÚèÇ°¨~aÝ*Ax¡Ç»­€¨ÔÅËÓΩ¥®Àºpp¤w;kgƒ‹j5!Y„™Š”¡Èùñ²««Ä¹ji£ÓÒ©—‹ºþúÍÊäËÓЧ±¢©½ÒìáÞ øáíçÖÈêÏs&ýø—[`a€|wpz‘žj6û¼¥ÅÆÅÜÜç ¸À êÀ}<àäÿ𾘕¢»×ê<‡%gŽ$u}È `šR’ÿQ}ÀÑÙÖ´FýòñîSb908RFCL8Ny{ƒf|nOf‰Ÿzk‰‹}m? >DôÌî9v½Bg~zt¿¸°Õí ïÚíûíôäÒÑѳ¢±ï觜“¤¶Ç«|1é³óü]e•ÍòØÇŇk‚‰••pY:-d–g=OahwS@Ÿ›’–¦ÇìÌ—›ªÓŦ¿Ê×͆…Š¶Ó½¯µÆòæØìÜÇÉÊè÷Þõåö×ÎÄЭl' íáÊŽbo£°’vd†oa1ç¾’d–¿ÁÃÓîç Žœ&ùÄq(øíîóïñüþòÐÒÏÎÓëý/f½l…Ü-`±Âhpñ"ý+V¾ÞÖÌ~ÚçõGjUIRRUWQ\k•˜vhyoV]bzhYkzP`h?&E;æäæ n©ªÆXš”Œ­ÉöôÓÈ¿ÍííñØÆÕͼÅÆàâ½Á⶜¾¿‹?Ë€zt±âá½Í-I]P àçÎÍéÕÞø' -4WKB=C+÷;|¤·­«¿ÎѪ˜§«Ìû'àµëÖªœ££ªŠ›¤…ÄîÎé çÉãðüØÈîöÜíýìÎ¥’ƒLúÍz‡¢¹¸~ZLmh7"þÉ«—Œ›Âø#ãëð×O‚ì¾\âøðæàíôùüïççÛÛë(9JϦ /d…òFƒZœ!%-k½Ô¦8ê½Í>t–lSG[bqaOYri_s•hOIeo}zVRpsA%'#%ÓÞàÔô Q ÕÞ÷Di_Jc¸³¿Ô·¾Å»½ËijÁãÔÜãñÒͽ dRfX3Au}ZVudtŒˆ©¹Ÿ}°¿¿ý-2W[RW>U[/f“¬ÙâåسÀ·«³Ðõ­»Ûª¤Ä´­ž ‡—ØçÝåãÞÙÜàîçÔÀ¨¢ßëÁ³ŸyN"-. ê—Xlš{‚aZ_d5Ðœ¨š¥î”·ãûÕ#fÏdýíñï þôñûïÖÙø$QAÁ›Ps„|¸«þ, …Þ¨-óêò!G>ax‚zc^lŽ¥ŠiELfer¤µ†[Ea€ƒumZuž£].) -ÕĬ¹×ñú/i{žž¸Øñô-5W’ž{…•¶»»°‹»ôÞº¥“¢­§pS%²^?$)YU õ/:C‚ªž®Ê 1glVr~”À¢‡š‘Oœ¿Žg—¶€j›²Ùꦌ¦ÂºÙʿʧ̘—ÁèÈÂ×͘¦˜¡Áº°ÜÙµ±ÌÞßΪ¬‡“œ«–{pa_Éü›dMhsb`Wi—E᜙ˆ©5éÌ#ÿ."²ãlO ÀiôÝù!:D'!þÞÚÔÐÉßúü Ϩ݌vek?Äðñ::ò 1tŽZ -6-MWWXOvƒnWv †wWHOciPvweS`|„wch‡ÀÆt4&êÔ»™¡ËÔÎòý"":j•“œÇåÑëCAi¾íë÷åÉÓÝ¥ ¬‘sz…t^m&ÛÖ7*9=s|¯ÇÝJRg¢Ô¼ÇÍ¿Ò ñÅáÙ˜Àª‚“Í -äµ±³²Ë°¯ÖгËʺ¯—Îà¿™»ñìÿû»§’—«—™¸×ͬ«ÆâÂÝã¥xŒŠ†s^ZS5뤋wu]YgeQB8f°ˆ1üâКq“À;˧1û\¡HLø~D6ý!TT!ñèϺÁ©Ëöÿ j>ôÔ¾x@ìDˆ¼; )-<U@EH:8Gkm[BK_KRarVV`FG|vncu€m[~›«Šn=ÿÿéîíáµ®®¶¶Õîþ,I_peˆªºß >—¢ØÜÔÃœ‹‘‘qdojRßxøöÕZ á65j²ÄÕ¯š½ÐËãáÈÏÌÍκx–Ïô óÉÈÈÅðùëËÏÖ¬Ž¨ä濬¾Õý㻨›©Æ±·³ÉìøçÓëÍ·ó㟃ŽmYU77G´qr[Tavp_OHQj…‡^ ÛÏÛª‡Äý@ut9ë–å_iVÁbH<''90)üÚȺ¶¹¾±¢²Ô*Ñ_&¿%Òµ10ÍN›ÍÄù?QA:OZ`\?&%<RV[N;V`w†wdjc[cx…š†sy¨«xS -óê꺞¯À¹É×áñ"/¥«¼´Þ1|®Ç£¥¦”’l[[¸_ÿ&\®ø]}~’áÓ’–¢¨†‚œÍðâÎÐÂÑãʽåõÒæïÏÓâÁ¶¿Ò¼»´œ¡åüÎÁ›¸ÚÝ×®„„¦ËÐÅÕôûÕÔ§ º¡ƒuL0 &,&êkClvd†ŠRNr}‚m?Ó¿²ÎÇñ '@.ÿïÂRÒ±åv¦VB8#/3ùÓÇɼÑâ໩¶ -—>øŠˆþ8©Å.×¢ÈVfQK[7#" /SYQQTo~tŠ–ŠfVK7g~m„¨¤³É«†ƒn=îäíãÔçõôðö (@ MO*8o±A^bumDD6ò¦dQ0!50OX_’ÉQtºÍµ–ËúèÕ³Žz†¯ºÙ×ßååѬÚäÌßìÖ£Ïá±Îá±€hzźÇáæî‚›–™‰ˆ·îúÝÉáùúóñݵš´¤RB&ýûéóèà£REc|s†‹c|®•oQ×µ®Ÿ°üGMCÝÅñó¸ZE|y›²U!!L/øÓÆÈÒ×ÍÒÑÊÐÒÃÒp9tï"C_ȹùLÐÁÝ Bcla@%CRjwkdsuffgŸg71D[nwv’¡¡“·×¯”^#úÜÁÌðû-9FL*$2LGúëóàɾèùõ(j„•¾êæÆ®d.PK3@CTy„þj–¥¦ äðšÂöß×È›¥æù¸Äݺ­ÛÕˆ¢âíûðÒ¼¤½òðÍäÅ…{elŸÀ´ÇÉÞ㹑‰¤°­–p}ÐýøéçíÚ»¤¶±‡vˆÔ‹ ÑÈé öʹ¶€TH}“r^ˆ²¨^' Ü—“±¬çKt™z ijâßÍ:¸µa' ,ˆ¦g'õëëéÓØѼÁËÔæÀ­±×X#®”Ž:uèìÞ»MÁÍÞ÷'SD6>OO\€‰mpƒˆ…pKVkaos„hbd~Š‘pik^g‹Œ\ëÝäßì1:AczF(8ht-úåÏÛå =E;O$  FxžŸn>GI( )ŸÐÒ»³ÓÉÕ¤ÛïãúãÉÔÞØßÿعÉÖ¦—ÇÁ¨µÍåز‚‹ŽÔàÙÑÀ–•žÌÌ¿¸£ÊÐ|~Ï̹£j·äêþçÐÒ´›¾^—+æÀ«ÓíäÅŸ•˜€_e™•sbƒ’‘pL-ƦÊÓ vÆËgë°»øq¦K‚n¸zZQ’çÉt+ûöõîéÖÆÊçýêéK -Ö -Þã>ÿìas¯£Óÿ (>iqjzˆ{M?t¡ yUSSLFi’”£›™“…ˆŠ‚‡yˆoDþÙþ&ïó%:wš–‚¿Ú«ˆŽ§œ±®Ž„uSU^{nq=)Wˆ~¶B34šÀ«¨Òпçõ ×ÎÎÁÐÉíà̸Š€°ÂÁ´¡™¡¨y–›£ÈËÇå½®¾­¼°ªˆŒ–…{²Ú¬{˜™Â ùßÑÈ©ÃãË̲_u­”Bì˽£©²~nmy|o`„•_s|eW[RÏ¢³´»)á4ÃEâœÊ "pÓÐ>2?ÇÍÔ6Å|< õñëÒÏå 3 ,r©:&̵fž²/2ƾ쉒é4-*4G\^K1EpXQ‡Ÿ…uSPTEOr“ŽŒ­¬›©°œ–Ÿ–f4)9*óñ=a–ß$<IUSIU~x[\sd[O0üã¾Â¹¾¼¼Ñâþð7tŒaKÈÓ¦•¬óéÿò¹ºÁ¨¡ÉÏÞЗ„—ºÜ䖕ûÁ¯­ÔãË®³œ²Ä¬Ãܽ˜‡­Óº§˜ÃáÁµ«­ÃÛñⳇ_€ ŠSÓ–ƒ’’uKUoon{•‹˜«oi€{xtIòÞı«Îd-…ÿ­«ó3gÌé¼æÆ,3gž¸eù®ŒG -öíìçâù,%;L¯7˜yGÑ™ -@z 8'8ÎÀí8S/0-0QZ4O†‰|nTM¦¢…YVQ=[‚‰‹¦ÉÆ©¨‘dZeXN7 ',9rÅw¨ÕìÔ§œÝô˳åëÌÈ‘–°º•„pv¤­Ì¦œ§rœ•³ïòÄ»Ý! ᶼ”kœÍÈÂèíµ½ x°ÃßÂŒ®Ë¶§Í÷ÞοÇäÔ¢®ÁŽ·Î™ÍØžw–·àöãßö ¶”§¶×éãÿåoAP|“cS!Ó¨¡¤–pWb…¡®—“Ž†s–°®Žt@ãÉæÁ—ŸþÍxÒºð=‘ÑäÀWQn}áûË`Ìngb?ú -þô>V6-;\›|VÜ„ë¸ö÷w4|aØÑç,VO9+Yx†£¦šy^GdŠˆ‹…z‡€V`‘~t”š‘Z7 0øìåEr·ÐOß÷ìíŨªÏôæÝíëÑÈÁáï;=FúѶÂÞêë΢¸°ºÔÔÇêè–c‚´ÈÙÚÊÕËÄë•\`¸Ô¤º­ŒÄè·Ä¼¥ËÍÌÑÕÑ®±œ™µ³–u*7^Ž¬ý -þÍ•±Ç¾äþàá¯B<e•šza:íõ¥ƒx€zt Î³†rn|˜”‚‰s^ÓÎÇ£y«4{C ûÒâ2}¸ÑµgÏñ‹Õµ%œ)0 ùéì  7e_** .{|+­ ÊÚ’*®Ãé¬Åö&=<--AMs™yffdƒ™ubƒŽŽ›€r™ÀbkdIB(ãÞñνÈô!KŒÈ÷8qÊßÁÛæ­³Ãõ$ýÖãÝÝûÖäø âäÍÎÖæê絤µ×Á¹ÈßþÖ‘~‹§ÑìóàΨƒ¢É£y‚¸çÒ•œ Ê¾ÀÒÀœ¶á嶵ɫ”»ÒÊ´ŽˆôBŽÑßÚÎÙäü眛ÑÊØàÚÁ:Lr‰¥]$úæáÉ pp‰{zŠˆ†nTVˆ’cg[X=åÏ®˜¥j;øÙy®žŒJϨ¿ÃQÏ€Küæâñ ùü7TD6WÌj·œ»u˨Þc›¹  ÷Ý'½Äêý÷û( ._€’–’‚™ˆlŽ’ƒ‘Œ•´§ƒs>êåäÜѹÎF’bx¨Ð߸ œ’ÛúáÒçñîÍÖóêîò×ÛÕßÞáÔÜçÓÍ˼ÍíÖ»ÑËÑÇÀ×ÛÇîùÌŒ¨¸Å­¥ÝíèÒ¡’™ÁÿæÖÕÇÚîÓ±µÓ»±ñ å¾Sï4ºóܘ–¾¶ÕÁŒ·ÎØòº‰qB*Ri„Šdôá×äÇ«ˆzxvofObmScxdPVYLùÕµ²Í(xh ÿóå |¿­7¦üvXF}C- ôéÿ*4)%4APIP™é ¼ÁÅ„çUNü’jzÐöñjvðßØÑÕÚÞ -Cq‡•¦­¥¢©›Œ˜¬¤ ›„r’ŒoU%ýüîõÜÓßçý 1x X¦º¿ÎÀÆ»™—¼üãÀÊǴϽ¨ƒ—üˤ»ß¬·Â¿¬¤¼ÊÜÞÕª¹­¸ÏÅÜéØåÚÛ½‘·Ñçö½ÉÊÊÇ«ÅÌßÍ·ÍãûÜÛáÛÓÇÖùæ¤iðS}°™–¹´¥¼ «ÁÉЫN4@k—N ÷ßÈ«†žˆ„‰{dKkzaUb`O.ëIJ¸Ó%‹˜s4Ðá9¬ŸP -ƒ²³¤u= #* ó#TOC?RmœÛKž4Bçá™14Q%¨0Ò'<Ü°Üħ™¤®ÅñJgou‡­´££œ‡†™jCC1þçôøóæÛÛÑé.\›,¹²¶·½ðùØØôöÿ¶´ÚÍ­Óñ ïø⽚˜Õí¡Œ”—¨Á»ÊÍÌ­²¥¨Â¦®ÃÈ«Š¬¶›È õÞÝ[˜ªÔÛ×ðâÒæâÑèòå¼ÈàôÌÇÉÙøÓŽ>˽ Ymj¶ÞâËeq˜± Á·f 8¦°…I÷Ø®zgCLŠ•“”›hKa‹ubafi/ä­“œÂè@©¹q*Ôà WBÛv„ÕZ$ô èÚàèé;VB^ŽÁòJ¶$k»d?®'C$7:¸âÙµü4;øïí•œ¤—²ò"*Ajx{ˆŠŠ¥œ›”{}Œv@ØÏâú ùö ôüMŒÁgèÝÓÓÉÙäææàÛèæ ™³×ÒÛë))5 -ÕÚÌá¿ÃÁÆÅœœ‚”ÍÙ¯ÃÔÜ漺ãóþ϶±È»³ ´»º½±Š°À²¹ Ë¡·åŹºžyÉïÑäÌÜÑ­§OÀwË7{}¤Óêß‚8^§©ˆ“NîÝëu˜R3 ͇e<1$W}|‚”tnRTtziY[V¬Šp{£í{ðÇDìÄg-k´]­Aúêï üõÍ­ÀÎÕò&_…ÁåB}¶ÉŠý©X¥%SÙ÷Þ ˜…4%úT"ººÆ±´ßõõ5Fqvu}gŠ»š¡”y’x6ÿèýþüõ*z¾òG¿ìâëøñï¹–š¯±ºº¿¼·ÁÄêûÓÒÞØåÐÇµß â³›sš«Èéúù¼ÁÍ×èâÿÅ ¾ÀËÊÔÚÇ×Ó¿«’ºÏÑéåëõϱ¦ÁÑ®¸ÜȺ÷ÑÆåÍ·”Œ–hà¢ÓX{‰ŒƒonŒwe> &ËßDˆ=êÕÀlGO9&ISnmQv¦Ÿ›wosng]^(½{VdÅYᨴÝuÁå×w\+óôõíðîèùÛÀ°ÂÙõ4}À-@Wfr`¯+Ñœaª$j&›À4”\)ívsàíæÒÈÚÝØáò 5O[šº‚‚ª¨£Å«|TI æûïô/NÞWoŽÄ žÉñÖ»¶‚ˆÇÍÀâåìïîÑÎÛàÕµe ÛÙÂä౬³©¹¿û ýäÀ·«ÈáìΫž§º¿¶™¢©¶¾ÝöÜÀ¾É¸Þýûé°œ®ËËÕÞ éêøÜ­ž­—kÞ¾ Q8(9}“m1"åÉ»À4ƒŠs;Þµ«qB]|II¥§Šw¥Â¢ž‚pNNlJꯩ¤“žÿ‘êÛXÆ¿@Ô¢v0|'/J;òêðýD6 ÙÕéòM­ NJ' ú:rDs…ýLy5„è-A«$Ê Ûßþåå×µ¤¨Ò×ÍÑ*/aš¥|WF>Sz“e)×ßíìïú 7uær°Ðóàš€¹Ëµ¶³ÄñÞßÎÑàßÓÐÁÊÒÞÕ|f¿òçȶ˜«ÉÒÝħ³îíôÔ×ÑÈÖÒ´˜©®Ðíöâ­¬›ªÑÞåÞÎÉ°ÐÒ­ºÑµª¶©Âüûè ¿Ž›ËÓ¼µÊƪãï‚ߘ¥ÔÚÒêV]ýÝÓûu_篚’xy}„js±‘xŽÎÛ¡‰‡xuymKPÿÊÀÝȽÒ÷5{eÍ8ô?›H+{ô*Q@&üçâü'IA÷ñA…Æ -5 ï—‰zááöR–tÎÍmZ;s(Û|ÄÞôödCÈË¿¨œºÍζ½í%% /Q_EãDQ:ùê½ÓéÞÚû)Žû_œ½ÜþýçæÚ¾²ÁÃÈÅÍÊ£–Êßß׿¡¾¾Ñ÷À—±ÆÒÊÅËÀ¾¹°¼¢§äùçÑÑôæ×½±´ËÝàÍÐúàÕèõÞØÁ½Ã’z†•ÉÏéï½ÙЦÉãЗbˆÈ¿»Æ±Π-¸PÇmkk±âÒ½ô#ñã)L·‹w–º¢yqy€h~¸”x•¬—nzurxfNàãðÚÆÑó*%Hæ—y„;.UÀÂeb(ýæÜáô-õ /T‚­Ñõà¿›c?+ÐÆ6Ÿ¶]uÓF¼ŒuÀÿN¾îìéŒx¿ÒÔ®£¥·ÅÆÕæî #õþàͶ´¹í J¨kŸÄÙÙÒØòéÏäÔÉÈÄ«¹Ò¿Êõý㢒¯ÝÍÄÙÜà;ÍÊÚôÓ¼œ†ª´¹¿îÙÇöùÈÐÕãÔÑþ£x¬áø"в²œƒg„­¡¥Þ -ðË´¯Å·ËÇËòâýÖáØ'òÞµc4OžÔðߣ²âðÛÓÚè⫯ÁË‘PPr†€‰—‘¢›rwdMXhQI=âÖÜÈÄÇÐú-"ü)¹]¤;1Þ°å§Ò;.ñÙÞæí *i”ªÇÖÆ…^=ùób´(ÒªÓ¶ V“Ç}ÂÌü÷ý¹¸úö ø®™™¥³ÈÕÅßïååþæ̵¤¢ÔCTgÐq²°¾É¼®º×øùìÿóèñÈ·Ò¹¼ÄÏØâÎâô×°“°ÔÛéëô˾Խ®ŒŒ›ª¿ÄØ­³úþÓÓÐ Óö/®×Ü&õܼ¹¥ŠœºØíäÅ¿¯¬Ÿ«Ë»ÌÛ½ßòÌ´ÕïøÚöÆÛOAE‹¤Ê¹¯Æͯ±ØÑÇØΤ˜¨©vVWuh˜·¯‡fm>8hsE6üɧŽ€±ÛõòÚ}ö`c­‘[TÐÃÎãÜëúú,!D|»ÚáÙ›Býýø¸‰AñmêïeÞ -ûæï\JúÎâíöí93ÓãÞÚß±Ž•ÒÉÉáÕÜîéñóàòÞŸ«å D‡¨ÝÕÉáç­®áóæø -õØåá¹Ï½ÆÖÔÜú Ǹ¤®š‰Ãøι·ª—¯é ᬬ°ªÍáÕ¶²ËèÞÀèÝÜÌëøÙѯUA‰¨œÑ ýðûÞ¬€®¤©ÞõÔãÚÓçèò ëÝÿãêü©ÑzYd—©¡ªº·©¡ÈìõÙË­‰‹wu€}‚zsœÆ­‘d4+N~q= -îµ{{š¾íû÷òÉðK¶ÿ!ÜìÝÿEÞŸ¨ÐáÚÓÛõ÷0,.o–ž»Öù÷Ït6!$$&-ólhÀæò»‚ÇUþ¾ÿÁ‡òàçñ·Ñ%ñûù宣¨À¿¸ÅÚæÏÄÑÖÂÚ÷öéîúL›:ÇûßßÐÑËÎîþïíß½²¹Ä¯ŽÊàÉà­šÂì꼸ÍØÈ£–ÂÞ£·Ô¨¦ð0Ú¾¤ ´Æãî䬔¼ßîðع½»ëãÀžl-T‹u™ñÔÄÃÍÄ´²ËÙÃÔÉÊôîÉàé éÚäÒ ézçšpƒ¥š›¯¯˜§¼ûÿ¶žŠŒƒrv‘ŠcU}šÃ«„ˆˆ_PX]cCáÕ¿Œ™±àóåÝãê,ŽÕá”ÊØPêi稳ÕÏÐÒÖñ$(6J`›»¶¶ÉÖà³nDAKE6-7!„ÅïµJ9qàM†ØŸ?-ò  ç#B -û׏ÑÛÎáîââÁ¨±ªÉêú$8,i¥þz¾ÞæíÚ²ÈùéáÔÂŽƒœÌ»Šz¸àÀ•umŠŸœ§ÏÚØ×ÙâĵÄÁ¼ðåÛÒɯ›°Îî ô侩½¼ïöÇÍ®ÕΛ³¾¶·ª±±™¬¶ÆçòΤŸ½ÜïÏžÄÀÊòåÝãÀ¿ÉéöÔæ àTܧ…ul’»¨“² ŠÁɲ£—µ±‘ƒŽ‚_N‚‹žpj„jWmoMïÔÔ·¨µì26óèí÷1€~B¤×éøiîÄÈáÞÝëü0+)Bg…¡·­¬Ÿ‘•Žo`[g_÷ùV˜ì£í4XèåujC‚ç¥×Ò æ,!ÖøðîðÔ¸µËì⮩µ¹ÊüCoy¡ g¸ÃÒÚêü÷ôݬ¦¢ˆŽ²ÒÉÑÆ©Çο£—¥œrsw–½òìÝ̼–§ÌïáÖåÒ¾ª§³Øº™‡£¬¤´ÌÞ½ Ð·}¥×ÝöÿÛÝÕ™ÂëÍÊ©¶×Ø«œÏûûîæòåо¹¨åÝÕèêÄy‹bx]k¤µ§°¥w€š¢Á³¶·‘xwtlt–º‡ibJquHQb[C.×ÉǽÅÚ%]PðíñÑ”3›Èrªº?Þ°Ñýøê-$"3=RlŽpW`xtWDLX.øÖÅþ/-Ô­¹uñœ›\·›Î†­¯óèäßw CA&í¤•©Æâý궵Áäl¬Åîn¼×ΩÆËàõòÓÏ®–Ÿˆ¶¿ÉÕÊé -æÑǵÂ×ᆵ ´Èæùìέ§œ­äòÜþÿŸ×Í¥¶¹Ž„m€µ´àíåÔÑò“~¾çÞð&øøÑ©ÈÔ¿ÇïçØÝÜÊÕïóÿúýÕ±¯¿ñçÎïé¡zà>rŸ­žx}zi—¸£‰~ƒª…]SRPa‘²¯˜{g}zSE;=OVp]ѹÏ6`q924¥îˆ8É[DFÁœ©Øÿ (&;MPdxxz`<:/>_D;@óñ <ÿŽ©¾òÝPSE¦xþIŽ÷ôùñƒ¬ï4P:5!ößåÆ«™Ãßåð>‚® N}ÂÀÃÛǿǵ»ÍÆâൟ{®Ùɹ¯ÑèÚÛàÏÜÈЫÏÇ´ÏƬ¤µ½ÄÌ¿ëâ½Ã³ »Ð©’À½ˆ•™‹Ëä  -áôØ“ÆïѾÒë -àÌÌÍËÄÖ) -åÚóòøø êʱ©ÁæîäÚÆäРazéo¢¢yn‡®Þ¿ƒfJGbk[^S\b“®¢•‚z™ˆV #bäkèÝ/hq‚wB"@•F(§O' õû¿¡µÁÚæ - 2BRbT/3EG?297. -ü>*  ¯SWl+[ÁñÝ$Ý·å!kÝóý °öêZŒuZUTT=๰ÉìDˆ¾c}¨¥¢˜½Óо°ÉĤ¢¯þ⤊¬ÐåäÞÇŒ¡ÙãèôÛ¶¦¸Ëâʸ¶ÂÑÛÅÎäíÓ”¹¹øø¾®†|’Éù.25÷Îê ¾ãùÊ©Ÿœ·ÝÛçüõûâÐñéíÂÀÆÁœ»éðìÇ›»å¾¹ZZà$_yŽŽœËóÌ~ga^`^ku`l|‚¦³¥œzŽ?ç÷/’Bh¥C¤ª¢kU#_­Á¹ ×ÓÈÎÓáðèàÛõ7hš|2þý %&  5$ý - õd0¥²Ûì0ªÛö´³,ùëô{´ìs¿t±(L4ñ»„T7+$=U¤O¦½ÑÄžÆßÕвŽ‘§Št®îûüóÏáùòëïÅÈÐâôíÚÔÏÛ踶Õñݨ”¾çÑǹ¼¾»È ß´·ÀÙ"í¿¨€Œ–±Áœš«Î×ô÷ù -ïÁ¹½ÑÓÊëüÝßÔÈ瓦Íó÷ÙÁÁÑöÛÄÙO^^o‚«š¡«•|opsvL\odTe¥Ð¿£~WdŒˆ`  ‡3Š7[Ÿ¼¸’h!ìÇûFZéµÙÏÌÏÚóÔ×ó./\Šƒ>ôéíîÿ -3#/ úàÂU¬d·B˜ÂÛÑdò±k$tµñçêÌ•Zn­Á¯‚H1æÀÁÎÛñCX_Ž±ÇçèÔ×ÝÜȵ©Â©¯Ïï#;ôÆ´ÓúÞÜÞïûÂÝþâæ×äñÜ’ÆØÖÎÅž§£—’©ÆÅâÿ -ëËÇÛ½·ÒÙ²uƒ®¼ÃÓâþ#ÿÖÖóô̸µ¨´ ž¯·àøùç˱°ÆÉÞÔÓÓëûçж`K\e–Ž¤mZgpip]3O|„vu·Ù²rGA]hGýú×à<­«V@†•¥féU=8Z‹0ÐÙÚÚÔÅÍÞÒé <\rPé×õû)0*,!þíý,, ôæeni€~YTOs®Ê¥ƛ9°lwèíéäƼֻ¼ÀºÇÍĸ´›aF[Ohž¨i^Ž¥±¿ÞäÅ©¶Á·ÇÖÞÛÍýÉí4겺Ðà÷ûßìè±ÕìêöïÞ–«ÃÂϺ“¤Žy¡ØãÕغÉÙÑ׿­¨„¹ùìÝ÷ôÉÒüÙÔÎÃƵ¨­â  á½ÄÍÔ¼ÈÑçô×÷é¨ýw&"T† ÀŒ’T<zˆlr–²·‰–nQ:PRé¼ÖÝÍêáø"J6øÔ;ŠE˜e‚7”/  íθÂàÝÛû>@6ðÀÃå".?L; ü&="êä°2l“§»Äž™¾Ò̳cª?ÃÚÏ¿º¹µ·µ¾´Æî"óÄ¥•’®ÇÍÓÆš†ŸÆóùõÖ¨°ÈÆÀ×àä⸨ÃƽÀÑèîÍÉçÚÚòùÔäëÛÕÁÏÍÚÈÙ»¬ÅÚÓÁÇ¡®Å±‘—ÍâØêÚÂÉçÚÕÚ±‘‘§½ÛؾÇàå»À÷$ ×ÉÉË»ÁÌ­¥êïúØÌÁ½Ð½Èì& -ÊÍÿú¯6ø -J{ »˜”ƒYdŽ‘¤ ­¾’rpR.2=DòØ×ÉÎ÷òÞÑÏßá,D¿eQúpýäÖ²Äó$$6èÎÁÑõ#41%# +ARSF2& 71 ðz’hÍÜéþåÛàöãÕÐdŸ³ƒ»›š•’“žª¦ÁØÒÞø×ÁÌÈÆÊÀ¬­ÈDz”ËؼŽ¸ÏÎƹ¨«ÆÆ®´ÊÓ‡e­ô곤ÄÂÁÝßé¼€¢©Á½·×ıªÛóØÓ¾ËÒÏÝÚãÌÆÔ¼š«ÛÝ·¢»´¶ÅÍÚçÞÜ°Áö ðÏÚëäìÞÓ¿Æ÷àèе¬¯×ßÖÍîô¾”¹âí²%®EâÌ/Nwdnƒˆ„«“‰ŸŽ¢MJX1#<?ßøã¾ÇééÏÀº×ð3Déˆ*Ë‹„ùÕÞöèÙÏâ0A.ÿüïÎÎÅÇ¿Ó'"&:?Y_=-ìYLûDElQÙ  çÉÔöɖ(±:+”Ÿ¦¡ ¯²Á­­¨zs“®¼ÛÕÅÇ¥Š°ÚÁÜé­§›ºÖÀ»·º‹c~¦çÿòïþ˵¾ÙÞǯ¥«™µäÙºŸ¦³ž“¥Æ³€ƒ£ÌàçÜÒûÛéÓÖïä’zµÐ¬£¶¶¡È ýìÊÌÕÈÍÞìÐÕߺÆÝÓÍÕöèèã³’Ãïý÷ÒáÖ«ÉÔӿȨ!ªDãÛãá -3W‘¥¢„jXb[pdO4)ýíûЯªÔáÙ×ÅäGd0¹?ùפ4/þçÝ×ÖàõûüæàÛпËãÖÇ»Ð-òú))+GX8ðN‹QæPÚËáÆåÅÇ»¿Ñß½ƒÜ”ùr˜šž¥–®àæÇÁ·®ª¬½Ôͦœ–€“Î×ÎáÅŽ¸©³´¢¥•©ÕÛÚñ óãØéóȧ´ÞìÁµ¹±êúÃŽ­æÝÆŸ¦ÊЗ¬¿ÅÎÎëôӑྡྷÇÒ£–¸¤¿³×*úijÏäçÐíׯ¼¯¡ÆÔçæáÚÞçõûÖ­¨¸®Ç³Êà­ºõþóâÁŽ:ðàÒÑÙâý/Tx†tiGKRg”P÷ý÷èýíÕµ¸ÑåÑ¯Õ >vY¶Ö3;U"ŒõøçØßùüÑ£±ÑÞʹ×ïØÍÜ+/ "/1+>“›&ØÅ'{3]ràäÐÒɸ·ËØÐvæñY”š¡ŸµØÿ%þÇ󣓦»¶¤¬¡²´ÐÈÙô¹…§¥¨¡¢»ÓØ,(ïèèëÚËÚÓÂëûØÔÖÉÁó¼ÖÝ˸ªµÊÙÞèÝÁ¨žä÷åų¼µœ†´ÎÚçÃÏÝÐÀ¾ÊëåÏÙÛÎÓ౧´¸ÆæÂÎØËÊ¿ÑòÖÒÓ®ÏÕÀèü æœã{ å±ÌÞÍÄÙøFM;:O9ìÓßßâÆàõ³Œ³äÜЫ–ß0dKÅÜÍJ„Åxúï  -ôáù øΣ¤ÆѽÀÜØÙ×ô5994+(üû  ;vÃÔÑ7û2×õF8‡ÅÎÂɦŠ–}3ó&‘®Ïßåæëÿý¼´­Ÿ£¨£¯¿Ïòúá´µúôϾÕíä¹Âóå¼ÂÝØ®È!ìÊ·ÀÔÐÓáü·›Ž©àéÒÅÚÕ³¾àðÞÆÖÔ³¢š¼ÇÔÉþؽ˾¾Á§¢áíÀ³ž¯ÁÔýÛ«ª§¬É½éÞçؾ¶ÙíÒÕÜðóìzÀkêÅ­¿Ú¼ÄÖíðåùñùíÞÇÛÙǹ¯ÇË–¼Æ»©¸Äÿù'=°ºÕ% 2-ñéöð ùæʱ¨¿ÛÙ¸¸ÀÌÕáîõ8SHþö9:M°Ú_ÿÝÌñÙã%»´½o ÊðÌŸ}x2ñ(Ê×Ѻ´© ±Û½£ÅßÏÎßšÈòû÷Õ¬´ÈÝ -üÕàùäÅÈͼ³©§ª¹Ñß³ÁÝîçáÏÐÑëÎÂØÄж˜´ÞýøýÍÁÁÇ彫•®Á°²ÔÊÌÉèد¬©²ËÐÇÏÜÖ²‰ªÒƾ²ÀôåÁÜàâæ긜žõ93¿§Çñ !õêå¿:¸Fзɳ³ÚæìٻʲÍèïöóéÓÇÈ­£¶»¸¤•µ¼½°»Æà(1©ÑÝ$êôßþ%õýÔÑðýêåíýìDz­·ì.EacD#8>EUñnâÆ/ÙìäÛ†9ÊUY>ºÕ¿©ž|"Ó’¸¬¹¼¼³™¯ÜáÊÐêãȹ¤¨½ÊÁ¦¬ÀçÙÛû ÙÄí ìÝçÔ²¹äó×ÎÒèÏ¿ÐÖÄ“¥¾Âµ·£·Òž˜¿ÆÁçÞçܽ¥åâʽ³¨ž«Ÿ§ªÃ¨žÉÔÕ½¸º´ÊàæþðØÂÉÈ’”м½Û #-¿Ø½§æΤ›©é-Ý«®Âãì÷öÃÏØu -™&Õ½ÛÊœÇûñܬ½Ë½ÈØàÅ°¸Æ¿Ëª¦­´¬²³¸ÝÖÚËÊøB8å2Kuéûüúî 8< ôàÌÈî ùõð浦ð":M[S=$ ?G48™Ü3ëçÝoûþàÊÉʦŒ\yrj(ÄìŒ×¸ØãÑÙÔÇÕèðêÚ¾³ ž·Ð¾¯©ÇÑäóÝÞÑ·êôÜÓïÞÔåð³ºÔû÷òȲ¤–ŒŒ‚š®ÐÒÍÊíÞ»£¡”¡â˶µ»À½é«ªàòÐÍàúýÛÁ µòÚÚâÍÄÊÏÔÈá÷Ó¬ÏèͲ­¹þäÎâÆÁÔçñÀÊêäÛÔ¶ÛÃGç„"¿¼Ò¹©ÎÌÀ£šàÍÝâÚÇœ§ËÚÛÒ󕦨 žÈçØßÄß,(²8°UñÒÕ×1+ üìÓÖõûéèñ÷ñíô÷ïʼÌàò $,#;Tµ#¿Ïͽ6$ 99ièï¾&<6ù½ÐvåÛßßÈÅà×÷ÏÓ¶¦¸Ä¾ÒÕÄéòÊÊÐÔèöíÐÖèßÅÎÕÉ·˜ŠÆÍëïáÓ˜{u–±§´Ä¾ÇæôòÿóöÆÆÅÎÑÛÛîâÍÛðýƯçüü'àÕÀÅûÝ®ÂÍÅÛÀ´ëý̹¾«‡Ñþ!ö×è áõ ìÞæì÷ìäëÞÍÆ­;®Dúʳ©¾¼Ë©•ˆÔôË×Üäðùýôཽ¤¸¾¶ªÂÖÓÆÕ)kÉQæm ìâÔð1#%/âÕÆÚûôàŶÏÖäôòÏÖèÚÝë4&78%,3A>O¹°#âàï×ÜÞëîÅÓÅAÈëàÀ”qä©âÎÆž¹ÕÕº¥¥¶ÁÇÓîéÁ­ÅñêÅ°ÂéÔÂÙº¬»µ›š«Ç¯®¹Åáäɼ•„£ÄÎÖòÙÓÎçàÀÎ÷ ÒðÝÝßñàÒÝûüÙ¿ÓßÛÉéöêÆÕÁÏˤ£©ÂÎÇ–™ÄÜŠŽÍûåúûÿ & ý çßÉÊÚÓðùúá ùÒšéBÛðüÓÖçíą̀¦Óò¡°Ú -j©¥KàÖÔâëÊ°ÌÜ×ÜøV‰á{1ñéúþ!4 ý& õõ ÛÊÕÎÔÑËØìéâæù &C3""*;n^rÞô{ ,Ç™¹ÃËßîãçíwŠ×y›x<V&ÌÕÃÇ×ÏÒÚÞɹ¬ÊáöâÜÉ£›³×äÅÅßé·Ž{™šŒ†¦º¸ÕëüëÒÞèÆËÿ ß¿¿Îà⺣׺•É û¡¦ÑàçãÊØ÷Ýïçá  òÖÛº°±§ž¿­£´•³¸‘¨èáÀ©±š‹½íðÑ«Àá 'äÍóí¿½ÝÚ¶ÉñùÑÀúíº{¼'Üä õè¾Æ¹·”‘»ºÆßûh;Ÿ…uûݼ »ãê¼#t¿K âÜ!*I;ßô  íç çÔûüäÖÌÇÇàãèó"<71%8E2 -46NŠ™µó´L,.ûÞÇÐÍÌæ - õì  []V_Z4‚aõüÿßÆÚèî×¹°½ÊÀ´ÁÑ£qy¾þóÏÀ¿ŸmÄáÌÓëäÕ¯ÄÒÖÝÖÆÔíØÚÍÅʲœ»Ã§šÆܳ¨Ò̽ÊÆÎêîåðîáßõ1ÌʵŸ•ž£½ÁÔéÞÀŸŸ®½µÓпÁÆÀ¾ºÅðáÓÛë&×®ÆÌÒíðùÈÖâìüÓÁ²£›X”ø -+I;Ø«¾ØÄ›¡Îìÿïð¯ÎµO¦)ð̳ª®Ùý 5Úé8±2ú÷<MC1ÔÅÓäúöâäýûöü3KêÐĹÈÎãð*I[YDC=.*!4*/kªÌáÃz7##(A=ø!9#äÊÆéøŸVl[.(0Í™ðÓÃÊÌÊȽ¶Ÿ©œŸªÃð•§ËêÞÛ£ªÈêþ åÈÕô®ÆèÚ·ÄÕÈ·Þç÷ãÕ»ÑÛÌÇ×ĹèîзÀ»ÚÞ×ΰ€•—£·ÀÄÌÑßøÒ­ ¨ÕÛ׺¦Éú׳ÉçåêÛØ÷ÍŽ›¸ÐïçÛóÞÞàð -ïÀ¤–‘š6u%*HTP[f>÷ìôÌ¥Èî xáIHßc!ÿÓ¾Êø Üü„5 %=SaS? Þæ½ßÿõÔîíUWæã¿›ÁîõD__SOEDUbX9OŒœºÓ”U2 " =\@!/<IG越ÄË€‚o=ìàä=¼çêãÖ¶—}›·ÉÆÈ­ž¯– °µµ·Ä¾¦¶ÒéüþÜÀ £¸ÙÙÊź°£ÂÔ”¤ËÉè*$çÉÆÝ÷öÔ´à÷âÆ«ÑßâíÉ¿À¸ðõܧ›—±ÒìèØÏÂÃÒ¦‰§ÜëçòûÔ«×øçÚãýýÏ¡®è™qš£ÉêÑäöðéòûÔžÂÚþØ÷B ;B[—Á©S/áÎÌè"0/56ecL0üHDŽ (pSI42;\tDßßßÛÑåò ûþõ-óëØÄÀ×öý û85:FBKdy^Wbg_}‹O?9!ÿ>>, <W'ݺ•`—hIQXèà÷w=¥»ßîÞÒÓßÑãóß«œ£©³ÉÙÙÐÍ»½ÇÅËÕÑ»¨ž– Èãײ¾Ç¾íóˉ¢ÒÜåäêÔÊÞí³§ÐÞƸª±Ýûè¡ž¨½ÄØãÑ¿ºÉÝêàÙÑÍÏÁÉ´¢¿ÛàçàìÞÔî¼ãÒéïÝ·¶éˆÔû¿¼ÙñüãÚØÖ!% ‰þÑð0¾ÓÑ«‰mFÿÛÔõ2IJüÂÃÏî)T^#Æ#“fƒ—tc}‹k-ûêîõõìǺÒû&MßãíäËÂÒÓæþÿû (8BB,9b€wdeZYTG%8>ÿ÷üàö%õ ÿ§‡íèFB^EMTg^'÷Ïè†1šÜúøäÖö¦Íòâ¼ÀÎÖÜÑÉòô¼ª–­¡·ÁÐìüÚ°¹Á¶àïáÛïôྺæøõðääãäßòêÂÔëÌ °âÝããź»äÿȤ´²ÖþÜ×àÞÈØòèͺçû×¹ÛßÞô -ý܆¡ ÖãéûîÛÂÄÐÀÝå“ïVö°¿7žÙ麰³­’5üîÜô+¹˜¤Âäðð FT%ÅÞ‚Zn»Ü¿ÃÃؾÎãö úȦ©ë%5QYæÏÜÑÂØçòòðú ?VkI*P™pRNF.!!L2 ëôî;²‚ÁŽî_GHQ<6GP ã©ÍT‹ÀÖÜæäÜ·Àãûý âÈ­ºåÜ¿ÎöåÔ¥~q•×ÝÏâÞÎÚ½¸ÅÑçíû⶜©ÏïäŵÏÜâÿæ·©éìÉÃíÒsoÁÓȹ¹ÔÚµ¦¾Ö ìò÷dzâð멤Ȱ§éýàÓ½Åÿ É›³ÜÞßöðϱ¥Ôêôø·Ž³°ðméñ»ª··¿ª2ÝÇÊØäÙ¸§£™¶äò]FÍoüubh’JR6ÏSõ˱›¼î Ù»°×:mrL%äϹÓæøýíé/LlnlW:c¶¼x`H- -JJ .WN éßêÖ®“š$3‡VyS<DGD24Ù¹­Ý*µcÂÐÌÁÆáö/îâðãÑÓÂÑ츽ÂÇÑ­ŽÊßƵ²ºÆ÷ãÄÖåàÛàÂÏéí·¤œ¨¶èðçêûØÓÑäèäÙÇÊÑÜèÚß Æ´ßéß!òÍùøЮ¸»™‰©º˜Á   áÀÈÚñ÷ÒìñÖ»ëäìز¼éíöê¼nÉHô§žÁà[ÐÇ´¾¥ ÑÝhÕ¨®¶ÂÉ̵–—¿ããþrÒ‰’^z‘ÌWÁÔŠüc&ÿвºõ&Á´ºè,E6 ÿæîå¾´âþôÝò &=^|„nI4}ðË„9 - -$,2gš5 öä×Χ™Ê¥ø`aT7AGG)ßɹ¸¾þ—'c¯ÂÆÿáººÔ -ç´ž£¦ž«Èäöõ½ÏÑàåå!ðƨœÈÖÑØôóʱºèéÌ¿õ'/ ü ͨ•²Öêý˧Ѵ­ðïøî·Êò³‘ÈÒ­¶ÕÌÍëþþÐÈÂÛñòõÛ½ÆÓÓèʵÉÖæöäæé¤WàvB-çÖÇéW™´·eg£*®˜Š“žÀÉÙЊíe$ýµ‰rtÄÌ&oþ; ʹÞøðíèÐÌ××´¬ì!ÒÉê&eyfr[‡sz$¯B -úB¼ ¤B. ìÀ°µáx°>X^pcO7.6ßÃÛ¿»ºÀß0²!‡ÂÜññïßÇÏÇæ༱½¦Ž¬Ã»ØÖÎäÙÖÊÖêìÜÙ¾¬‘œÜâàÒâðˬ¶éôîâéãõÅå;‹³ÀÕ𼜕Ìúûþè¼ÃÔ ÞØÜÚàúâ©®ÝÓÇìãèðåÜÒëïÞëس­¿èüÚÖÛWÑO)77ÛÁ´µé?l9$'ÿÍ‹Ž…žµ«•¨ÕþÐ[ÇOA&Öž…wyà— &ä'8Ðõ&89b|$ßÐÙÚÝÀÃËÊÀÁÊÇÏ^IùÓý3Y‰^L_ÁJù$È™4þø8͉×s¤(pN?? ÖÈìYUbKi…›’jJIW<ñ§µ»Çº·¿R·-X™µÚù ô»ÌéïòâÊÃʪ®ÆÈÖôéÃÀÒÑÁœ…Œ³ÍÜüÚÑõäÒàîòóôÛ¾•€†¤È×ÒÔÞáÁÐè -ôëàÝÁ±àõÜãÛÃÔãÙผ£–x|µô긪¶¼â  -ôÉ·°Ö - Ķ®ámúöͦ¡• ±ÐýäÝÑ»·¤Œ›£¸± ‘³÷-å*y2]†<¾”}“Îh÷êóÄ÷ Ìè9r¥mÔ³«ÀÇ»ÂÖÌÂßî n±Œ"7TcxmOhΞvÍQˆÉ^B8 0Æ¢ZYtyN<IlV] 'Ú4^u…~daw]÷§Ž™Œ„¦ÊÑÈÜ7nªúmÖ þÒàÿ ðÚçû¿¦ÞûñîýçϦœ˜—ºóêâÚÓïõá»÷çر½Á®ÎßììðÂßúíÇÉÝöîÉÕïôÒ–¦¥’É75üãǶ§Áì¯jgYIÙã<„“š’ž«´Ò #ëËáÇÁÍäó­˜—ûX!ðÔ¼¨ˆx¯¼ÁÚßÑÁ•££˜ŸªàÍ¡ã.RE”¤(Eƒ^à“²µñVÙôð¾!côýùC•u Ê·½ÓÝÜßÚÕòþø=åJåJ<dobip{ââñwì¶Ìb65FIE©‚xå]%G -@>Evž¨û§ò5<:Qt}}y”s'Ï•m\h…ÁÜëäÂÀçG“ûg¹ãü  ãÈÑëöçàÑÖøðËÁ¸ÌÂÈÝêÜõËÓáøØ¿×áɼ§…­îýñ -úɬÊéáðõæåôãÙÐäèèåÂÀí+,êÐÕðÜfå­ÀÍ—k^gq¡÷ Rsˆ®¢¹½ˆ£·¡°„]?C0Â/ã˺¬–—w ¬ ³¤¢¸ª µ©š½ÉÀØ×c‡•€¼ãm9¶r°Eˆ·ãêÈgÊLâÝÿQ‰Sõ¿ÑðúëëãÜ÷öÏ)&Üi‚Bb}^g‹L¨,Ú</Q][[„8`3'åœôq”°ËöJ³ƒÊç$1IZivs’Ÿ@ó¾œwdiÍ÷àÎÆ¿½Þ _ÈTáõñÙÄÈåæí -åθ¶Ô;ÚâðåîóɽÅì߸¶¡™«°¶ÆÆáóîàÖÚöìÞѪ“» ëùÝâßâü9< -é§7¶mH8&"68?*EkŸË¯ÀÓÚí?b/'ѵ¶Ã·±³‰‡ˆ„|ª±Šƒ‹¢š¡ ž±Àôÿé)ÿè.IÃ*¶6£kªé<„¯ï/*ôÑ™tMÚn1ø1ƒ›Z÷Ùóú! -üÔ¹&QZïºMkzˆàØ7UcÙ 6OŽx[©Ä™Ó;2å܆½ HuÇ<„¥“ ß#N~mydN*öÖ¾‰–²àþÞäâ°«×ü2„ÏôB™¿Í''âÕ¤”¸ÞïúóôíØÊ¿ÈáÔÄ®´±¬ÓØì#ùäòõýÞÚÒ°~Šï  ôÇ×ÕÁÚ.8 ò -ö”û´‡c,ìß ø<=4DCEKU msciY=è´™©°¬™‡wgt ¤ls™œž¬¤°ÔìºC¢hµæŠ÷ŸšÀï6u£)s-Ü¢yL³y]j‰z\Z°Ûž7 CÉ¢Hçë{¦Æ=äskf€«T„®*V†; U”¾À~Zê>QNõŠûÓ¾t´|ËìÙeÙA„‡lkdIH]VJ%ýÚ·¿Íé,"òðèæ‹ vºðú×¦Æ ÿîéôÒÀàûëÛúüÛ¿ÍÏæýí"ø¿ßêð,øÓÛíõßÑã  ÝöÎñ#ëÄØ Ó•£qS)üüðþùþþÞ¸Þ -íñéô -ø¸ˆ–µ®|¯®uShŠ…o”¸«ºÆÂâ)4Z¡o ê/ddíÌ«¾ zðgqëÍ#澈œ|v8?BØfEbë¦ÑL@äÓß`IEN ™­=Ùªw([¼)ž³±Úk«áÕÌU_^®*œMùÊç\Ô)9II=19IL9JJÌ¿ë5QA1VKÊ­­­×"kØ-P†ËúûöãÕ͹§Ôÿþöúúþ63ÈôѧâóÃÇþÒ·ÍãøíÉÂáÉõÌ%ò²µº¸P&â›q/&ãæ÷ääýí¯©ÈÒÌÊËÓ®µ±¿ÞǾ¦Œ}¤Á¢z’µ§§˜ˆ“›ƒ¸Óàíñÿ&bpö zOVf‚ÕFH/êËÐü|ÿdTöíë…ý¼•ŸÇ5+ €ÀŒ50^³˜ E™‘Ûv¡#ÿ1ΦS„ >á›–'™§bLF×ììï*5QzÚ.)ËcK˜iVñ3A-JRK]f`$Õ¿â*95EAßÌÇÇÖ 'Gy¥dÆôòÛÞðÌÕççзÈ× Ë²×ú 0+üкɿ··ÛèÂjBd§Å©¤µ›€‡s_v©Ãàßµ‰ÐÝŽ*Ö¯©ŒAü -ùê÷ÔÔÜÿåÂÔÆÐéÑÍËè—ž–§°¨œœ}š·¢¢ÒѺ»¸Åíâ 1šÔä©ÇÇw;DwÐ8T? üÿübócÄÅÇO✄¸Qè5Rk  DZþÑ#Ïò€H¤›·Ø¤I^l]ÒS w> 1=¿O{âФüâæø2T„±í å˜aW´mFÚ -A  OSOgtZ5ÎÅò  -(.2;C)íÐÕóùúR–¡Å2{•²ÄÂÕáï Ý»Ô÷âì屴ź{G,!ª…›™ˆ‹¼ýéÅëéâ 8y{Ž…›n9Ô…csxMø -æèíËæÿãÛÊìêÞßÓèòÒÄ¢—½ÀÌßÞÆ«ŸËÁ´ãëÕô·ç#R*úIÎ$TšnËòúW0‰òQi4)7)0gÒ®|®¡:ÆŒ’î]Œ±"‡îKHÇšn¦ Â…4¾£‚„¨™m?4K¢+·2åÉæBÇØÈ'O€^ú8<vñ LƒÐ1np?ÿ‹§'ÖsÕQXRN: 4X<üÈ× $9D=3:CíåèãÜäéìãÉ žëìS‚°Ý 0L/+ úçðßÛï—ZÉiLM+>C(NzfubYeŠ…¤Ê±˜”½Õšwlp…\4;+ôùî÷ Ú¯»ÖöÿöýÊ·Ñ,Ö©˜«°´Ê¿ÊÈÊÇÊÏïùæнŸ´ñ?B `Ä1|Çá¾… Ĥbúe†O(`sfdhžÎƒRu[ö•}³1c;"‘4³R†SÇ–ëÛfD5ÇźÅçãŸss„¶ØµQûéêüI#‰u»Å”b“öu  - kÌF¬ÛµMæé0±k\€Š}i],9MYVCþõ1 -/$'BYUA4 ðËêË 4*YÅÿ G|‰‘¬¥­¡«™b<6íÉ«Y-$(.ÿãÕ½ÓKA2>738(9Teif[dB" $01èììßûå´t¥Ù ó«¼°»Î¸ž¶ÔÜÎáôóúѹ¾ç6b#é"‰ùgµÎÁ½¿Ÿ¸c³úv€\iÄÁm[T£Óz# ÿ¿Œ‹¾#["ÎÒ\Ú3Ùjƒ«Á¢€lîÝÝÊè âʾ²¶£O:D!0°Õ*Îá„êf°êwGý¿<¨ÞÈz ìü;£Mż¾Í¨nH94B^p€‘uQåÖ5J7<ITZ]?>UtR'&/ýêáí #6./1Js‡ƒ„¼Ð±uy£†VM/ÿìâÛð÷S>"0ÇÍàËš´ 1 ù. <SlgT]W*9C%8JM@(þéÝÇÐü ÔÀÆÐäöéɾ«´îö% .!8->|Sâ!w¨Ì­ÀÉ™‘k£J® VhxÊ1/Õã! ž:(쬔“è^"–¿¨r߉շìèsÝʦ–²­§Ï*84Ó˜r<%]{aJ¡e{bƃ›®4èyí×å  v¼Æ‹Q-8åËpÓÝÕÍÝÅžcQLW€sU\[A¸J›~ˆ¢Ô¡G( "+-6.*6I1äß+ 9ùäãìóòÛß秲Þ%<kH01#ñéØõýù!*IE*N‰lom\SYn_X]AOUN;ôåï"$ùÎÝãÝà 462è %:W_W-5J9F[T»‡®5ª¯±ÕÓ±š{ù¢ã 9fÄE¼"!79¿r/ú­—Ç(åo¡ŠˆÁÞBt¸gÇdPc_u•˜‰¹HZT6ò¨‰‚†›´ë5ÄOÓ5-|Q¦™f(ë¾Æä °ºµ¦€G%Wÿ僾ÓÚÒÔç²lb[^kU3,!û—«“É»î( -Ú¦Tó¿Üü -FdB@3/AP'æÔ)4 '9 -  *øªÈCRT]N3(YxqM!%$,&û.-÷ MF1HJ?ntXKY|ypU*9nple+ý -ý²”Âîáò?TkTIaL?w„a6;M€¥_.ña•¦†¾ÆÍ™“«˜Es<Z,JŸ_%·*RaB=aT#}Ú<ÎÁÆ‘~£TX¡®Ò²©qH*b‘Ÿ™æG]E3 ?•ýsûG$ÖGEsCjybHÞæéýÙ¡j%çä$|ãK–³¯ËëèΑ_<H`‚m.Æ4nÑ^H,íön_2 -Õ† ëÔô@e}mL?OUdtG $20' ';%(?i`41TQØÄ#lK?=9^V9?PXG$d„a89)ñ+<.'I766=EH>ID."e”‘j@0-+6)üÀ²½ÄÜö)uwŒ±{C}™z\b^Y—ºˆ+¶} ìÖt·¿µ¸Ë¶ÊÒwcËçæ…èå·ÈÑÒ¿,ÝIQ\ã˜}‰ª'–`¬Ÿ|d; ^zªýHW-?‚—¾Ó„ëH¡«N—”›! :[^íø-)˜?ݾ½"c›©À³¦«SäSÔ+×Ú®Ú|`:(ÊRv‚u€k/øš+æå 9J<C0>A5,5J3Ûç éêéäFR6HoX0$57Kj[6-gu`Dg€[Yƒ–_2,('5LVlk2'87), -/\_B)âëbHXgNCXuU&7#ïƶ¹Üñáø*\=Qd6*P=(FUAVzž+ñãí:‡!ýð‹êÿúëÔë Õ¯®A[;ÔÛæûåÌ·¿½®W|p_ºhŠÐLu#˜ðpZ`Z0:nØMn-F°îêÒù-Bl¬/Á½)# -Sñäí 8F-ýù -æ„(éÖ˯4»:[‡˜Œ…š¡Dòƒp×ÕöOz?Q¿Ork†¢¥}.Æ>Ñ¡’“{x…{ƒˆlVRft”SV¹Qi\[xR.g„\P`]U{˜¬¾Ôø ûÝêîÝ´¦”]EH}k+1_MC(øR#7þ¶Ä\i]L ð:n8ôÙÓÐÔÍÄGC1èî5<ó .35D‚©—NCN05,l ÉÜàò Ðô•ÐéšyÍÙÜÁÇúüä×ÙÜϧ3dW€pëGc»hHWdC7@Pu¸äÿ/ 'J÷ õøwñ-9Vb¬9 -ðóó !ÿöãň=çÑÎåN÷ˆð.KKQNZ]‚”Š>ÌŸßÃøæÈyWbʉ­ØºR¯é̲›cêE–éyZQ>9/&(IaZ+\{„V>ŸŒÇŽ\Z‚icƒ…Š“rŒÞý /ŽÆ³¾­‰](/Y\c`û›sr7n–o -&//ú>V#×ļøKj<RB ôüèÐÆã@XK;1:ãö7HU|†“•E¸jBùã -ŠÐúûÄéŠéúƒaÅççͬµÍÝÞàÐÊ´X¬Øfn¢.À[ONakL4LQBE`ŽÂ:ÞFCø²‹{ˆ˜Áìôÿësà}>.1ìèõúøùÿñ̆="ö -TÞmÞ9ai[@âöD©BCä@gfé «/ý¯c&¾Úµ‹{Wã*DJ‘UH8,Cpyh_aSK>F•Ê½´þt![é{Pu£ºÛÛõ@†‘¬š1¢ øû ·§Ú''Ý›Kå‚Odw> Aj3%D<EJ064/KUR9'?jS#üñÿ #2;G_cB-:>ä +8WfORn•nâ9û»¼ùÿ1.±Âºƒ£täí w_5ŸõòŒ"$…ÒÓÇÀ¯ØÖŽ%ηP‹É´.‰H_g3 &n¤ÜfÛ -Ý‚79RJ Ù„Uq‘˜[íäëõëâã–pRK:,ZÇ\År“~m7úÑõ8hJÎô_©3=߬,ضüÎté\Ã$JaiM°ëÁÅJ!#(%[‰iD>@I&2ã 4•9õI(â¾½ {x$5f¥ãÄ’´‰o¿Ø%a\B:9%/.óÑ4MR%3bG-<I'!0Juzh_JGVOd~p* -ÿù.QF 6`F7,+B8$#E95v†`\‡®³jÖ™=uƇW¤T‚“JˆpÕìA®n{·Ù°‚‹ô|´³´ÝóÓÅ¢ˆˆPíCŒòŽ —Y:HP*òÝö0†¹^mI!ìÉÌdXµ¬ ‹pLaÁ!Oþ‹=úèÚ [=<=1N´:Ì6y®ÓÏ«k+k‰ Rå+ÃfÛwÿPx {Ûî"2I;ù•¡Žã“kddˆ‹ZDUquh>@tãgšÎ9õ‘ògòÿÝô¦$1<J°·~]Wg%Úÿs¡Ê:LÍ—Îõÿ€²H*(<P9"6IM*1>h†aP4!6B^R"ùõ)K%)YFJe~b/PW=Tw„˜}³à¯JÊ-Ž„kµÁElG©‰?z½"•ú]a)¢ï•B¯â ûúéÀN„¡ÐJô¢}QBK)ÿøþ5h»×àζ«·}¨UÙ|U5,U¥ªîµ:¾`)ëÙòú'2UÚ«@‡±ÂÖÕÅžxoÒ qŠüM¿0Úyc–ò (¦*flGÞaŠ¼ š¡¿îö¸Œ—‡}tu´Hɽî™lÊ%B>'ï†âT<W`iH#8.ÜÈ63E}˜‘XLC[†«Ã³[½a^\O'Z;3OWvqhB5'8N3"æé - /Wl~|rpy}’œrXgWPQ<P}Šž¾Âµlªó«@¶‘öẠ-Ò•RuŽóÉ,I®ÅdNLÒæ%⃔„šÕpJUP; Gprnˆ•œœ¹ÍÒþ‚Úªˆ=!Aµ”ôçsÒXúþ!£ŸÏ>n„Ù†¼´Ÿ·ÇÏÃÁau Uø¥Wã?Aÿ ùÅwÁ<¡t3‹ýeûµùLoOƨv]Z_Š -´ì±ê¹,ÀÍ—Š6.%ÖoJE@>÷ѤÊèìéìïòÙ–¦|j­ß“ñƒbK+îÍø&0OjdoŒn/--FH*÷ûö e£Ø#+MIüÝÝÙݦf 5e¡¸­œ¹ˆ‚ºQÖ®ÃE'ÝqßØ|ß;­œ Ýíòx¡•íŠ`jU½éüèÒX4ò¦¡‰ae|½Áf<^™‘ŠzmypˆÊ 6²h®9'bˆ¾ e¬ùýy«ó )1JÄU¨a( Î°¢¨¹ÐâÕ½Þ)¬Ïgöhu€†—²–1ÍÅg¬ÉÃ]€ÍK;V–¤h𨤮{j_ŽÒMÒÿpD*ô¬a²PTɾ’I!'%ÝÕöòßÖÝßÕ¾ÑéÙvo\-!iÃõi¾~cJüʬ®ÒG12L"øøçÕð2=]¢Q‚›°¯º×˨‹\v¬úû{ÈŽ~Œ˜ˆ‡¾©K²Âɨ¯å6ÂǛȕëC¥|î֌ڦÕÆò»³âmEA|«Ô཮x£Gl`aP;5ŒþðŠQd¥¹ybNO”ÞE|ŧåA(Uhr†–Ÿ÷˜øC†Ñ×η›®‰Æĵ¤«—±ëë×±¡£Î¶x«"‡¯¾ºÇÏÒÄe:}«ÀÌÒŸTàùXœ± BôʼÌ×èçú#…åRÇ~Oëa-S¨® [ÿhß#0US)øåðîÑËÌÎŽ¶ÊÑÒÅí4ÔÝ{áj^=í¢œ¿ïùÜâõíó -º–Í úS´LÐåÐÇ´ÉíäçѬŽËEäêZ’ïǶœ~‚ªšÄQ–Œ¡·ÏSQ ]GéK—WÚÏ~™;6"¨¹¿“ßÌc¿ü'ሎX‡CCL<97]ÀЇJWyœœge–ÁîA[wÀô¿#ˆ..3DafXƒ°ô¥h ÊÏÅÆn¢å°ÃÁ´œŠŽ®ÒÖ¶xF&/W‰êU£ÅÈÁ»¼ØÍ­˜“·ÐÕ¿†3™£Ç7çö+[wwF-ó:I#éŽò)lÙh ñZ­N-F€†PÕŸ¼ú6[[iX- ÿ4ðáÝÒ«¥½§‹¹PƒÓ9ßïdB?¶ÍÈ´±°¡¡Íâ̇™ä05d¸F™°ïà­”®ÃÇ¿âÿ¿¤­ú”3‰ÛÒ!Ï›…ys„+ -ëm:_·ßÕ Xô'Y~Q×¾Odç×øº«³žƒ}åpòh¡ÂÄ¢;`ªF>CIV_VSw‘iOSoyvzç3äëâ××$™»xñY$8GDG%°×3ÇßëîlªÊÒǵ¡«³¤Ž¨«‘w^(jâUªÁ³³½ÃÌ×âÕ²Áäá¥jÕð‰<9LF5ƧÒbÓ=ìYí ÂÐNïñòøD=/\m€dG?IO]E4î¹·¾¥Ÿ¾× +mTÇâQN9ûäÛÁÁ²•–ªÍ5MŒâ8²¹ÁÓ¹¯ž ­œ´Æ«°¼3µ-²ÕÁ„Š£„ˆ‰±LxEwú×Ù&½™==§êÃ9Í1/–½ù¬£°Àpy¨è/J?5J>ІL*<=YsE6`ti[KO_^p»6t+Ý°‡ti¶Vö}±D6=JPULS¯[åÆûKèÈì!![¥ËîáÔÍÑ¡‚r—¸Ë¹’M/J—t«®ÊàÞÜíÝɬÅéÞ£@H~@@$ïëþYÏÊkôäÁülÔjñ3.½æ"DâÐß9_82`eO_fskWK/Q~vV#çÅÁ¿«›¢½ß8“ ÁJQ^. òéèÍ¢™˜£ºî(L…åa³¾¸ÄÇÀ¶Ã¨±Û𮓔¤ëþ6“ º—}—³shyÐ¡ßœÍ ëõ{yMhR¯$œ!ÔÊṲ́“†kyŸª¬´ÝûÕŒO@0DrsG1IQ^[g][Te¬2÷©O65G–.„r\w}hROiàa`Ë4çÐDO‡Ã.íý éÙ­€‘¿ÎÒãÛYL`VvçlºÒôñÔÛ΢ËðןH{z¤%1#3/<àvNÍu'ÞÅkây-!—œºhåà㿼àüô&HtlI=Yk^G@L]sxB"àÁàܯŸÓþ -AìO=’n„cíÓÀ®™®Ü;yÏ<¡ÞÏ´ÉÞÆž‹¨¼º¼ÑÁ»ÔðßåÐsÕ›bIls;+Åo,*Esw*w]>YÄæ& QŸ«ê‰!ƳŽ†p‡Ÿš¡³Ïí¿qACKZm^^LCIAC_nX?8lœ¹À[# 4w±—Åv{Žš}U@T‡ÒáaûäÂû=¼Šùôë¿‘¬ÌÚÊÙéí˃K)üéœ)Œ¿±™”µåû©BÔ`§ïUG\âæý›@Kçªc-Ez®VÀ/±œ 7ýæÌ¡Î(8adzlYTll`Zi^8-+ÖŸã ýõíø UôJ~ëy‚¯¢*л¢“¥îHy«k‹ºÇÓÞÖ¾“lŒž¾ÕÏз®ÊÏÁͪƒ?Ób=K2! -ïröȺÞôsUñdY4"[ú„%&XŽñ´£‰‡„®¬˜ ¢Óí¢abwfI.0L\aP@KU_N&No”¢b801;aöÇ›Ò@ªs~YH>=Z~tåÉ´Õy«<˜°èÔº¨¬ÃÍĸÃÊéöÁC µÏ> ”»ãø&PqGÇaꀔ-;±¶vX‚Öb|O/H˜èͪÜ`Ä/¸œÁ+ÚöõºÜ-0'W…Žxehz…gXp„O ô Ù«­ãÿ÷÷ÝÞè O¦Ç•Xæha±Óp³Œ‡’«Ó7xŽÎU ¼çâÓËƪÇáÞèäÎ׳ µ¾ÓÄœ€Uíd5\G=I=*¾+%PÀÞŸkQxF-f ‚•GÝ®ýD¯>¿›¶éôáÍÁ£…˜ e3+L}‹eSU]kX?%:T§ïÇiE=<>Wž:^ë‚Ï º–wWB>$ èìßèð’@IbëåØàĪœˆ¬Û×Öðå czÓ³&hÝ8'öÉ]ýÊv:kòÞtVßÓž)èë-Šæä~b—êRDZ±-ÉÂÓÚ -ñä?|€zš¯›vB?N8òíàͳÂÊÁºÊÀîíÁÊ -?T9ëk>n›e%׿”˜Æ^‡±-«ØÜËÖÁºÊ¢·âýîãÌÞáÞδ»ŸŠojEÖ„qXJS90&ÎJK³D÷pv?ÎÀEôóNœM_¦½j&Ë+†ÿšìOp5Ñ•—Áδ{QMNm«˜hLIRYJ8O9WÅ6ÓA'?GeJQÞy%Ôœ{dAíí2YúÆ´'êÕøÆñèÓµ§ŽŠ°ÏμÃàÇ0Q7h ÐìÜë6OÔ±žt>GŽ¾‹ãt¢Ú "á+˜îè]+ƒÐYÀ‘6lǤÂöòæïýZ•«˜§²t4(+ëæ& ⻾µª¼àêü󡉽HŽ4”9:XM9þÈ¥©é&O‹ù‰ôþã×ϼ®œžÏòíãöæßóåÛ¼‰~¬°¥L»N!/óó2‡§XiE,ºðÝËéž3‚¥ò>•6‹ -Úa¿½ÉI’VéúÝ—SCGTlŽTC@BBGPG)YØt4QnK>’\,`ÇQ8 ïý¼V2/95!1f𽯶þ6L¿²´Â¶£–‰£®ÄÊlMu**a€†Œ¶˜ßÉqBUx40I9ù‹]µï)0â q‘eVŸÖMÀ e§ö#ó´°žz­þ  QŠ»©}G*ʬËòæØå3TÞ¿½ÍÓàÜØýÇÃU¿Ÿ)~BacG×ÌÒð X³"’ÎÍÔ׺«¼¯ÈåçæÞóõïòåͺ²®¤Áçô~­%-+R‘lï|ÊñÈXES}ÓD(Yåýa³6i®Oaä wc´â‰ÇƒXE$ä²lBPZIN[whis[H:C;$sõÔV4?UhuSIee.5L™¿G³œ©¦˜`:C×÷ÅØÛMR]5Ug~‹’ª»½ÊÚ¿rÀŠƒ"Cx†pD-‰öTPù(`VÑÞø¯vpš:-^®¡Ë +f–ÓCÃt·'!ß¡maœ¾àèÓMq6Ü­Šwy†£ ´×-ÖÏÛ¼Öäɦ²áèÀ¸æSs'›IVtlD1DÛâðyÝN£¤— ‘Œ¢ÁÝü鳟ÃÒÀ«Ž“¢ ¬âôØu͆qU01R{{g¼'VùHâ5°Â)±îeƒÔº;™3á}Ö—þIÓ͇Q Å‹œ£‰msg_WZz¡ÇFð›þ¦P@)AcXUR_¢Iî÷Pì•A,ïÄŽWÃÃÓçùFœ5Ó3czŸÉ•ÉÆÐæÙÇŠÚ¶¨Tu–†qhWCm˜ºÊí :!Ü½Õ ê¹”©áþ’RRi—Áî7pƒµBâVšèêÛÐÒÈÁ¯›—ÇÊ­Èóà´›ƒ•²­¥{‘ÀÆÂÃíæп¹¥˜¤¾»Ïò+aàP,IT=.btDûöú fÐy¿¯Ÿ§À¸ÊóæØÕº¸ÙÆŠoŸ­ž„–Ããôܱ¡Z,qž¢»vvT“n@ë´0\$÷]¶ÓsóÜ;¤wÉORvK!ÜŸlt¤Î¶‰„‡„[O}ÙµKîúRãÝrEB3@HH2K‡»çߨ¶„¡b@B1çŸr1ïºØñ9`Sg¯ö0LYyÿë¨ßÐǸ½¦ýkl»µ‰‡Z05^p Ü( Ö³Ô)zzD$÷£g<5<XmŸÍò5u~±:ÚF«ï妺æíÄœž“˜ž²½Ã¶—¤º–›¬’‡¤¿Öß´ ±˜eq•¾ÒÉñ@òuïE|^J, QÎy±¬ÊßÖÅÉÝÉ´Á×ÔæݯŸž³¸ÀÀÈìóÇÁ²ÅaÉxX7Ari‚ÛZ««I†“¦W2CˆÇ -ýsap_¢H<fk œKÜ—`Tk£È¦˜œš’dL=aÅí”V! ·PUCN]H$ "b†ª® ¤ÆÚéëò½~XæÒè+/!$(JZ[j›á¹íÁ××ÃÀŠ%C5‹ú â—oTHU_s¯åùûÔ·p‡‹ŠQÓgWk¿°¹Æ×D­›¬(£ßݺ¦§´Åµ¡|xŒ’z˜©¢Žr¢§x`gˆ•†gq“”¬ÒÚ˲¦|u‰ÀÝÞ?=ºXØö3K6@IQKFhÚW›¯ç缶àÚ¤¶ÕÞÙ»”¦¢®ßëëòìÉ´Ûõx×w= HG*/—¸É9)|KXÇ;{dìƒr»?šù‹îf=ðm×zL6Eb¨‡ƒt}\WI9>u= /šñ»a28OR5 ø+Fd—¼Á¿¾·›~¬!˜e?úèïûü$0+DVeÑî®ÒϽoã9ÉÌPIÇZ7Mjk`QqÎ|Ÿ½×0~1¾’ž¢³Ïí:€Ì¤sñ—ÿ‰õòÊï–«¸¤|vzy‡·Ä©iPxvyul|ƒv^Y—¦°ËæŨ®…w¢Öì>V ƒ ó7gepq]M\N‘'©×ÜêÔ»µÏÍÇíͦ˜‹™š¢ºåòèÚ·¯»ÚÙlâyïñ )¼f•©«ÎžWµç/e›º|ã7Ùö³Güª+ï'C´ýx+$8J€ŒzjQHHQ9)#ôù!N±ì N%+5 ûóø3dxŸÆÓÍ¿¥jK¦=“X/.ææòýñ"ùû$Vfq™Ý§HO ‘ä.DZ´e¤2†DYrygB(£'x£h¤Wʶ­“’¸óY¬·¡ˆæ§ôøÖέŠ™š”‡|dh•Ç¸„]Rpv|ƒš˜ŠeOp•¯Â²ˆ»’tp©Îÿ9y?©ž–‰e4<N¤2»ÛàæÒ½Á¾ÑÞÆ•už®¯¨µÌξ®ÄÕñóáرVëj2",à’áÛ}R)• qÚî‰%?€¶ÉÊ”Uøx+X^i´SA<@vyaH3ATPK*÷óP£À>--" -`‡´Ûâѯq5S¹Ry7(-1ÊÊÑå 7*$8]q ÌÑ€MXL -¨+¾{•ß^´Q¹`ULaG/om¤…ŠºÞ㙀|ŒérŠ…”©­#»‚ÿúμ§…‹Œ‡—­ª½›iX^q{†¢½¡€h`TbmuƒŒ“Ÿ”p{£ªºû%@ôyIt ¬¡“m?=Knšø~µÀнÆëÜÛê³—«µ½ÅÄâõèǾÇï;"Þ©XÔI-LF 8+ÏìÜ9Íݸ*Q¨ñªV2N˜»¿È¸Ÿ‰6ÎœŠgÎ~UK3HypI/+OE'$+íí5m¥<49887:91=Cm§ÙòÙ§b>\ÏD3­_D>N¿Ç¿Ìö3^WB??bÌc“<ã¶æ,UQ9Ò{Y›iq¦X7. Fc~¯ xtn…µKجór}ÖE…`lzÎOÇósùüɦ”~ˆ’³Á¤›xjje„‚˜·µžoWO9OUTNYŽlWij•·Ð!F4Úi=G4Qɸ{meSbÌdÐøÞÌåçÜéß±ªäâÞÕÍðèÏÉÚõß×ÞæÆÍpÛ_/GRÏw½¶nöEÇTw—Èúå¦M<j’¸¼¹ÅÑ”2ĦyýO¶X(,]M+2=/1: þ 0'WžƒK//MlU+".8_Ïöé’SQˆÚ/?ÞbakãÙ˾ÄÞöAfW52j'cóêJZ Á±¤o>J‡‡Š)Ήi?+ DFCFEr~]L\ìÓ±›¬²zfxÉ:’›o•H´àQÛùÂ’”’Ž§—‰ž±¤ Ž€rn~‰wˆ˜z<%4joiOG^s~{HMxÆì*¾P"êÂïkÞÀT,žHãùÝåÞÄ»ÔÛæÊÌâîÊÕز´ÄÓÑ®§¿Ã±Ãß{2#wÈ'†®ž<¶?/ϵ©ÁÓÚÄŠF;x©ÇÍÆÁɯ5¾‡Q•È8  -, *)&AM65HniO8J£õf 0b“ÍæË^$Du•ÐìÄxZyŸùðàÞÓÔã *7*!;¦¢»<ŸÈ­d,#WÖ¯o:g»“ˆF=BYUB;Ti?'Só,;S7î[?6OÔoŸgeí€Û?¦ðÁ©‰z¯‰bk„Œš£™fIWk]v“ƒH/7lƒw[Ctƒf—raš·äà÷#×a»³×tØê•%áóL Áت´àáÂÜ "ñºÕëØÍ»µÆÚòÌ‹ª¨¥­®`ªC(;{¿òF¦´¹f¹ˆÂèáÒ«…nU1Ù¢Â;–ÊìïÙõ›FÂX -ô­ãT&ñèþ-*;A9@WvZ1)8[dIN… -y:áì0^¡Òî¤-"3:@j‡zfby¸'D9áο¾Ïìðõ 5ÊCeÈV…•~\BWÖ äɱȘ p2156EiP69E@GA+§¿à É/;2O¯$[%0çiö…äÖ¹Žyzˆhajv†‚†ŒŒ\MKY‘§œ–|zŒ©–h\MQ¡À¥rv‘¨Ý5xáÔÊÓlpPôÄã9Ø~®¯ÚêÐÚáççÙÝòëÞÐÑØÜÛèõ¬µÛ¶£•n5L‰ÁÕ•ÊÈ·#~k¶ÝáÞÅF¨0Îi;¸ hÍòøßéå­;šÛì"GBA þô1^plOhŠX,+ASb?<†Rñ3ë5Av¯îð…$/CSjªJedÞßßÝòèàÕâý]“Å€Ù÷Hz]>¥îÒŠ{ª¡ˆdlxmgP0;KEFpƒUTÝ™Ù'm-BT{êì3””ÐsØêÕ©¬x‘“ƒ •r¤©‘‰ƒx™ š‰{‰‚s]fe{¾¢€‰¨Âë< %ûÚÄÕè5Ýä+sï\µõì×ÞÙÅÔͯ±ÃÛàëÆÌËÚÇ£´Ù¬D£USi¸ÀÀ ¾Á‰ÙXRŠºÔë¤{_ßcwïÍÈ_™¿Å®JÃLáðæÔyiS*þ 0Yuo_W€È³N6QPY^ELŸmQ·gYev—»£H#÷ñìñ0z³½-=0þôü:AïÕËØ&$ìû-\`E(àÌ{ƒöÍÄ°™ ŠzaORMNxŸ£`Ah±¾b^pˆ‡“ ?Y1¡Ã úÿÜ¿§’‘¥¢ªÀ¬wv¢¦•›™ «™{™˜“bPZB2=q£¤‰‹nÍÐÆ9@ãl˨°Âæ úé 0wßÖûðèêÓÈ«ºÇÛéÛÍÕåÚµ§Û÷ ñ™ l6?¯ªŽÞàl¤ õ? ¤t•+Q-wªRÁṳ́^ê¬¥Ú /Æ5É„a0 .XWF2ZµëTIQZq‡Š¸–çÓˆJ) -0GQ#ªOú÷#h¶ìkQäöý÷WwJûÚØèA‚T°4&0s‚†tÕÆɵ·ÌŲ”€^JNÁÈz/+LY…ˆ“«¸¤¹0_K‚0šÔ!šõ󮊤¦“” ‘|uy„š©–qzˆTLqŸ•O5TZ[[£Æ®Žzo åßÙ -. ŸO -³¤¦Äô -äëþE´.ŠÇæôùðëãäööèúï¾ÎêÙÀÑý Ì4¥]\hœÄ¢¿‹ÃÍV~Ÿ<e·¯OóÙÞë6‚ã¬l< ÔÌO ˆè‹S'øü,5DUICx˶L7MVt~Ø!¯2;0145(öÒ´.ƒ3,EVu¹ã9ü¡ÆÖáèÎÁí?RêÙî!…ãüÉXùæàóý%ÎÂË*¸§¦xSÕìåÓ tX>h’tJ79JhqŠ·Ó©ÇMRŸTªÂôfÚÙv—¯«Ž{]m{ss‰©…_kgHD]}‚|ƒŸ’~u›Å³»£–¯½·Òüþ ÂYÙÖãåúú×ÄÇçõc»#Ca—¼ ; öö첟Áò #š ¨a_‡˜­¨ý_¥¸˜ì×¾ sWñrñçµ²Þi®B½q<A—ÔI1¢ÿ m&#8BYu}œ¨¨b!LzwoyÊì¤+9?KU°èã¡P,öD•T=Qm’á1ٚɩ¯º­ŸªÔáÍ×ùD±æªFùíÛ¿¼ÐîûÚÅσqqM7i¾ÚÎ…e;?IW_ia^TNc{·×ËÎ#O÷•½É…Þ伌„“›’Œ€r{grt€†mTT;Ad…ªºª¡•~ Ñ³ ¨¾³¬œ¡Ãéûí£TæÛããÔÁÃÀÖÍÏÈüEm¥ÊYˆù7 ãâéß´Ÿ¤ç ø€÷‰SZp–¯ÁÇîI’¡”(&ϹFuÎðçͦ¸ì Jg—©|X6ú×ç#…_$Ã?ó·]&^•¥½ª—ˆ<<qŽ†©¨ªáz汦ÉU_%éÔ‰ê|]Rf… ü¯€Ë­¸®««®ÇÜæìálÛßmýÞÔÀ¾ÆÔèôðüüö!z’‘…b=A…È™cYU>;TNb„Œq`j’ÃÆñ-`-Åëé‡üÏ’_SWgxorfuš|k~ž~pQBWm€´¬©¿ªx«‘~›À©¢¦ É÷çïºt*ÝÞüÙÉ×ãŲÆô%Hy»í4€˜¼åñùïÍÚßßäìæÐ}ý„3,e˜±±ÇÖ -=k{8†GüI";…àè™2ñÆÂê!F`pR(üÑÌìs0ï9£C°c:,KÓ»—zqPOj‹”ƒ„’„s¼Vʦ7Õ=M3)CGý¥gNm€šãi=ÃË˨Êùæ×Îç" -rÔô¨1çǼ¿Êßïðêè  *i“¦^#,N‚Ÿ’nEG;'&WVOb‘ªˆe\ƒ´þo‰t•UèèðiÍÛªrTmm`dht|©­iiŽ³ ‘Š„sfqž¥™·êÖ’‰‹Œž¿£††£±ÁîôîÄh-û. -ÑÀ˺á ñß¿ÇÿImÌø ,k¤Ã½Ìº©›s= ¼p>2`«Éθ²ÆÖ De øu,#S™e!óÚÝò &A:.(ßÈ -µc€‘@¶0Í“Ž²ëë¸laup‚‘ƒ‰zjj\Pn»d Ì“µÏ¸Š•×÷¼~^i‹™¼H °ÛÐЕéSm0àÅô#_Íû™Û¾¶ÀãíÙéúöíëõ0]w|‡‚X3Fxž †}z|XEQ|xnqˆ‹…ƒ³þc¼¨sÄ…Á·Ìx«Í·’„ˆvp|}u¥¨…i—­¿«­¿r~•˜¨Éûµ”‹¿ûÑŠw¯éýÆ‚B -ÇŒ¾ãáýÛ­ž¡¶ØöDy´ºÂÓÍÔ, ¶kgDN‘ÒåÔÀÃ{E…ý4œ%êt^G3;P?% èçþÿ '! -6´5Ÿ.Í’áLà··ØÁ€y{ ´¥ŽiYg\{°ÏJÕ¢«¹‹fk¬Å°™‡«Ïå=ä|ÓÜɵ¼ä 'źÍö2€Õ ´:ÊÁÖïáÖùøéßûA`ijYPE=I€­³¢ }n\Qt‰—Œ•Š©µüUŒ·Žpû“¥·(ËâßϦp²¤Žž…”¥š¬¸²ÊÀ“”•¡¿À×åÖ¯—–Éè¦}’Ž€Áöä{7ÿÓ³ªßñࢪ½ËÖƼÚ.Qh`YYb^^WL- "K<F’ã×6æ…àQ(b2Šx~kE$!é ü#517 ,j¼ùG'ö2¹Ú)ÐÃÒü À®¢¸Ð¼™pjvˆ¨òû Ÿû¥¬¶¨‰¢©¬½ÜûKÎP¸Ç°ÈÀàÔØØж¸Ðû(RŒ¼ÒÐ0þý÷óÿü  7MLFHMI@C\z™¬®pŽ…¬º¼£˜™²¯µáWª¿¯D®ÊËÿM¥äùÜÀ‘[t’¦¢ž‡ŠÚ⻶¹Â¼¹œ˜©™§¯µÃȽ¯¹Ê¢eŒÇ±¢½ó()Út;-Æ×óíÙÏÓµµß×Ìɹ«¢¬Âë ',ÿ 1" *>.1QgëtµlƒºØÇ‘s!8ZcJ$ýò&Hú7GVZ3;bQOcêè -¡µÄæô½ÈÕí¥Š~‡‡¥ªÑA•špáðÍ­˜˜³¨¬ë/'£1§Õ´›ÂÛ¼©·ÂÆÁÇôM~‹ŒˆmK,    (B;&6.*8RWI0)Noˆ†l“âÖÈòû³§ÁÊ´ˆ¦CÆÏÁ#¾ÿ -#N–ÙòúÌŠbDKf•³Ä³»ý´ª´¶´ž••…Œš’¤ºË½À­y¤É³°¹øÅ€Zúñ÷츛ÀÖåðÞŵ œš¨²ºÞÿáÙìúûøïAeyV¬äŽp3×¹ãJ¥Y" 479C1û   3? ý0IJSBDEE"ï& qj {‚¦ÕàÆØö¸~evŠ¦ ‘…—¸ÝB'"á”}£¹ÃÍfñwȨ̂¬Ö팴ÇÎÜô*Š¿¤kU5;;305 ý -"Is—h"($õüz¤†x”ë6 ø25õÁ­¹g4Ù{W\\ÈþÿìÀd:Ear™ÉÔÙà°š²ŸŽÀ¹•ƒ—¥©‰¨·»´À¾·¾»À³©Åí®y‰`ðÛö õû%ýЦ–”—¯ÌÚá÷úòÉÈíóéîP„€0…pÇÓê¢yŒª–ZT`B-&(<J:" 59 3;÷ï*:8AUnmJþå" |xš>KVœUXˆã,+"AP2à‹\Pgš–~VGAT‹C"øñä­|µÃñò°iÐݶÃÙê \ No newline at end of file diff --git a/build/lib/WORC/resources/fastr_tools/elastix4.8/testdata/output/TransformParameters.0.txt b/build/lib/WORC/resources/fastr_tools/elastix4.8/testdata/output/TransformParameters.0.txt deleted file mode 100644 index 91fb51c3..00000000 --- a/build/lib/WORC/resources/fastr_tools/elastix4.8/testdata/output/TransformParameters.0.txt +++ /dev/null @@ -1,31 +0,0 @@ -(Transform "AffineTransform") -(NumberOfParameters 6) -(TransformParameters 1.093378 0.007227 0.007167 1.160360 2.611043 -8.332901) -(InitialTransformParametersFileName "NoInitialTransform") -(HowToCombineTransforms "Compose") - -// Image specific -(FixedImageDimension 2) -(MovingImageDimension 2) -(FixedInternalImagePixelType "float") -(MovingInternalImagePixelType "float") -(Size 256 256) -(Index 0 0) -(Spacing 0.6250000000 0.6250000000) -(Origin -57.6875000000 -250.7380000000) -(Direction 1.0000000000 0.0000000000 0.0000000000 1.0000000000) -(UseDirectionCosines "false") - -// AdvancedAffineTransform specific -(CenterOfRotationPoint 22.0000000000 -171.0505000000) - -// ResampleInterpolator specific -(ResampleInterpolator "FinalBSplineInterpolator") -(FinalBSplineInterpolationOrder 3) - -// Resampler specific -(Resampler "DefaultResampler") -(DefaultPixelValue 0.000000) -(ResultImageFormat "mhd") -(ResultImagePixelType "short") -(CompressResultImage "true") diff --git a/build/lib/WORC/resources/fastr_tools/elastix4.8/testdata/output/TransformParameters.1.txt b/build/lib/WORC/resources/fastr_tools/elastix4.8/testdata/output/TransformParameters.1.txt deleted file mode 100644 index 9d8fece1..00000000 --- a/build/lib/WORC/resources/fastr_tools/elastix4.8/testdata/output/TransformParameters.1.txt +++ /dev/null @@ -1,37 +0,0 @@ -(Transform "BSplineTransform") -(NumberOfParameters 722) -(TransformParameters -0.797651 -0.899812 -0.567982 -0.090251 0.362533 0.664447 0.698055 0.613911 0.562796 0.655900 1.003181 1.493262 2.014318 2.408660 2.515107 2.422683 2.171719 1.875230 0.967992 -2.461451 -3.294072 -2.989131 -2.078819 -0.436468 1.006800 1.282175 0.924471 0.529309 0.601374 1.663309 3.272003 4.893039 6.099638 6.440101 6.232003 5.669377 4.985743 2.694170 -3.492840 -5.158785 -5.538924 -4.754331 -1.951626 0.907262 1.404768 1.063566 0.810686 0.287207 1.923911 4.717488 7.143864 8.771270 9.033556 8.564957 7.723691 6.767274 3.698100 -4.651166 -7.635104 -9.899493 -9.992501 -5.470303 1.198635 4.474355 -0.035367 3.493754 3.721981 2.919594 5.398357 9.049066 11.448164 11.357541 11.154067 10.442510 9.107388 5.028431 -5.508803 -9.765550 -13.444123 -14.896448 -16.443444 -17.454890 2.877532 -2.209845 -1.559854 -4.244879 2.913068 7.399367 10.088452 13.125830 8.382072 11.826689 12.708447 11.592334 6.492623 -6.110422 -11.190107 -14.976982 -15.721853 -16.258194 -24.481343 -4.035109 -3.426838 -3.999801 -9.691043 -1.826314 2.721312 12.508926 20.034075 5.554020 11.606275 14.180833 13.915499 7.921519 -6.415946 -10.979084 -12.654546 -8.279417 -3.958570 0.985696 4.470790 0.385194 -5.401817 -6.656889 -4.629888 3.855928 19.404527 9.526424 6.173852 13.187612 16.000229 15.680896 9.056849 -6.233209 -9.534005 -11.325951 -11.701062 -1.026067 13.842419 14.833562 5.806137 -6.204052 -6.962267 -4.870293 4.944642 21.074258 16.323212 12.559078 18.162075 18.108465 16.953317 9.675191 -5.373064 -7.793744 -12.382515 -11.120500 15.193489 29.788790 14.669896 6.074739 -2.056573 -5.890166 -10.683056 1.463330 23.153573 19.821541 14.660159 24.681986 20.109813 17.829823 9.546722 -4.221134 -6.274873 -7.573220 -0.537523 11.613887 20.979552 12.064490 8.131696 -2.478781 2.252529 -7.429946 6.595663 23.919208 7.722238 25.301113 34.915814 22.552897 18.057429 8.887785 -3.117568 -4.679225 -3.428620 -0.786712 -0.641903 13.947812 10.616244 4.962987 4.203297 12.435095 11.312713 12.252099 16.665379 15.996207 29.351193 31.610889 23.285369 17.354009 7.914249 -2.331078 -4.869155 -3.173977 -1.010591 1.581692 9.198612 7.141775 4.981958 10.156463 6.882965 16.356922 18.924815 16.130277 27.575780 29.583346 26.725624 22.071866 15.845139 6.793222 -1.911926 -3.392847 -1.686127 -2.362780 -4.382990 0.047746 4.529209 10.468984 22.207666 30.592126 32.523104 26.068070 18.478559 21.170734 24.665363 23.517681 18.964724 13.656880 5.691560 -1.747298 -3.970517 -5.185951 -4.709722 -3.848449 -6.080596 -1.473843 11.705482 25.906850 39.869830 34.973801 26.962045 23.124642 16.953551 17.377569 16.334589 15.076240 11.200847 4.620072 -1.509334 -3.774132 -5.124485 -2.201081 -1.096552 -12.798254 -12.898217 7.737426 17.344800 31.229131 35.005551 25.743114 19.164374 17.747893 10.698369 11.906915 12.800504 8.856976 3.586501 -1.279334 -3.308635 -5.056468 -5.203882 -6.580460 -10.078012 -7.737325 2.290724 12.503907 28.042879 26.084067 17.510828 20.555660 16.152833 9.558606 10.971153 9.735785 6.758396 2.645081 -1.069484 -2.982135 -4.125922 -4.627283 -7.633528 -9.083527 -6.661872 -0.682921 7.184959 17.683118 21.633125 17.964700 16.766790 11.779693 9.423979 7.755794 7.198624 5.189986 1.808954 -0.906470 -2.562865 -3.585384 -5.080281 -7.090940 -8.279197 -5.993148 -0.967060 5.201046 11.763855 15.453521 14.435299 12.137977 9.857751 8.343902 6.666854 5.470708 3.822061 1.200683 -0.506160 -1.562869 -2.252581 -3.114357 -3.924161 -4.119366 -3.063539 -1.145910 1.235795 3.437035 4.789294 5.378051 5.335494 4.850748 4.060466 3.096270 2.162370 1.409372 0.353455 -0.555436 -0.725854 -0.725165 -0.648112 -0.455749 -0.310517 -0.366454 -0.941514 -2.354692 -4.235969 -6.214128 -7.902458 -8.913712 -9.115503 -8.366089 -7.053716 -5.436391 -4.022811 -1.507695 -1.300621 -1.886926 -2.086836 -2.148542 -1.940635 -1.298551 -0.179473 0.039828 -2.128943 -5.763870 -9.714044 -13.120286 -15.309234 -16.081678 -15.224244 -13.268419 -10.504822 -7.964339 -3.321799 -1.708202 -2.463913 -2.936769 -3.025215 -2.659649 -1.946355 1.028167 1.357463 -0.084560 -4.959923 -9.602684 -13.535535 -16.388568 -18.228653 -17.963406 -16.016699 -12.707030 -9.544060 -4.115991 -2.175724 -3.435463 -5.255959 -3.359257 -1.422844 -5.172098 5.297310 3.685483 4.740534 -5.044062 -14.383971 -18.616189 -18.648906 -19.588740 -19.845593 -18.901226 -15.195141 -11.296495 -4.981858 -2.521729 -2.808321 -0.056822 0.256129 -1.253442 1.691947 2.866641 7.154755 9.335955 2.012132 3.931860 -1.177297 -13.682887 -15.297196 -18.096738 -20.670993 -17.370105 -12.852099 -5.677349 -3.044758 -3.447015 -0.923977 -0.584051 -0.689704 15.281009 10.775409 1.526753 4.936696 6.897297 0.667728 -4.537007 -3.070824 -10.084834 -24.200490 -21.178257 -17.985612 -13.630392 -6.022361 -4.030899 -6.934797 -8.251689 -4.713070 -1.099935 3.974921 3.880922 -3.416493 -0.272204 2.272196 -2.618114 -7.354444 -6.025054 -3.219405 -16.996541 -17.860017 -16.873360 -12.838707 -5.741038 -4.941427 -10.363386 -16.045509 -21.272333 -15.860056 -9.080074 -5.627943 -4.804500 -8.161901 -12.384997 -16.197556 -13.674651 -8.983933 -5.021218 -10.954066 -16.083392 -14.577457 -10.537619 -4.815267 -5.236294 -10.509735 -17.081680 -22.701040 -12.161820 -9.534964 -8.604416 -11.949161 -9.025737 -8.719827 -14.971248 -14.730373 -3.317161 -2.840357 -9.735728 -9.448991 -8.367386 -6.800985 -3.220060 -5.026055 -9.348339 -11.741405 -10.053122 -0.237850 0.923093 -0.749137 -2.010690 -6.953768 -5.569397 -2.136054 -4.532084 2.146556 -1.495442 -2.990384 -4.730911 -3.231085 -2.982801 -1.603328 -4.395468 -8.004802 -8.689402 -8.335020 -9.516769 -4.790815 1.387008 4.191299 1.403052 -4.853382 1.377804 -5.308374 3.488954 5.696952 8.635010 2.455407 0.694899 -0.386035 -0.612491 -3.565433 -6.626123 -8.747806 -8.541076 -6.541104 3.716750 7.777842 5.499565 7.473210 -1.345177 -3.560004 1.789624 4.741276 11.574867 8.732917 5.670990 3.128788 1.074157 -0.051927 -2.645883 -4.285452 -6.835496 -8.361655 -2.507119 7.781381 9.497913 9.412890 10.686927 14.682033 5.547949 3.681238 7.506884 9.801204 7.252453 5.171466 3.328438 1.479063 0.273967 -1.647160 -0.770311 0.940032 4.011459 12.405884 18.628435 14.649402 9.034598 12.525080 16.206794 9.743341 0.871755 3.059074 6.612828 0.677273 -1.654634 1.570818 1.334416 0.449203 -0.799287 0.803731 2.763396 8.524214 14.090057 14.637087 12.992319 9.954128 -1.238963 -9.587698 -9.312351 -4.467326 -3.962055 2.396159 0.079794 -0.483891 1.925344 1.174223 0.557005 -0.070496 2.287001 5.763372 13.173688 12.838631 8.248917 9.662476 9.463713 4.988427 -0.673747 -6.059197 2.574450 6.081590 0.011343 0.713316 3.471379 1.607415 0.963703 0.582313 0.525017 2.782754 5.588656 9.203668 8.739954 6.836195 6.961536 6.137012 3.909369 2.261940 6.750399 10.432726 6.691149 1.036708 0.610912 1.052737 1.062051 0.913165 0.500690 0.878069 2.738563 4.084548 5.470234 5.688882 5.254938 5.078195 4.734200 3.233367 3.391413 6.472089 6.021188 3.762429 1.556880 0.693657 0.529338 0.836436 0.676182 0.389880 0.754030 1.713982 2.126502 2.472723 2.532172 2.454984 2.347356 2.189486 1.927189 1.871937 2.209528 2.305316 1.764839 1.014431 0.494629 0.228224 0.207345 0.252693 0.179219) -(InitialTransformParametersFileName "output/TransformParameters.0.txt") -(HowToCombineTransforms "Compose") - -// Image specific -(FixedImageDimension 2) -(MovingImageDimension 2) -(FixedInternalImagePixelType "float") -(MovingInternalImagePixelType "float") -(Size 256 256) -(Index 0 0) -(Spacing 0.6250000000 0.6250000000) -(Origin -57.6875000000 -250.7380000000) -(Direction 1.0000000000 0.0000000000 0.0000000000 1.0000000000) -(UseDirectionCosines "false") - -// BSplineTransform specific -(GridSize 19 19) -(GridIndex 0 0) -(GridSpacing 11.0060504422 11.6752721522) -(GridOrigin -74.4434104873 -284.4608503394) -(GridDirection 1.0000000000 0.0000000000 0.0000000000 1.0000000000) -(BSplineTransformSplineOrder 3) -(UseCyclicTransform "false") - -// ResampleInterpolator specific -(ResampleInterpolator "FinalBSplineInterpolator") -(FinalBSplineInterpolationOrder 3) - -// Resampler specific -(Resampler "DefaultResampler") -(DefaultPixelValue 0.000000) -(ResultImageFormat "nii.gz") -(ResultImagePixelType "float") -(CompressResultImage "true") diff --git a/build/lib/WORC/resources/fastr_tools/elastix4.8/transformix.xml b/build/lib/WORC/resources/fastr_tools/elastix4.8/transformix.xml deleted file mode 100644 index d7dd21c8..00000000 --- a/build/lib/WORC/resources/fastr_tools/elastix4.8/transformix.xml +++ /dev/null @@ -1,123 +0,0 @@ - - A wrapper around transformix (part of elastix). elastix is open source software, based on the well-known - Insight Segmentation and Registration Toolkit (ITK). The software consists of a collection of algorithms that are - commonly used to solve (medical) image registration problems. The modular design of elastix allows the user to - quickly configure, test, and compare different registration methods for a specific application. A command-line - interface enables automated processing of large numbers of data sets, by means of scripting. - - - - - - - - - - - - - - - - - - - - - - - - - - - transformix version: 4.800 - - transformix applies a transform on an input image and/or generates a deformation field. - The transform is specified in the transform-parameter file. - - Call transformix from the command line with mandatory arguments: - -out output directory - -tp transform-parameter file, only 1 - - Optional extra commands: - -in input image to deform - -def file containing input-image points; the point are transformed - according to the specified transform-parameter file - use "-def all" to transform all points from the input-image, which - effectively generates a deformation field. - -jac use "-jac all" to generate an image with the determinant of the - spatial Jacobian - -jacmat use "-jacmat all" to generate an image with the spatial Jacobian - matrix at each voxel - -priority set the process priority to high, abovenormal, normal (default), - belownormal, or idle (Windows only option) - -threads set the maximum number of threads of transformix - - At least one of the options "-in", "-def", "-jac", or "-jacmat" should be given. - - The transform-parameter file must contain all the information necessary for transformix to run properly. That - includes which transform to use, with which parameters, etc. For a usable transform-parameter file, run elastix, - and inspect the output file "TransformParameters.0.txt". - - Need further help? - Check the website http://elastix.isi.uu.nl, or mail elastix@bigr.nl. - - - - - - - - - - - - - - - - high - abovenormal - normal - belownormal - idle - - - - - - - - - - - - - - - - - - @article{KleinStaring:2010, - author = "{S. Klein AND M. Staring AND K. Murphy AND M.A. Viergever AND J.P.W. Pluim}", - title = "{elastix: a toolbox for intensity-based medical image registration}", - journal = "{IEEE Transactions on Medical Imaging}", - volume = "{29}", - number = "{1}", - pages = "{196 - 205}", - month = "{January}", - year = "{2010}", - } - - - diff --git a/build/lib/WORC/resources/fastr_tools/elastixtools/bin/create_def_transform.py b/build/lib/WORC/resources/fastr_tools/elastixtools/bin/create_def_transform.py deleted file mode 100644 index 28b3b682..00000000 --- a/build/lib/WORC/resources/fastr_tools/elastixtools/bin/create_def_transform.py +++ /dev/null @@ -1,120 +0,0 @@ -#!/usr/bin/env python -import argparse -import os -import subprocess -from elastixparameterfile import ElastixParameterFile - - -def create_def_transform(input_transformation, output_transformation, deformation_file=None, verbose=False): - """ - Create a deformation transformation from any other transformation. This - will call elastix to create the deformation field and creates a new - transformation file based on the input transform. - - :param str input_transformation: path of the input transformation - :param str output_Trasnformation: path to write the output transformation - :param bool verbose: flag to control verbosity - """ - output_dir = os.path.dirname(output_transformation) - - if deformation_file is None: - command = ['transformix', - '-tp', input_transformation, - '-out', output_dir, - '-def', 'all'] - - if verbose: - print('Running transformix...') - - proc = subprocess.Popen(command, stdout=subprocess.PIPE, stderr=subprocess.PIPE) - stdout, stderr = proc.communicate() - - if proc.returncode == 0: - if verbose: - print('Finished successfully!') - else: - if verbose: - print('Encountered errors:\n{}'.format(stderr)) - print('Aborting!') - return - - # Create the output deformation field file - if verbose: - print('Clean up output...') - output_deformation = os.path.splitext(output_transformation)[0] + '.def.nii.gz' - os.rename(os.path.join(output_dir, 'deformationField.nii.gz'), output_deformation) - else: - output_deformation = deformation_file - - # Remove log - if os.path.exists(os.path.join(output_dir, 'transformix.log')): - os.remove(os.path.join(output_dir, 'transformix.log')) - - # Create the deformation file - if verbose: - print('Creating transformation file...') - create_def_transform_file(input_transformation, output_transformation, os.path.abspath(output_deformation)) - - -def create_def_transform_file(input_transformation, output_transformation, deformation_field): - """ - This function reads an elastix transform file and creates a deformation transformation. - It create the fields for the deformation tranformation and copies the fields related to - the output sampling etc from the input transformation. - - :param str input_transformations: the path of the input transformation file - :param str output_transformation: path of the output file to be created - """ - if not isinstance(input_transformation, str): - raise TypeError('Input transformation need to be a str containing the path of the transformation file!') - - if not isinstance(output_transformation, str): - raise TypeError('Output transformation needs to be a str where to write the new transformation to') - - # Read the input transform - input_transform = ElastixParameterFile(input_transformation) - - # Create a ElastixParameterFile object - output_transform = ElastixParameterFile() - output_transform.addline(comment=' Initial transform') - output_transform['InitialTransformParametersFileName'] = 'NoInitialTransform' - output_transform['HowToCombineTransforms'] = 'Compose' - output_transform.addline() - output_transform.addline(comment=' Deformation transform') - output_transform['Transform'] = 'DeformationFieldTransform' - output_transform['DeformationFieldFileName'] = deformation_field - output_transform['DeformationFieldInterpolationOrder'] = 1 - output_transform['NumberOfParameters'] = 0 - - # Copy fields from input transform to output - output_transform.addline() - output_transform.addline(comment=' Image specific') - output_transform['FixedImageDimension'] = input_transform['FixedImageDimension'] - output_transform['MovingImageDimension'] = input_transform['MovingImageDimension'] - output_transform['FixedInternalImagePixelType'] = input_transform['FixedInternalImagePixelType'] - output_transform['MovingInternalImagePixelType'] = input_transform['MovingInternalImagePixelType'] - output_transform.addline() - output_transform.addline(comment=' ResampleInterpolator specific') - output_transform['ResampleInterpolator'] = input_transform['ResampleInterpolator'] - output_transform['FinalBSplineInterpolationOrder'] = input_transform['FinalBSplineInterpolationOrder'] - output_transform.addline() - output_transform.addline(comment=' Resampler specific') - output_transform['Resampler'] = input_transform['Resampler'] - output_transform['DefaultPixelValue'] = input_transform['DefaultPixelValue'] - output_transform['ResultImageFormat'] = input_transform['ResultImageFormat'] - output_transform['ResultImagePixelType'] = input_transform['ResultImagePixelType'] - - # Save transform to file - output_transform.write(output_transformation) - - -if __name__ == '__main__': - # Parse arguments and call main function - parser = argparse.ArgumentParser(description='Create a deformation field transform based on another elastix transformation file') - parser.add_argument('--in', metavar='IN', dest='input', type=str, required=True, help='The transform convert to deformation field tranform') - parser.add_argument('--out', metavar='OUT', dest='output', type=str, required=True, help='The path to write the resulting transform to') - parser.add_argument('--def', metavar='DEFORMATION_FIELD', dest='deform', type=str, required=False, - help='DeformationField to use for the Transform (if not given, it creates one using the elastix on the PATH') - - args = parser.parse_args() - create_def_transform(args.input, args.output, args.deform, verbose=True) diff --git a/build/lib/WORC/resources/fastr_tools/elastixtools/bin/create_mean_transform.py b/build/lib/WORC/resources/fastr_tools/elastixtools/bin/create_mean_transform.py deleted file mode 100644 index 3e4655d6..00000000 --- a/build/lib/WORC/resources/fastr_tools/elastixtools/bin/create_mean_transform.py +++ /dev/null @@ -1,68 +0,0 @@ -#!/usr/bin/env python -import argparse -import copy -from elastixparameterfile import ElastixParameterFile - - -def create_mean_transform_bin(input_transformations, output_transformation): - """ - This function reads a number of elastix transform files, creates the mean transformation and writes it back to the specified output path. - - :param input_transformations: the path of the input transformation files - :type input_transformations: iterable of str - :param output_transformation: path of the output file to be created - """ - if not all(isinstance(x, str) for x in input_transformations): - raise TypeError('Input transformations need to be a str containing the path of the transformation file!') - - if not isinstance(output_transformation, str): - raise TypeError('Output transformation needs to be a str where to write the new transformation to') - - input_transformations = [x for x in input_transformations] - reference_transformation = ElastixParameterFile(input_transformations[0]) - - # Outsource to dedicated function - output_transform = create_mean_transform(reference_transformation, input_transformations) - - # Save transform to file - output_transform.write(output_transformation) - - -def create_mean_transform(reference_transform, input_transformations): - """ - Given a list of transformation paths, and a reference object, create a new object that is the mean transform - - :param ElastixParameterFile reference_transform: The reference transformation object (for defining the target space etc) - :param input_transformations: The paths of the transforms to create a mean of - :type input_transformations: list of str - """ - if not all(isinstance(x, str) for x in input_transformations): - raise TypeError('Input transformations need to be str paths!') - - if not isinstance(reference_transform, ElastixParameterFile): - raise TypeError('The reference transform needs to be an ElastixParameterFile object') - - output_transform = copy.deepcopy(reference_transform) - - # Get the weighting vector for the transforms - weighting = [1.0 / len(input_transformations)] * len(input_transformations) - - # Substitute relevant fields - output_transform['Transform'] = 'WeightedCombinationTransform' - output_transform['TransformParameters'] = weighting - output_transform['NumberOfParameters'] = len(weighting) - output_transform['InitialTransformParametersFileName'] = 'NoInitialTransform' - output_transform['ResultImagePixelType'] = 'float' - output_transform['SubTransforms'] = input_transformations - - return output_transform - - -if __name__ == '__main__': - # Parse arguments and call main function - parser = argparse.ArgumentParser(description='Combine elastix transformation to create a MeanTransform') - parser.add_argument('--in', metavar='IN', dest='input', type=str, nargs='+', required=True, help='The transforms to combine') - parser.add_argument('--out', metavar='OUT', dest='output', type=str, required=True, help='The path to write the resulting transform to') - - args = parser.parse_args() - create_mean_transform_bin(args.input, args.output) diff --git a/build/lib/WORC/resources/fastr_tools/elastixtools/bin/elastixparameterfile.py b/build/lib/WORC/resources/fastr_tools/elastixtools/bin/elastixparameterfile.py deleted file mode 100644 index 210202e9..00000000 --- a/build/lib/WORC/resources/fastr_tools/elastixtools/bin/elastixparameterfile.py +++ /dev/null @@ -1,317 +0,0 @@ -#!/usr/bin/env python -from collections import OrderedDict, MutableMapping -import re - - -class ElastixParameterFile(MutableMapping): - """ - ElastixParameterFile is a dictionary object to allow access to parameter file in a style like:: - - >>> params = ElastixParameterFile('/path/to/file/params.txt') - >>> params[key].value - >>> params[key].value = 'new_value' - >>> params[linenr].value - >>> params[key].comment - >>> params[key].comment = 'This inserts/changes the comment on this line' - >>> params[linenr].comment - >>> params[key].linenr - - ElastixParameterFile is a MutableMapping, meaning it offers all functionality of a dict object. - You can index both on setting key as well as line number. The returns values are ElastixParameterLine - objects that give access to a key, value, comment and linenr. This allow easy manipulation of certain - lines in the parameter file. - """ - class ElastixParameterLine(list): - def __init__(self, data): - if len(data) != 4: - raise ValueError( - 'ElastixParameterLine must have 4 components!') - - if (not isinstance(data[0], int) or - not (isinstance(data[1], (float, int, str, tuple, list)) or data[1] is None) or - not (isinstance(data[2], str) or data[2] is None) or - not isinstance(data[3], str)): - raise TypeError('ElastixParameterLine must be of types [int, list/None, str/None, str], found [%s, %s, %s, %s]' % (type(data[0]).__name__, type(data[1]).__name__, type(data[2]).__name__, type(data[3]).__name__)) - - if data[1] is not None: - if isinstance(data[1], (int, float, str)): - data[1] = [data[1]] - - data[1] = [self.parse_value(v) for v in data[1]] - - super(ElastixParameterFile.ElastixParameterLine, self).__init__(data) - - def __repr__(self): - if self.value is None: - key_val_str = '' - elif len(self.value) > 10: - key_val_str = '({} [...({:d} elem)...])'.format(self.key, len(self.value)) - else: - value_str = ' '.join([self.unparse_value(v) for v in self.value]) - if len(value_str) > 15: - value_str = '{}...'.format(value_str[:15]) - - key_val_str = '({key} {value})'.format(key=self.key, value=value_str) - - if self.comment is None: - comment_str = '' - elif len(self.comment) > 15: - comment_str = '//{}...'.format(self.comment[:15]) - else: - comment_str = '//{}'.format(self.comment) - - return ''.format(nr=self.linenr, keyval=key_val_str, comment=comment_str) - - def __str__(self): - if self.value is None: - return self.comment_str - elif self.comment is None: - return self.key_value_str - else: - output = '{key_value} {comment}'.format( - key_value=self.key_value_str, - comment=self.comment_str) - - return output - - @property - def linenr(self): - return self[0] - - @property - def value(self): - return self[1] - - @value.setter - def value(self, value): - # Make sure value is a list - if isinstance(value, (str, float, int)): - value = [value] - elif not isinstance(value, list): - try: - value = list(value) - except TypeError: - value = [value] - - self[1] = value - - @property - def key_value_str(self): - if self.value is None: - return '' - - return '({key} {value})'.format(key=self.key, value=' '.join([self.unparse_value(v) for v in self.value])) - - @property - def comment(self): - return self[2] - - @comment.setter - def comment(self, value): - if not isinstance(value, str): - raise TypeError('Comments have to be of str type!') - - if value[0] != ' ': - value = ' ' + value - - self[2] = value - - @property - def comment_str(self): - if self.comment is None: - return '' - - return '//{comment}'.format(comment=self.comment) - - @property - def key(self): - return self[3] - - @staticmethod - def parse_value(item): - """ - Parse a value in an elastix parameter file and cast it into the right - type. Supported types are string, integer and float. - """ - if isinstance(item, (int, float)): - return item - - if item[0] == '"' and item[-1] == '"': - item = item[1:-1] - else: - try: - item = int(item) - except ValueError: - try: - item = float(item) - except ValueError: - item = str(item) - - return item - - @staticmethod - def unparse_value(item): - """ - Parse a python variable into the format used in an elastix parameter - file. Supported types are string, integer and float. - """ - if isinstance(item, str): - item = '"%s"' % item - else: - item = str(item) - - return item - - """ - Create a ElastixParameterFile object. If filename is given the file is read - and parsed into the object. - """ - _re_line_parse = re.compile(r'\s*(\(.+\s+.*\))?\s*(//.*)?') - _re_keyvalue_parse = re.compile(r'\((\S+)\s+(.*)\)') - _re_value_parse = re.compile(r'(".*?"|-?\d+\.?\d*)') - - def __init__(self, filename=None): - self._data = OrderedDict() - - if filename is not None: - self.parse(filename) - - def parse(self, filename): - """Load an elastrix parameter file and parse it into the ElastixParameterFile object. - """ - self._data = OrderedDict() - - if filename is not None: - with open(filename, 'r') as input_file: - for linenr, line in enumerate(input_file): - match_obj = re.match(self._re_line_parse, line) - - if match_obj.group(1) is None: - key = 'dummy_%d' % linenr - value = None - else: - submatch = re.match(self._re_keyvalue_parse, match_obj.group(1)) - key = submatch.group(1) - value = re.findall(self._re_value_parse, submatch.group(2)) - - if match_obj.group(2) is None: - comment = None - else: - comment = match_obj.group(2)[2:] # Strip of // - - self._data[key] = self.ElastixParameterLine([linenr + 1, value, comment, key]) - - def __getitem__(self, key): - if isinstance(key, str): - return self._data[key] - elif isinstance(key, int): - out = next((value for value in self._data.itervalues() if value[0] == key), None) - if out is None: - raise KeyError('Line not found in parameter file') - - return out - else: - raise TypeError('Key is of incorrect type!') - - def __setitem__(self, key, value): - comment = None - - if not isinstance(key, str): - key = self[key].key - - # If we get a ElastixParameterLine, insert as is - if isinstance(value, self.ElastixParameterLine): - # Unpack the desired fields - comment = value.comment - value = value.value - - # Check to update value or insert a new line - if key in self._data: - self._data[key].value = value - else: - if not isinstance(value, list): - value = [value] - line = len(self._data) + 1 - self._data[key] = self.ElastixParameterLine([line, value, comment, key]) - - def __delitem__(self, key): - if isinstance(key, str): - del self._data[key] - else: - # Try to get a proper str key - key = self[key].key - del self._data[key] - - def __iter__(self): - return self._data.__iter__() - - def __len__(self): - return len(self._data) - - def __repr__(self): - return ''.format(len(self._data)) - - def __str__(self): - output = '\n'.join([str(v) for v in self._data.values()]) - - return output - - def addline(self, key=None, value=None, comment=None): - if key is None and value is not None: - raise ValueError('Adding a value with a dummy key seems like a BAD idea!') - - if key is None: - key = 'dummy_{}'.format(len(self)) - - if key in self._data: - raise ValueError('Cannot add a line with an already existing key!') - - linenr = len(self) + 1 - - self._data[key] = self.ElastixParameterLine([linenr, value, comment, key]) - - """ - Write the ElastrixParameterFile object back to an actual file on the disk. - """ - def write(self, filename): - with open(filename, 'w') as outfile: - outfile.write(str(self)) - -if __name__ == '__main__': - import argparse - - parser = argparse.ArgumentParser() - parser.add_argument('--infile', '-i', metavar='input_transform.txt', required=True, help='the elastix parameter file to modify') - parser.add_argument('--outfile', '-o', metavar='output_transform.txt', required=True, help='the resulting elastix parameter file') - parser.add_argument('--set', '-s', metavar='key=val', nargs="*", help='the items to override in the parameter file') - parser.add_argument('--verbose', '-v', action="store_true", help='use verbose output') - - args = parser.parse_args() - - input_file = args.infile - output_file = args.outfile - if args.set is not None: - substitutions = OrderedDict([x.split('=', 1) for x in args.set]) - else: - substitutions = OrderedDict() - VERBOSE = args.verbose - - if VERBOSE: - print('Loading input {}'.format(input_file)) - - params = ElastixParameterFile(input_file) - - for key, value in substitutions.items(): - substitutions[key] = [params.ElastixParameterLine.parse_value(x) for x in value.split(',')] - - if VERBOSE: - print('Substituting values') - for key, value in substitutions.items(): - print('Set "{}" to {}'.format(key, value)) - - params.update(substitutions) - - if VERBOSE: - print('Writing result to {}'.format(output_file)) - - params.write(output_file) diff --git a/build/lib/WORC/resources/fastr_tools/elastixtools/bin/transformixpoint2json.py b/build/lib/WORC/resources/fastr_tools/elastixtools/bin/transformixpoint2json.py deleted file mode 100644 index e9eb3878..00000000 --- a/build/lib/WORC/resources/fastr_tools/elastixtools/bin/transformixpoint2json.py +++ /dev/null @@ -1,38 +0,0 @@ -import argparse -import json -import re - - -def main(): - parser = argparse.ArgumentParser(description='Create a JSON from an transformix output points file') - parser.add_argument('--in', metavar='IN', dest='input', type=str, required=True, help='The output points to parse') - args = parser.parse_args() - - output = {'inputindex': {}, - 'inputpoint': {}, - 'outputindex': {}, - 'outputpoint': {}, - 'deformation': {}} - - with open(args.input) as fin: - for line in fin: - match = re.match('Point\s+(?P\d+)\s+; InputIndex = \[(?P[\s\d]+)\]\s+; InputPoint = \[(?P[\s\d\.-]+)\]\s+; OutputIndexFixed = \[(?P[-\s\d]+)\]\s+; OutputPoint = \[(?P[\s\d\.-]+)\]\s+; Deformation = \[(?P[\s\d\.-]+)\]', line) - if match: - sample_id = match.group('id') - output['inputindex'][sample_id] = [int(x) for x in match.group('inindex').split()] - output['inputpoint'][sample_id] = [float(x) for x in match.group('inpoint').split()] - output['outputindex'][sample_id] = [int(x) for x in match.group('outindex').split()] - output['outputpoint'][sample_id] = [float(x) for x in match.group('outpoint').split()] - output['deformation'][sample_id] = [float(x) for x in match.group('deform').split()] - else: - raise ValueError('Could not parse line: {}'.format(line)) - - print('__INPUTINDEX__ = {}'.format(json.dumps(output['inputindex']))) - print('__INPUTPOINT__ = {}'.format(json.dumps(output['inputpoint']))) - print('__OUTPUTINDEX__ = {}'.format(json.dumps(output['outputindex']))) - print('__OUTPUTPOINT__ = {}'.format(json.dumps(output['outputpoint']))) - print('__DEFORMATION__ = {}'.format(json.dumps(output['deformation']))) - - -if __name__ == '__main__': - main() diff --git a/build/lib/WORC/resources/fastr_tools/elastixtools/createdeftransform.xml b/build/lib/WORC/resources/fastr_tools/elastixtools/createdeftransform.xml deleted file mode 100644 index d0b03108..00000000 --- a/build/lib/WORC/resources/fastr_tools/elastixtools/createdeftransform.xml +++ /dev/null @@ -1,39 +0,0 @@ - - A tool that creates a deformation transform based on any ElastixTransformFile - - registration - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - diff --git a/build/lib/WORC/resources/fastr_tools/elastixtools/createmeantransform.xml b/build/lib/WORC/resources/fastr_tools/elastixtools/createmeantransform.xml deleted file mode 100644 index d2ea4f0c..00000000 --- a/build/lib/WORC/resources/fastr_tools/elastixtools/createmeantransform.xml +++ /dev/null @@ -1,36 +0,0 @@ - - A tool that creates a mean transform based on a list of ElastixTransformFile files - - registration - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - diff --git a/build/lib/WORC/resources/fastr_tools/elastixtools/elastixparameterfile.xml b/build/lib/WORC/resources/fastr_tools/elastixtools/elastixparameterfile.xml deleted file mode 100644 index 8e9788c3..00000000 --- a/build/lib/WORC/resources/fastr_tools/elastixtools/elastixparameterfile.xml +++ /dev/null @@ -1,38 +0,0 @@ - - A tool that can substitute fields in an ElastixParameterFile - - registration - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - diff --git a/build/lib/WORC/resources/fastr_tools/elastixtools/elastixtransformfile.xml b/build/lib/WORC/resources/fastr_tools/elastixtools/elastixtransformfile.xml deleted file mode 100644 index d35e7e43..00000000 --- a/build/lib/WORC/resources/fastr_tools/elastixtools/elastixtransformfile.xml +++ /dev/null @@ -1,38 +0,0 @@ - - A tool that can substitute fields in an ElastixTransformFile - - registration - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - diff --git a/build/lib/WORC/resources/fastr_tools/elastixtools/transformixpoint2json.xml b/build/lib/WORC/resources/fastr_tools/elastixtools/transformixpoint2json.xml deleted file mode 100644 index f4a2f053..00000000 --- a/build/lib/WORC/resources/fastr_tools/elastixtools/transformixpoint2json.xml +++ /dev/null @@ -1,45 +0,0 @@ - - A tool that creates a mean transform based on a list of ElastixTransformFile files - - registration - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - diff --git a/build/lib/WORC/resources/fastr_tools/itktools/0.3.0/pxbinaryimageoperator.xml b/build/lib/WORC/resources/fastr_tools/itktools/0.3.0/pxbinaryimageoperator.xml deleted file mode 100644 index cbd9bf7b..00000000 --- a/build/lib/WORC/resources/fastr_tools/itktools/0.3.0/pxbinaryimageoperator.xml +++ /dev/null @@ -1,67 +0,0 @@ - - A wrapper around ITK Tools, as set of simple command line tools for image analysis. - - - - - - - - - - - ITKTools v0.2.2 - Performs binary operations on two images. - Usage: - pxbinaryimageoperator - -in inputFilenames - [-out] outputFilename, default in1 + ops + arg + in2 + .mhd - -ops binary operator of the following form: - {+,-,*,/,^,%} - notation: - {ADDITION, WEIGHTEDADDITION, MINUS, TIMES,DIVIDE,POWER, - MAXIMUM, MINIMUM, ABSOLUTEDIFFERENCE, SQUAREDDIFFERENCE, - BINARYMAGNITUDE, MASK, MASKNEGATED, LOG} - notation examples: - MINUS = A - B - ABSDIFF = |A - B| - MIN = min( A, B ) - MAGNITUDE = sqrt( A * A + B * B ) - [-arg] argument, necessary for some ops - WEIGHTEDADDITION: 0.0 < weight alpha < 1.0 - MASK[NEG]: background value, e.g. 0. - [-z] compression flag; if provided, the output image is compressed - [-opct] output component type, by default the largest of the two input images - choose one of: {[unsigned_]{char,short,int,long},float,double} - Supported: 2D, 3D, (unsigned) char, (unsigned) short, (unsigned) int, (unsigned) long, float, double. - - - - - - - - - - - - - - - - - - - - - - - - - - - diff --git a/build/lib/WORC/resources/fastr_tools/itktools/0.3.0/pxcastconvert.xml b/build/lib/WORC/resources/fastr_tools/itktools/0.3.0/pxcastconvert.xml deleted file mode 100644 index bdc8ed14..00000000 --- a/build/lib/WORC/resources/fastr_tools/itktools/0.3.0/pxcastconvert.xml +++ /dev/null @@ -1,97 +0,0 @@ - - A wrapper around ITK Tools, as set of simple command line tools for image analysis. - - - - - - - - - - - ITKTools v0.3.1 - Description: - This program converts between many image formats. - This is done by reading in an image, possibly casting of the image, - and subsequently writing the image to the user-specified format. - - Definitions: - - converting: changing the extension of the image, e.g. bmp, mhd, etc. - - casting: changing the component type of a voxel, e.g. short, float, - unsigned long, etc. - - Notes: - - Casting of scalar images is done by the itk::ShiftScaleImageFilter, - where values are mapped to itself, leaving the intensity range - the same. NB: When casting to a component type with smaller dynamic - range, information might get lost. - - Casting of multi-component images, such as vector or RGB images, is - done using the itk::VectorCastImageFilter. - - Input images can be in all file formats ITK supports and for which - the itk::ImageFileReader works, and additionally 3D dicom series. - It is also possible to extract a specific DICOM series from a directory - by supplying the seriesUID. - - Output images can be in all file formats ITK supports and for which - the itk::ImageFileWriter works. Dicom output is not supported yet. - - - Usage: - pxcastconvert - -in inputfilename - -out outputfilename - [-opct] outputPixelComponentType, default equal to input - [-z] compression flag; if provided, the output image is compressed - OR pxcastconvert - -in dicomDirectory - -out outputfilename - [-opct] outputPixelComponentType, default equal to input - [-s] seriesUID, default the first UID found - [-r] add restrictions to generate a unique seriesUID - e.g. "0020|0012" to add a check for acquisition number. - [-z] compression flag; if provided, the output image is compressed - - OutputPixelComponentType should be one of {[unsigned_]char, [unsigned_]short, - [unsigned_]int, [unsigned_]long, float, double}. - NB: Not every image format supports all OutputPixelComponentTypes. - NB2: Not every image format supports the compression flag "-z". - - - - - - - - - - - - - unsigned_char - char - unsigned_short - short - unsigned_int - int - unsigned_long - long - float - double - - - - - - - - - - - - - - - diff --git a/build/lib/WORC/resources/fastr_tools/itktools/0.3.0/pxcastconvertdicom.xml b/build/lib/WORC/resources/fastr_tools/itktools/0.3.0/pxcastconvertdicom.xml deleted file mode 100644 index a215b6da..00000000 --- a/build/lib/WORC/resources/fastr_tools/itktools/0.3.0/pxcastconvertdicom.xml +++ /dev/null @@ -1,99 +0,0 @@ - - A wrapper around ITK Tools, as set of simple command line tools for image analysis. - - - - - - - - - - - ITKTools v0.3.1 - Description: - This program converts between many image formats. - This is done by reading in an image, possibly casting of the image, - and subsequently writing the image to the user-specified format. - - Definitions: - - converting: changing the extension of the image, e.g. bmp, mhd, etc. - - casting: changing the component type of a voxel, e.g. short, float, - unsigned long, etc. - - Notes: - - Casting of scalar images is done by the itk::ShiftScaleImageFilter, - where values are mapped to itself, leaving the intensity range - the same. NB: When casting to a component type with smaller dynamic - range, information might get lost. - - Casting of multi-component images, such as vector or RGB images, is - done using the itk::VectorCastImageFilter. - - Input images can be in all file formats ITK supports and for which - the itk::ImageFileReader works, and additionally 3D dicom series. - It is also possible to extract a specific DICOM series from a directory - by supplying the seriesUID. - - Output images can be in all file formats ITK supports and for which - the itk::ImageFileWriter works. Dicom output is not supported yet. - - - Usage: - pxcastconvert - -in inputfilename - -out outputfilename - [-opct] outputPixelComponentType, default equal to input - [-z] compression flag; if provided, the output image is compressed - OR pxcastconvert - -in dicomDirectory - -out outputfilename - [-opct] outputPixelComponentType, default equal to input - [-s] seriesUID, default the first UID found - [-r] add restrictions to generate a unique seriesUID - e.g. "0020|0012" to add a check for acquisition number. - [-z] compression flag; if provided, the output image is compressed - - OutputPixelComponentType should be one of {[unsigned_]char, [unsigned_]short, - [unsigned_]int, [unsigned_]long, float, double}. - NB: Not every image format supports all OutputPixelComponentTypes. - NB2: Not every image format supports the compression flag "-z". - - - - - - - - - - - - - unsigned_char - char - unsigned_short - short - unsigned_int - int - unsigned_long - long - float - double - - - - - - - - - - - - - - - - - diff --git a/build/lib/WORC/resources/fastr_tools/itktools/0.3.0/pxcombinesegmentations.xml b/build/lib/WORC/resources/fastr_tools/itktools/0.3.0/pxcombinesegmentations.xml deleted file mode 100644 index 1aa14fd1..00000000 --- a/build/lib/WORC/resources/fastr_tools/itktools/0.3.0/pxcombinesegmentations.xml +++ /dev/null @@ -1,56 +0,0 @@ - - A wrapper around ITK Tools, as set of simple command line tools for image analysis. - - - - - - - - - - - - - - - - - - - - - - - - STAPLE - VOTE - MULTISTAPLE - MULTISTAPLE2 - VOTE_MULTISTAPLE2 - - - - - - - - - - - - - - - - - - diff --git a/build/lib/WORC/resources/fastr_tools/itktools/0.3.0/pxcomputeboundingbox.xml b/build/lib/WORC/resources/fastr_tools/itktools/0.3.0/pxcomputeboundingbox.xml deleted file mode 100644 index 79445132..00000000 --- a/build/lib/WORC/resources/fastr_tools/itktools/0.3.0/pxcomputeboundingbox.xml +++ /dev/null @@ -1,67 +0,0 @@ - - A wrapper around ITK Tools, as set of simple command line tools for image analysis. - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - slice047.mhd - - {bin} - -in - {input.input[0]} - - 0 - 0 - 255 - 255 - -57.6875 - -250.738 - 101.688 - -91.3630 - - - - - - - - - diff --git a/build/lib/WORC/resources/fastr_tools/itktools/0.3.0/pxgaussianimagefilter.xml b/build/lib/WORC/resources/fastr_tools/itktools/0.3.0/pxgaussianimagefilter.xml deleted file mode 100644 index 05a63fe3..00000000 --- a/build/lib/WORC/resources/fastr_tools/itktools/0.3.0/pxgaussianimagefilter.xml +++ /dev/null @@ -1,71 +0,0 @@ - - A wrapper around ITK Tools, as set of simple command line tools for image analysis. - - - - - - - - - - - -in inputFilename - [-out] outputFilename, default in + BLURRED.mhd - [-std] sigma, for each dimension, default 1.0 - [-ord] order, for each dimension, default zero - 0: zero order = blurring - 1: first order = gradient - 2: second order derivative - [-mag] compute the magnitude of the separate blurrings, default false - [-lap] compute the laplacian, default false - [-inv] compute invariants, choose one of - {LiLi, LiLijLj, LiLijLjkLk, Lii, LijLji, LijLjkLki} - [-opct] output pixel type, default equal to input - Supported: 2D, 3D, (unsigned) char, (unsigned) short, (unsigned) int, (unsigned) long, float, double. - - - - - - - - - - - - - - - LiLi - LiLijLj - LiLijLjkLk - Lii - LijLji - LijLjkLki - - - unsigned_char - char - unsigned_short - short - unsigned_int - int - unsigned_long - long - float - double - - - - - - - - - - - - - - diff --git a/build/lib/WORC/resources/fastr_tools/itktools/0.3.0/pxgetimageinformation.xml b/build/lib/WORC/resources/fastr_tools/itktools/0.3.0/pxgetimageinformation.xml deleted file mode 100644 index c0ccdb93..00000000 --- a/build/lib/WORC/resources/fastr_tools/itktools/0.3.0/pxgetimageinformation.xml +++ /dev/null @@ -1,58 +0,0 @@ - - A wrapper around ITK Tools, as set of simple command line tools for image analysis. - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - diff --git a/build/lib/WORC/resources/fastr_tools/itktools/0.3.0/pxintensityreplace.xml b/build/lib/WORC/resources/fastr_tools/itktools/0.3.0/pxintensityreplace.xml deleted file mode 100644 index fda4191f..00000000 --- a/build/lib/WORC/resources/fastr_tools/itktools/0.3.0/pxintensityreplace.xml +++ /dev/null @@ -1,56 +0,0 @@ - - A wrapper around ITK Tools, as set of simple command line tools for image analysis. - - - - - - - - - - - This program replaces some user specified intensity values in an image. - Usage: - pxintensityreplace - -in inputFilename - [-out] outputFilename, default in + LUTAPPLIED.mhd - -i input pixel values that should be replaced - -o output pixel values that replace the corresponding input values - [-pt] output pixel type, default equal to input - Supported: 2D, 3D, (unsigned) char, (unsigned) short, (unsigned) int, - (unsigned) long, float, double. - If "-pt" is used, the input is immediately converted to that particular - type, after which the intensity replacement is performed. - - - - - - - - - - - - - - - - - - - - - - - - - - - diff --git a/build/lib/WORC/resources/fastr_tools/itktools/0.3.0/pxmeanstdimage.xml b/build/lib/WORC/resources/fastr_tools/itktools/0.3.0/pxmeanstdimage.xml deleted file mode 100644 index 90b93d7b..00000000 --- a/build/lib/WORC/resources/fastr_tools/itktools/0.3.0/pxmeanstdimage.xml +++ /dev/null @@ -1,57 +0,0 @@ - - A wrapper around ITK Tools, as set of simple command line tools for image analysis. - - - - - - - - - - - ITKTools v0.2.2 - This program creates a mean and standard deviation image of a set of images. - Usage: - pxmeanstdimage - -in list of inputFilenames - -inMask list of inputMaskFilenames - [-outmean] outputFilename for mean image; always written as float - [-outstd] outputFilename for standard deviation image; always written as float, - [-popstd] population standard deviation flag; if provided, use population standard deviation - rather than sample standard deviation (divide by N instead of N-1) - [-z] compression flag; if provided, the output image is compressed - Supported: 2D, 3D, (unsigned) char, (unsigned) short, float, double. - - - - - - - - - - - - - - - - - - - - - - - - - - - - diff --git a/build/lib/WORC/resources/fastr_tools/itktools/0.3.0/pxmorphology.xml b/build/lib/WORC/resources/fastr_tools/itktools/0.3.0/pxmorphology.xml deleted file mode 100644 index 310a709f..00000000 --- a/build/lib/WORC/resources/fastr_tools/itktools/0.3.0/pxmorphology.xml +++ /dev/null @@ -1,90 +0,0 @@ - - A wrapper around ITK Tools, as set of simple command line tools for image analysis. - - - - - - - - - - - ITKTools v0.2.2 - Usage: - pxmorphology - -in inputFilename - -op operation, choose one of {erosion, dilation, opening, closing, gradient} - [-type] type, choose one of {grayscale, binary, parabolic}, default grayscale - [-out] outputFilename, default in_operation_type.extension - [-z] compression flag; if provided, the output image is compressed - -r radius - [-bc] boundaryCondition (grayscale): the gray value outside the image - [-bin] foreground and background values - [-a] algorithm type for op=gradient - BASIC = 0, HISTO = 1, ANCHOR = 2, VHGW = 3, default 0 - BASIC and HISTO have radius dependent performance, ANCHOR and VHGW not - [-opct] pixelType, default: automatically determined from input image - For grayscale filters, supply the boundary condition. - This value defaults to the maximum pixel value. - For binary filters, supply the foreground and background value. - The foreground value refers to the value of the object of interest (default 1), - the background value is by default 0, - It is not only intended for binary images, but also for grayscale images. - In this case the foreground value selects which value to do the operation on. - Examples: - 1) Dilate a binary image (1 = foreground, 0 = background) - pxmorphology -in input.mhd -op dilation -type binary -out output.mhd -r 1 - 2) Dilate a binary image (255 = foreground, 0 = background) - pxmorphology -in input.mhd -op dilation -type binary -out output.mhd -r 1 -bin 255 0 - Supported: 2D, 3D, (unsigned) char, (unsigned) short. - - - - - - - - - - - - erosion - dilation - opening - closing - gradient - - - grayscale - binary - parabolic - - - - - - - 0 - 1 - 2 - 3 - - - - - - - - - - - - - - - diff --git a/build/lib/WORC/resources/fastr_tools/itktools/0.3.0/pxthresholdimage.xml b/build/lib/WORC/resources/fastr_tools/itktools/0.3.0/pxthresholdimage.xml deleted file mode 100644 index 443dbcf5..00000000 --- a/build/lib/WORC/resources/fastr_tools/itktools/0.3.0/pxthresholdimage.xml +++ /dev/null @@ -1,104 +0,0 @@ - - A wrapper around ITK Tools, as set of simple command line tools for image analysis. - - - - - - - - - - - ITKTools v0.2.2 - This program thresholds an image. - Usage: - pxthresholdimage - -in inputFilename - [-out] outputFilename; default in + THRESHOLDED.mhd - [-mask] maskFilename, optional for "OtsuThreshold", required for "KappaSigmaThreshold" - [-m] method, choose one of - {Threshold, OtsuThreshold, OtsuMultipleThreshold, - AdaptiveOtsuThreshold, RobustAutomaticThreshold, - KappaSigmaThreshold, MinErrorThreshold } - default "Threshold" - [-t1] lower threshold, for "Threshold", default -infinity - [-t2] upper threshold, for "Threshold", default 1.0 - [-inside] inside value, default 0 - [-outside] outside value, default 1 - [-t] number of thresholds, for "OtsuMultipleThreshold", default 1 - [-b] number of histogram bins, for "OtsuThreshold", "MinErrorThreshold" - and "AdaptiveOtsuThreshold", default 128 - [-r] radius, for "AdaptiveOtsuThreshold", default 8 - [-cp] number of control points, for "AdaptiveOtsuThreshold", default 50 - [-l] number of levels, for "AdaptiveOtsuThreshold", default 3 - [-s] number of samples, for "AdaptiveOtsuThreshold", default 5000 - [-o] spline order, for "AdaptiveOtsuThreshold", default 3 - [-p] power, for "RobustAutomaticThreshold", default 1 - [-sigma] sigma factor, for "KappaSigmaThreshold", default 2 - [-iter] number of iterations, for "KappaSigmaThreshold", default 2 - [-mv] mask value, for "KappaSigmaThreshold", default 1 - [-mt] mixture type (1 - Gaussians, 2 - Poissons), for "MinErrorThreshold", default 1 - [-z] compression flag; if provided, the output image is compressed - - - - - - - - - - - - Threshold - OtsuThreshold - OtsuMultipleThreshold - AdaptiveOtsuThreshold - RobustAutomaticThreshold - KappaSigmaThreshold - MinErrorThreshold - - - - - - - - - - - - - - - - - - - 1 - 2 - - - - - - - - - - - - - - - diff --git a/build/lib/WORC/resources/fastr_tools/itktools/0.3.0/pxunaryimageoperator.xml b/build/lib/WORC/resources/fastr_tools/itktools/0.3.0/pxunaryimageoperator.xml deleted file mode 100644 index 8e88f24e..00000000 --- a/build/lib/WORC/resources/fastr_tools/itktools/0.3.0/pxunaryimageoperator.xml +++ /dev/null @@ -1,69 +0,0 @@ - - A wrapper around ITK Tools, as set of simple command line tools for image analysis. - - - - - - - - - - - ITKTools v0.2.2 - Unary operations on one image. - Usage: - pxunaryimageoperator - -in inputFilename - -ops UnaryOperator of the following form: - {+,-,*,/,^,%} - notation: - {PLUS,{R,L}MINUS,TIMES,{R,L}DIVIDE,{R,L}POWER,{R,L}MOD, - NEG,SIGN,ABS,FLOOR,CEIL,ROUND, - LN,LOG10,NLOG,EXP,[ARC]SIN,[ARC]COS,[ARC]TAN, - ERRFUNC,NORMCDF,QFUNC,LINEAR} - notation examples: - RMINUS = A - arg - LMINUS = arg - A - SIN = sin(A) - RPOWER = A ^ arg - TIMES = A * arg - LINEAR = arg1 * A + arg2 - NORMCDF = NORMCDF(mean=arg1, std=arg2) - QFUNC = QFUNC(mean=arg1, std=arg2) - [-arg] argument, necessary for some ops - [-out] outputFilename, default in + <ops> + <arg> + .mhd - [-z] compression flag; if provided, the output image is compressed - [-opct] outputPixelComponentType, default: same as input image - Supported: 2D, 3D, (unsigned) char, (unsigned) short, (unsigned) int, float. - - - - - - - - - - - - - - - - - - - - - - - - - - - - diff --git a/build/lib/WORC/resources/fastr_tools/itktools/0.3.2/bin/copymetadata.py b/build/lib/WORC/resources/fastr_tools/itktools/0.3.2/bin/copymetadata.py deleted file mode 100644 index 31c66f6b..00000000 --- a/build/lib/WORC/resources/fastr_tools/itktools/0.3.2/bin/copymetadata.py +++ /dev/null @@ -1,55 +0,0 @@ -#!/usr/bin/env python - -# Copyright 2017-2018 Biomedical Imaging Group Rotterdam, Departments of -# Medical Informatics and Radiology, Erasmus MC, Rotterdam, The Netherlands -# -# 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 argparse -import SimpleITK as sitk - - -def main(): - parser = argparse.ArgumentParser(description='Feature extraction') - parser.add_argument('-source', '--source', metavar='source', nargs='+', - dest='source', type=str, required=True, - help='Source image') - parser.add_argument('-dest', '--dest', metavar='dest', nargs='+', - dest='dest', type=str, required=True, - help='Destination image to copy metadata to') - parser.add_argument('-out', '--out', metavar='out', - dest='out', type=str, required=True, - help='Output file (ITK Image)') - args = parser.parse_args() - - # Convet input lists to strings - if type(args.dest) is list: - args.dest = ''.join(args.dest) - - if type(args.source) is list: - args.source = ''.join(args.source) - - if type(args.out) is list: - args.out = ''.join(args.out) - - # Read images and copy metadata - dest = sitk.ReadImage(args.dest) - source = sitk.ReadImage(args.source) - dest.CopyInformation(source) - - # Write the output image - sitk.WriteImage(dest, args.out) - - -if __name__ == '__main__': - main() diff --git a/build/lib/WORC/resources/fastr_tools/itktools/0.3.2/copymetadata.xml b/build/lib/WORC/resources/fastr_tools/itktools/0.3.2/copymetadata.xml deleted file mode 100644 index 04481d34..00000000 --- a/build/lib/WORC/resources/fastr_tools/itktools/0.3.2/copymetadata.xml +++ /dev/null @@ -1,35 +0,0 @@ - - Copy the metadata from one file to another. - - - - - - - - - copymetadata.py source destination output - output = ITK image with correct metadata - - - - - - - - - - - - - - - - - - usage: copymetadata.py [-h] -source IMAGE.ITKIM -dest SEGMENTATION.ITKIM-out OUTPUT.ITKIM - - - - - diff --git a/build/lib/WORC/resources/fastr_tools/itktools/0.3.2/pxcastconvert.xml b/build/lib/WORC/resources/fastr_tools/itktools/0.3.2/pxcastconvert.xml deleted file mode 100644 index 51f95533..00000000 --- a/build/lib/WORC/resources/fastr_tools/itktools/0.3.2/pxcastconvert.xml +++ /dev/null @@ -1,97 +0,0 @@ - - A wrapper around ITK Tools, as set of simple command line tools for image analysis. - - - - - - - - - - - ITKTools v0.3.2 - Description: - This program converts between many image formats. - This is done by reading in an image, possibly casting of the image, - and subsequently writing the image to the user-specified format. - - Definitions: - - converting: changing the extension of the image, e.g. bmp, mhd, etc. - - casting: changing the component type of a voxel, e.g. short, float, - unsigned long, etc. - - Notes: - - Casting of scalar images is done by the itk::ShiftScaleImageFilter, - where values are mapped to itself, leaving the intensity range - the same. NB: When casting to a component type with smaller dynamic - range, information might get lost. - - Casting of multi-component images, such as vector or RGB images, is - done using the itk::VectorCastImageFilter. - - Input images can be in all file formats ITK supports and for which - the itk::ImageFileReader works, and additionally 3D dicom series. - It is also possible to extract a specific DICOM series from a directory - by supplying the seriesUID. - - Output images can be in all file formats ITK supports and for which - the itk::ImageFileWriter works. Dicom output is not supported yet. - - - Usage: - pxcastconvert - -in inputfilename - -out outputfilename - [-opct] outputPixelComponentType, default equal to input - [-z] compression flag; if provided, the output image is compressed - OR pxcastconvert - -in dicomDirectory - -out outputfilename - [-opct] outputPixelComponentType, default equal to input - [-s] seriesUID, default the first UID found - [-r] add restrictions to generate a unique seriesUID - e.g. "0020|0012" to add a check for acquisition number. - [-z] compression flag; if provided, the output image is compressed - - OutputPixelComponentType should be one of {[unsigned_]char, [unsigned_]short, - [unsigned_]int, [unsigned_]long, float, double}. - NB: Not every image format supports all OutputPixelComponentTypes. - NB2: Not every image format supports the compression flag "-z". - - - - - - - - - - - - - unsigned_char - char - unsigned_short - short - unsigned_int - int - unsigned_long - long - float - double - - - - - - - - - - - - - - - diff --git a/build/lib/WORC/resources/fastr_tools/itktools/0.3.2/pxcastconvertdicom.xml b/build/lib/WORC/resources/fastr_tools/itktools/0.3.2/pxcastconvertdicom.xml deleted file mode 100644 index c13e63d8..00000000 --- a/build/lib/WORC/resources/fastr_tools/itktools/0.3.2/pxcastconvertdicom.xml +++ /dev/null @@ -1,99 +0,0 @@ - - A wrapper around ITK Tools, as set of simple command line tools for image analysis. - - - - - - - - - - - ITKTools v0.3.2 - Description: - This program converts between many image formats. - This is done by reading in an image, possibly casting of the image, - and subsequently writing the image to the user-specified format. - - Definitions: - - converting: changing the extension of the image, e.g. bmp, mhd, etc. - - casting: changing the component type of a voxel, e.g. short, float, - unsigned long, etc. - - Notes: - - Casting of scalar images is done by the itk::ShiftScaleImageFilter, - where values are mapped to itself, leaving the intensity range - the same. NB: When casting to a component type with smaller dynamic - range, information might get lost. - - Casting of multi-component images, such as vector or RGB images, is - done using the itk::VectorCastImageFilter. - - Input images can be in all file formats ITK supports and for which - the itk::ImageFileReader works, and additionally 3D dicom series. - It is also possible to extract a specific DICOM series from a directory - by supplying the seriesUID. - - Output images can be in all file formats ITK supports and for which - the itk::ImageFileWriter works. Dicom output is not supported yet. - - - Usage: - pxcastconvert - -in inputfilename - -out outputfilename - [-opct] outputPixelComponentType, default equal to input - [-z] compression flag; if provided, the output image is compressed - OR pxcastconvert - -in dicomDirectory - -out outputfilename - [-opct] outputPixelComponentType, default equal to input - [-s] seriesUID, default the first UID found - [-r] add restrictions to generate a unique seriesUID - e.g. "0020|0012" to add a check for acquisition number. - [-z] compression flag; if provided, the output image is compressed - - OutputPixelComponentType should be one of {[unsigned_]char, [unsigned_]short, - [unsigned_]int, [unsigned_]long, float, double}. - NB: Not every image format supports all OutputPixelComponentTypes. - NB2: Not every image format supports the compression flag "-z". - - - - - - - - - - - - - unsigned_char - char - unsigned_short - short - unsigned_int - int - unsigned_long - long - float - double - - - - - - - - - - - - - - - - - diff --git a/build/lib/WORC/resources/fastr_tools/itktools/0.3.2/pxgaussianimagefilter.xml b/build/lib/WORC/resources/fastr_tools/itktools/0.3.2/pxgaussianimagefilter.xml deleted file mode 100644 index 6f7780c6..00000000 --- a/build/lib/WORC/resources/fastr_tools/itktools/0.3.2/pxgaussianimagefilter.xml +++ /dev/null @@ -1,71 +0,0 @@ - - A wrapper around ITK Tools, as set of simple command line tools for image analysis. - - - - - - - - - - - -in inputFilename - [-out] outputFilename, default in + BLURRED.mhd - [-std] sigma, for each dimension, default 1.0 - [-ord] order, for each dimension, default zero - 0: zero order = blurring - 1: first order = gradient - 2: second order derivative - [-mag] compute the magnitude of the separate blurrings, default false - [-lap] compute the laplacian, default false - [-inv] compute invariants, choose one of - {LiLi, LiLijLj, LiLijLjkLk, Lii, LijLji, LijLjkLki} - [-opct] output pixel type, default equal to input - Supported: 2D, 3D, (unsigned) char, (unsigned) short, (unsigned) int, (unsigned) long, float, double. - - - - - - - - - - - - - - - LiLi - LiLijLj - LiLijLjkLk - Lii - LijLji - LijLjkLki - - - unsigned_char - char - unsigned_short - short - unsigned_int - int - unsigned_long - long - float - double - - - - - - - - - - - - - - diff --git a/build/lib/WORC/resources/fastr_tools/predict/CalcFeatures.xml b/build/lib/WORC/resources/fastr_tools/predict/CalcFeatures.xml deleted file mode 100644 index afd0e160..00000000 --- a/build/lib/WORC/resources/fastr_tools/predict/CalcFeatures.xml +++ /dev/null @@ -1,49 +0,0 @@ - - A wrapper around the feature calculation function of PREDICT. - - - - - - - - - CalcFeatures.py image metadata segmentation parameters - output = Radiomics features - - - - - - - - - - - - - - - - - - - - - - usage: CalcFeatures.py [-h] -im IMAGE.ITKIM [-md METADATA.dcm] [-sem SEMANTICS.csv] -seg SEGMENTATION.ITKIM -para PARAMETERS.ini -out OUTPUT.hdf5 - - Compute Radiomics features. - - optional arguments: - -h, --help show this help message and exit - -im IMAGE.ITKIM ITK image file containing an image - -seg SEGMENTATION.ITKIM ITK image file containing a matching segmentations - -sem SEMANTICS.csv CSV file containing the semantic features for this sample. - -para PARAMETERS.ini parameters used in feature extraction - -out OUTPUT.hdf5f Path to save computed features to - - - - - diff --git a/build/lib/WORC/resources/fastr_tools/predict/bin/CalcFeatures_tool.py b/build/lib/WORC/resources/fastr_tools/predict/bin/CalcFeatures_tool.py deleted file mode 100644 index bc12a488..00000000 --- a/build/lib/WORC/resources/fastr_tools/predict/bin/CalcFeatures_tool.py +++ /dev/null @@ -1,68 +0,0 @@ -#!/usr/bin/env python - -# Copyright 2017-2018 Biomedical Imaging Group Rotterdam, Departments of -# Medical Informatics and Radiology, Erasmus MC, Rotterdam, The Netherlands -# -# 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 argparse -from PREDICT.CalcFeatures import CalcFeatures -import pandas as pd - - -def main(): - parser = argparse.ArgumentParser(description='Feature extraction') - parser.add_argument('-im', '--im', metavar='image', nargs='+', - dest='im', type=str, required=True, - help='Images to calculate features on') - parser.add_argument('-md', '--md', metavar='metadata', dest='md', - type=str, required=False, nargs='+', - help='Clinical data on patient (DICOM)') - parser.add_argument('-sem', '--sem', metavar='semantics', dest='sem', - type=str, required=False, nargs='+', - help='Semantic Features') - parser.add_argument('-seg', '--seg', metavar='segmentation', dest='seg', - type=str, required=True, nargs='+', - help='Segmentation to calculate features on') - parser.add_argument('-para', '--para', metavar='Parameters', nargs='+', - dest='para', type=str, required=True, - help='Parameters') - parser.add_argument('-out', '--out', metavar='Features', - dest='out', type=str, required=False, - help='Patient features output (HDF)') - args = parser.parse_args() - - if 'Dummy' in str(args.im): - # Image is a dummy, so we write a feature file without features - panda_labels = ['image_type', 'parameters', 'feature_values', - 'feature_labels'] - image_type = 'Dummy' - parameters = list() - feature_labels = list() - feature_values = list() - panda_data = pd.Series([image_type, parameters, feature_values, - feature_labels], - index=panda_labels, - name='Image features' - ) - - print('Saving image features') - panda_data.to_hdf(args.out, 'image_features') - else: - CalcFeatures(image=args.im, segmentation=args.seg, parameters=args.para, - output=args.out, metadata_file=args.md, - semantics_file=args.sem) - - -if __name__ == '__main__': - main() diff --git a/build/lib/WORC/resources/fastr_tools/pyradiomics/CF_pyradiomics.xml b/build/lib/WORC/resources/fastr_tools/pyradiomics/CF_pyradiomics.xml deleted file mode 100644 index 0810ec3e..00000000 --- a/build/lib/WORC/resources/fastr_tools/pyradiomics/CF_pyradiomics.xml +++ /dev/null @@ -1,48 +0,0 @@ - - A wrapper around the pyradiomics feature extractor. - - - - - - - - - CF_pyradiomics.py image metadata segmentation semantics parameters output - output = Radiomics features - - - - - - - - - - - - - - - - - - - - - usage: CF_pyradiomics.py [-h] -im IMAGE.ITKIM -seg SEGMENTATION.ITKIM [-sem SEMANTICS.csv] [-para PARAMETERS.ini] -out OUTPUT.hdf5 - - Compute Radiomics features. - - optional arguments: - -h, --help show this help message and exit - -im IMAGE.ITKIM ITK image file containing an image - -seg SEGMENTATION.ITKIM ITK image file containing a matching segmentations - -sem SEMANTICS.csv CSV file containing the semantic features for this sample. - -para PARAMETERS.ini parameters used in feature extraction - -out OUTPUT.hdf5f Path to save computed features to - - - - - diff --git a/build/lib/WORC/resources/fastr_tools/pyradiomics/bin/CF_pyradiomics.py b/build/lib/WORC/resources/fastr_tools/pyradiomics/bin/CF_pyradiomics.py deleted file mode 100644 index 4d0ff591..00000000 --- a/build/lib/WORC/resources/fastr_tools/pyradiomics/bin/CF_pyradiomics.py +++ /dev/null @@ -1,67 +0,0 @@ -#!/usr/bin/env python - -# Copyright 2017-2018 Biomedical Imaging Group Rotterdam, Departments of -# Medical Informatics and Radiology, Erasmus MC, Rotterdam, The Netherlands -# -# 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 logging -import SimpleITK as sitk -import radiomics -from radiomics import featureextractor - - -def AllFeatures(image, mask): - # Define settings for signature calculation - # These are currently set equal to the respective default values - kwargs = {} - kwargs['binWidth'] = 25 - kwargs['resampledPixelSpacing'] = None # [3,3,3] is an example for defining resampling (voxels with size 3x3x3mm) - kwargs['interpolator'] = sitk.sitkBSpline - kwargs['verbose'] = True - - # Initialize wrapperClass to generate signature - extractor = featureextractor.RadiomicsFeaturesExtractor(**kwargs) - - # Disable all classes except firstorder - extractor.enableAllFeatures() - - # Enable writing out the log using radiomics logger - radiomics.debug() # Switch on radiomics logging from level=DEBUG (default level=WARNING) - - # Prevent radiomics logger from printing out log entries with level < WARNING to the console - logger = logging.getLogger('radiomics') - logger.handlers[0].setLevel(logging.WARNING) - logger.propagate = False # Do not pass log messages on to root logger - - # Write out all log entries to a file - handler = logging.FileHandler(filename='testLog.txt', mode='w') - formatter = logging.Formatter("%(levelname)s:%(name)s: %(message)s") - handler.setFormatter(formatter) - logger.addHandler(handler) - - print("Active features:") - for cls, features in extractor.enabledFeatures.iteritems(): - if len(features) == 0: - features = extractor.getFeatureNames(cls) - for f in features: - print(f) - print(eval('extractor.featureClasses["%s"].get%sFeatureValue.__doc__' % (cls, f))) - - print("Calculating features") - featureVector = extractor.execute(image, mask) - - for featureName in featureVector.keys(): - print("Computed %s: %s" % (featureName, featureVector[featureName])) - - return featureVector diff --git a/build/lib/WORC/resources/fastr_tools/pyradiomics/bin/CF_pyradiomics_tool.py b/build/lib/WORC/resources/fastr_tools/pyradiomics/bin/CF_pyradiomics_tool.py deleted file mode 100644 index 73a7674d..00000000 --- a/build/lib/WORC/resources/fastr_tools/pyradiomics/bin/CF_pyradiomics_tool.py +++ /dev/null @@ -1,160 +0,0 @@ -#!/usr/bin/env python - -# Copyright 2017-2018 Biomedical Imaging Group Rotterdam, Departments of -# Medical Informatics and Radiology, Erasmus MC, Rotterdam, The Netherlands -# -# 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 argparse -from CF_pyradiomics import AllFeatures as CalcFeatures - - -def main(): - parser = argparse.ArgumentParser(description='Feature extraction') - parser.add_argument('-im', '--im', metavar='image', nargs='+', - dest='im', type=str, required=True, - help='Images to calculate features on') - parser.add_argument('-md', '--md', metavar='metadata', dest='md', - type=str, required=False, nargs='+', - help='Clinical data on patient (DICOM)') - parser.add_argument('-sem', '--sem', metavar='semantics', dest='sem', - type=str, required=False, nargs='+', - help='Semantic Features') - parser.add_argument('-seg', '--seg', metavar='segmentation', dest='seg', - type=str, required=True, nargs='+', - help='Segmentation to calculate features on') - parser.add_argument('-para', '--para', metavar='Parameters', nargs='+', - dest='para', type=str, required=False, - help='Parameters') - parser.add_argument('-out', '--out', metavar='Features', - dest='out', type=str, required=False, - help='Patient features output (HDF)') - args = parser.parse_args() - - if type(args.im) is list: - args.im = ''.join(args.im) - - if type(args.seg) is list: - args.seg = ''.join(args.seg) - - if type(args.out) is list: - args.out = ''.join(args.out) - - featureVector = CalcFeatures(image=args.im, mask=args.seg) - - if 'rdf' in args.out: - # Write output to rdf - # import rdflib and some namespace - from rdflib import Graph, URIRef, BNode, Literal, Namespace - from rdflib.namespace import RDF, FOAF - - # convert python object to RDF - print "-----------------------------------------------------------" - print " RDF Output:" - print "" - Img = Graph() - lung1_image = URIRef("http://example.org/CT-Image") - Img.add((lung1_image, RDF.type, FOAF.Image)) - - list_key = featureVector.keys() - list_value = featureVector.values() - for i in range(len(list_key)): - tmp_value = Literal(list_value[i]) - tmp_name = list_key[i] - Img.add((lung1_image, FOAF.tmp_name, tmp_value)) - - print Img.serialize(format='turtle') - # Create a rdf file for storing output - Img.serialize(args.out, format="pretty-xml") - - elif 'hdf5' in args.out: - # Write output to hdf5 - import numpy as np - import pandas as pd - - # Assign features to corresponding groups - shape_labels = list() - shape_features = list() - histogram_labels = list() - histogram_features = list() - GLCM_labels = list() - GLCM_features = list() - GLRLM_labels = list() - GLRLM_features = list() - GLSZM_labels = list() - GLSZM_features = list() - - for featureName in featureVector.keys(): - if 'shape' in featureName: - shape_labels.append(featureName) - shape_features.append(featureVector[featureName]) - if 'firstorder' in featureName: - histogram_labels.append(featureName) - histogram_features.append(featureVector[featureName]) - if 'glcm' in featureName: - GLCM_labels.append(featureName) - GLCM_features.append(featureVector[featureName]) - if 'glrlm' in featureName: - GLRLM_labels.append(featureName) - GLRLM_features.append(featureVector[featureName]) - if 'glszm' in featureName: - GLSZM_labels.append(featureName) - GLSZM_features.append(featureVector[featureName]) - - # Convert feature to single dictionary containing PD series - features = dict() - pandas_dict = dict(zip(shape_labels, shape_features)) - shape_dict = dict() - shape_dict['all'] = pd.Series(pandas_dict) - shape_features = pd.Series(shape_dict) - features['shape_features'] = shape_features - - pandas_dict = dict(zip(histogram_labels, histogram_features)) - histogram_dict = dict() - histogram_dict['all'] = pd.Series(pandas_dict) - histogram_features = pd.Series(histogram_dict) - features['histogram_features'] = histogram_features - - GLCM_dict = dict(zip(GLCM_labels, GLCM_features)) - GLRLM_dict = dict(zip(GLRLM_labels, GLRLM_features)) - GLSZM_dict = dict(zip(GLSZM_labels, GLSZM_features)) - - texture_features = dict() - texture_features['GLCM'] = pd.Series(GLCM_dict) - texture_features['GLRLM'] = pd.Series(GLRLM_dict) - texture_features['GLSZM'] = pd.Series(GLSZM_dict) - - texture_features = pd.Series(texture_features) - features['texture_features'] = texture_features - - # We also return just the arrray - image_feature_array = list() - - for _, feattype in features.iteritems(): - for _, imfeatures in feattype.iteritems(): - image_feature_array.extend(imfeatures.values) - - image_feature_array = np.asarray(image_feature_array) - image_feature_array = image_feature_array.ravel() - - panda_labels = ['image_features', 'image_features_array'] - panda_data = pd.Series([features, image_feature_array], - index=panda_labels, - name='Image features' - ) - - panda_data.to_hdf(args.out, 'image_features') - - -if __name__ == '__main__': - main() diff --git a/build/lib/WORC/resources/fastr_tools/segmentix/Segmentix.xml b/build/lib/WORC/resources/fastr_tools/segmentix/Segmentix.xml deleted file mode 100644 index c27a99b6..00000000 --- a/build/lib/WORC/resources/fastr_tools/segmentix/Segmentix.xml +++ /dev/null @@ -1,38 +0,0 @@ - - Segmentation toolbox. - - - - - - - - - Segmentix.py image metadata segmentation parameters - output = Radiomics features - - - - - - - - - - - - - - - - - - - - - usage: Segmentix.py [-h] [-im IMAGE.ITKIM] [-pi Pinfo.txt] [-seg SEGMENTATION.ITKIM] -para PARAMETERS.ini -out OUTPUT.ITKIM - - - - - diff --git a/build/lib/WORC/resources/fastr_tools/segmentix/bin/segmentix.py b/build/lib/WORC/resources/fastr_tools/segmentix/bin/segmentix.py deleted file mode 100644 index a3acc53f..00000000 --- a/build/lib/WORC/resources/fastr_tools/segmentix/bin/segmentix.py +++ /dev/null @@ -1,127 +0,0 @@ -#!/usr/bin/env python - -# Copyright 2017-2018 Biomedical Imaging Group Rotterdam, Departments of -# Medical Informatics and Radiology, Erasmus MC, Rotterdam, The Netherlands -# -# 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. - -from WORC.processing.ExtractNLargestBlobsn import ExtractNLargestBlobsn -import SimpleITK as sitk -from skimage import morphology -import scipy.ndimage as nd -import numpy as np -import WORC.IOparser.config_segmentix as config_io - - -def segmentix(parameters=None, image=None, segmentation=None, - output=None, metadata_file=None, mask=None): - ''' - Segmentix is a mixture of processing methods that can be applied to - agument a segmentation. Examples include selecting only the largest blob - and the application of morphological operations. - - Parameters - ---------- - parameters: string, mandatory - Contains the path referring to a .ini file in which the - parameters to be used are specified. See the Github Wiki - for more details on the format and content. - - image: string, optional - Note implemented yet! Image to be used for automatic segmentation. - - segmentation: string, currently mandatory - path referring to the input segmentation file. Should be a - format compatible with ITK, e.g. .nii, .nii.gz, .mhd, - .raw, .tiff, .nrrd. - - output: string, mandatory - path referring to the output segmentation file. Should be a - format compatible with ITK, e.g. .nii, .nii.gz, .mhd, - .raw, .tiff, .nrrd. - - metadata_file: string, optional - Note implemented yet! Path referring to the .dcm from which - fields can be used as metadata for segmentation. - - mask: string, optional - path referring to the mask used for the final segmentation. - Should be a format compatible with ITK, e.g. .nii, .nii.gz, .mhd, - .raw, .tiff, .nrrd. - - ''' - if parameters is None: - raise IOError("You must provide a parameter file!") - # Load variables from the confilg file - config = config_io.load_config(parameters) - - if segmentation is not None: - # Load segmentation and perform routines - - if type(segmentation) is list: - segmentation = ''.join(segmentation) - - # Convert to binary image and clean up small errors/areas - contour = sitk.ReadImage(segmentation) - contour = sitk.GetArrayFromImage(contour) - - # BUG: remove first and last slice, fault in liver segmentations - contour[:,:,-1] = np.zeros([contour.shape[0], contour.shape[1]]) - contour[:,:, 0] = np.zeros([contour.shape[0], contour.shape[1]]) - - if config['Segmentix']['fillholes']: - contour = nd.binary_fill_holes(contour) - - # contour = morphology.remove_small_objects(contour, min_size=2, connectivity=2, in_place=False) - if config['Segmentix']['N_blobs'] != 0: - contour = contour.astype(bool) - contour = ExtractNLargestBlobsn(contour, 1) - - # Expand contour depending on settings - # TODO: this is a workaround for 3-D morphology - if config['Segmentix']['type'] == 'Ring': - contour = contour.astype(bool) - radius = int(config['Segmentix']['radius']) - disk = morphology.disk(radius) - - # Dilation with radius - for ind in range(contour.shape[2]): - contour_d = morphology.binary_dilation(contour[:, :, ind], disk) - contour_e = morphology.binary_erosion(contour[:, :, ind], disk) - contour[:, :, ind] = np.bitwise_xor(contour_d, contour_e) - - # Mask the segmentation if necessary - if mask is not None: - if type(mask) is list: - mask = ''.join(mask) - - mask = sitk.ReadImage(mask) - mask = sitk.GetArrayFromImage(mask) - mask = nd.binary_fill_holes(mask) - mask = mask.astype(bool) - method = config['Segmentix']['mask'] - if method == 'subtract': - contour = np.bitwise_xor(contour, mask) - elif method == "multiply": - contour = np.multiply(contour, mask) - - # Output contour - contour = contour.astype(np.uint8) - contour = sitk.GetImageFromArray(contour) - if output is not None: - sitk.WriteImage(contour, output) - else: - # TODO: perform segmentation routine or transform segmentation - pass - - return contour diff --git a/build/lib/WORC/resources/fastr_tools/segmentix/bin/segmentix_tool.py b/build/lib/WORC/resources/fastr_tools/segmentix/bin/segmentix_tool.py deleted file mode 100644 index 0642fbf3..00000000 --- a/build/lib/WORC/resources/fastr_tools/segmentix/bin/segmentix_tool.py +++ /dev/null @@ -1,56 +0,0 @@ -#!/usr/bin/env python - -# Copyright 2017-2018 Biomedical Imaging Group Rotterdam, Departments of -# Medical Informatics and Radiology, Erasmus MC, Rotterdam, The Netherlands -# -# 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 argparse -from segmentix import segmentix -from shutil import copyfile - - -def main(): - parser = argparse.ArgumentParser(description='Feature extraction') - parser.add_argument('-im', '--im', metavar='image', nargs='+', - dest='im', type=str, required=False, - help='Images to calculate features on') - parser.add_argument('-md', '--md', metavar='metadata', dest='md', - type=str, required=False, nargs='+', - help='Clinical data on patient (DICOM)') - parser.add_argument('-segin', '--segin', metavar='segmentation', dest='seg', - type=str, required=False, nargs='+', - help='Segmentation input (ITK Image)') - parser.add_argument('-mask', '--mask', metavar='mask', dest='mask', - type=str, required=False, nargs='+', - help='Mask (ITK Image)') - parser.add_argument('-para', '--para', metavar='Parameters', nargs='+', - dest='para', type=str, required=True, - help='Parameters') - parser.add_argument('-segout', '--segout', metavar='Features', - dest='out', type=str, required=False, - help='Segmentation output (ITK Image)') - args = parser.parse_args() - - if 'Dummy' in str(args.im): - # Image is a dummy, so we do not do anything with the segmentation but - # simply copy the input to the output - if args.out is not None: - copyfile(str(args.seg), str(args.out)) - else: - segmentix(image=args.im, segmentation=args.seg, parameters=args.para, - output=args.out, metadata_file=args.md, mask=args.mask) - - -if __name__ == '__main__': - main() diff --git a/build/lib/WORC/resources/fastr_tools/worc/PlotBarchart.xml b/build/lib/WORC/resources/fastr_tools/worc/PlotBarchart.xml deleted file mode 100644 index 43849e6a..00000000 --- a/build/lib/WORC/resources/fastr_tools/worc/PlotBarchart.xml +++ /dev/null @@ -1,37 +0,0 @@ - - A wrapper around PREDICT's Barchart Plotting Function. - - - - - - - - - PlotBarchart.py prediction estimators label_type output_png output_tex output_csv - output = output_png output_tex - - - - - - - - - - - - - - - - - - - - usage: to write - - - - - diff --git a/build/lib/WORC/resources/fastr_tools/worc/PlotROC.xml b/build/lib/WORC/resources/fastr_tools/worc/PlotROC.xml deleted file mode 100644 index d40f7330..00000000 --- a/build/lib/WORC/resources/fastr_tools/worc/PlotROC.xml +++ /dev/null @@ -1,39 +0,0 @@ - - A wrapper around PREDICT's ROC Plotting Function. - - - - - - - - - PlotROC.py prediction pinfo ensemble label_type output_png output_tex output_csv - output = output_png output_tex output_csv - - - - - - - - - - - - - - - - - - - - - - usage: to write - - - - - diff --git a/build/lib/WORC/resources/fastr_tools/worc/PlotRankedScores.xml b/build/lib/WORC/resources/fastr_tools/worc/PlotRankedScores.xml deleted file mode 100644 index adce5719..00000000 --- a/build/lib/WORC/resources/fastr_tools/worc/PlotRankedScores.xml +++ /dev/null @@ -1,41 +0,0 @@ - - A wrapper around PREDICT's Ranked Scores Plotting Function. - - - - - - - - - PlotRankedScores.py estimator pinfo ensemble label_type scores images segmentations - output = output_zip output_tex - - - - - - - - - - - - - - - - - - - - - - - - usage: to write - - - - - diff --git a/build/lib/WORC/resources/fastr_tools/worc/PlotSVM.xml b/build/lib/WORC/resources/fastr_tools/worc/PlotSVM.xml deleted file mode 100644 index d94f3281..00000000 --- a/build/lib/WORC/resources/fastr_tools/worc/PlotSVM.xml +++ /dev/null @@ -1,37 +0,0 @@ - - A wrapper around PREDICT's SVM Plotting Function. - - - - - - - - - PlotSVM.py prediction pinfo ensemble label_type output_json - output = output_json output_tex output_csv - - - - - - - - - - - - - - - - - - - - usage: to write - - - - - diff --git a/build/lib/WORC/resources/fastr_tools/worc/PreProcess.xml b/build/lib/WORC/resources/fastr_tools/worc/PreProcess.xml deleted file mode 100644 index e7218477..00000000 --- a/build/lib/WORC/resources/fastr_tools/worc/PreProcess.xml +++ /dev/null @@ -1,37 +0,0 @@ - - Node for preprocessing of images.. - - - - - - - - - preprocessing.py image_in metadata mask parameters image_out - output = Processed Image - - - - - - - - - - - - - - - - - - - - usage: preprocessing.py [-h] -im IMAGE.ITKIM [-md METADATA.dcm] [-mask MASK.ITKIM] -para PARAMETERS.ini -out IMAGE_OUT.ITKIM - - - - - diff --git a/build/lib/WORC/resources/fastr_tools/worc/RTStructReader.xml b/build/lib/WORC/resources/fastr_tools/worc/RTStructReader.xml deleted file mode 100644 index ef9c06ce..00000000 --- a/build/lib/WORC/resources/fastr_tools/worc/RTStructReader.xml +++ /dev/null @@ -1,43 +0,0 @@ - - Tool to read an RTstruct, convert to a binary mask and save as ITK Image file.. - - - - - - - - - RTStructReader.py RTStruct ROI_name Output - output = ITK image of binary mask - - - - - - - - - - - - - - - - - - usage: RTStructReader.py [-h] -rt RTStruct.dcm -roinames ROINAMEString -output ITKImageFile - - Convert ROI with a specific name from the RTStruct to a binary mask and save as ITKImage. - - optional arguments: - -h, --help show this help message and exit. - -rt RTStruct.dcm RTStruct file to extract contours from. - -roiname String with name of contours/rois to extract from RTStruct. - -output List of ITKImagefiles with names and extensions to write output to. Should match the cardinality of - - - - - diff --git a/build/lib/WORC/resources/fastr_tools/worc/Slicer.xml b/build/lib/WORC/resources/fastr_tools/worc/Slicer.xml deleted file mode 100644 index 65f8eaaf..00000000 --- a/build/lib/WORC/resources/fastr_tools/worc/Slicer.xml +++ /dev/null @@ -1,36 +0,0 @@ - - Slice the images at the center of a ROI segmentation and print the output to png. - - - - - - - - - slicer.py image segmentation output - output = Radiomics features - - - - - - - - - - - - - - - - - - - usage: Slicer.py [-h] -im IMAGE.ITKIM -seg SEGMENTATION.ITKIM -out OUTPUT.png -outzoom OUTPUTzoom.png - - - - - diff --git a/build/lib/WORC/resources/fastr_tools/worc/TrainClassifier.xml b/build/lib/WORC/resources/fastr_tools/worc/TrainClassifier.xml deleted file mode 100644 index 60badcbe..00000000 --- a/build/lib/WORC/resources/fastr_tools/worc/TrainClassifier.xml +++ /dev/null @@ -1,49 +0,0 @@ - - A wrapper around PREDICT's Radiomics patient classification. - - - - - - - - - SVMGS.py images patientinfo seg parameters - output = Radiomics classification - - - - - - - - - - - - - - - - - - - - - - - - usage: TrainClassifier.py [-h] -feat_m1/m2/m3 FEATURES.hdf5 -pc PATIENTCLASS.txt-conf CONFIGURATION.ini -parameters PARAMETERS.ini -class CLASSIFICATION.hdf5 -perf PERFORMANCE.json - Perform a grid search over several features types to train multiple Support Vector Machine (SVM) classifiers. - - -feat_m1, ..m2, ..m3 FEATURES.HDF5 File containing the features for an object. Support up to three feature files for a single object. - -pc PATIENTCLASS.txt File containing the labels for an object. - -conf CONFIGURATION.ini File specifiying the configurations for the SVM optimization. - -parameters PARAMETERS.ini File specifying the grid search parameters containing the feature groups to use. - -class CLASSIFICATION.hdf5 File to write the SVM output to. - -perf PERFORMANCE.json File containing the performance statistics of the fitted SVM. - - - - - diff --git a/build/lib/WORC/resources/fastr_tools/worc/bin/PlotBarchart.py b/build/lib/WORC/resources/fastr_tools/worc/bin/PlotBarchart.py deleted file mode 100644 index 8fb4f86e..00000000 --- a/build/lib/WORC/resources/fastr_tools/worc/bin/PlotBarchart.py +++ /dev/null @@ -1,67 +0,0 @@ -#!/usr/bin/env python - -# Copyright 2017-2018 Biomedical Imaging Group Rotterdam, Departments of -# Medical Informatics and Radiology, Erasmus MC, Rotterdam, The Netherlands -# -# 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. - -from WORC.plotting.plot_barchart import plot_barchart -import argparse - - -def main(): - parser = argparse.ArgumentParser(description='Plot the barchart of the hyperparameters of a number of hyperparameter settings') - parser.add_argument('-prediction', '--prediction', metavar='prediction', - nargs='+', dest='prediction', type=str, required=True, - help='Prediction file (HDF)') - parser.add_argument('-estimators', '--estimators', metavar='estimators', - nargs='+', dest='estimators', type=str, required=True, - help='Number of estimators (int)') - parser.add_argument('-label_type', '--label_type', metavar='label_type', - nargs='+', dest='label_type', type=str, required=True, - help='Label name that is predicted (string)') - parser.add_argument('-output_png', '--output_png', metavar='output_png', - nargs='+', dest='output_png', type=str, required=False, - help='File to write output to (PNG)') - parser.add_argument('-output_tex', '--output_tex', metavar='output_tex', - nargs='+', dest='output_tex', type=str, required=False, - help='File to write output to (tex)') - args = parser.parse_args() - - # Convert inputs from lists to elements for single inputs - if type(args.prediction) is list: - args.prediction = ''.join(args.prediction) - - if type(args.label_type) is list: - args.label_type = ''.join(args.label_type) - - if type(args.output_png) is list: - args.output_png = ''.join(args.output_png) - - if type(args.output_tex) is list: - args.output_tex = ''.join(args.output_tex) - - # Number of estimators should be an integer - if type(args.estimators) is list: - args.estimators = int(args.estimators[0]) - - # Plot the barchart - plot_barchart(prediction=args.prediction, - estimators=args.estimators, - label_type=args.label_type, - output_tex=args.output_tex, - output_png=args.output_png) - - -if __name__ == '__main__': - main() diff --git a/build/lib/WORC/resources/fastr_tools/worc/bin/PlotROC.py b/build/lib/WORC/resources/fastr_tools/worc/bin/PlotROC.py deleted file mode 100644 index 5c00e567..00000000 --- a/build/lib/WORC/resources/fastr_tools/worc/bin/PlotROC.py +++ /dev/null @@ -1,57 +0,0 @@ -#!/usr/bin/env python - -# Copyright 2017-2018 Biomedical Imaging Group Rotterdam, Departments of -# Medical Informatics and Radiology, Erasmus MC, Rotterdam, The Netherlands -# -# 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. - -from WORC.plotting.plot_ROC import plot_ROC -import argparse - - -def main(): - parser = argparse.ArgumentParser(description='Plot the ROC Curve of an estimator') - parser.add_argument('-prediction', '--prediction', metavar='prediction', - nargs='+', dest='prediction', type=str, required=True, - help='Prediction file (HDF)') - parser.add_argument('-pinfo', '--pinfo', metavar='pinfo', - nargs='+', dest='pinfo', type=str, required=True, - help='Patient Info File (txt)') - parser.add_argument('-ensemble', '--ensemble', metavar='ensemble', - nargs='+', dest='ensemble', type=str, required=True, - help='Length of ensemble (int)') - parser.add_argument('-label_type', '--label_type', metavar='label_type', - nargs='+', dest='label_type', type=str, required=True, - help='Label name that is predicted (string)') - parser.add_argument('-output_png', '--output_png', metavar='output_png', - nargs='+', dest='output_png', type=str, required=False, - help='File to write output to (PNG)') - parser.add_argument('-output_csv', '--output_csv', metavar='output_csv', - nargs='+', dest='output_csv', type=str, required=False, - help='File to write output to (csv)') - parser.add_argument('-output_tex', '--output_tex', metavar='output_tex', - nargs='+', dest='output_tex', type=str, required=False, - help='File to write output to (tex)') - args = parser.parse_args() - - plot_ROC(prediction=args.prediction, - pinfo=args.pinfo, - ensemble=args.ensemble, - label_type=args.label_type, - output_png=args.output_png, - output_tex=args.output_tex, - output_csv=args.output_csv) - - -if __name__ == '__main__': - main() diff --git a/build/lib/WORC/resources/fastr_tools/worc/bin/PlotRankedScores.py b/build/lib/WORC/resources/fastr_tools/worc/bin/PlotRankedScores.py deleted file mode 100644 index 9b308391..00000000 --- a/build/lib/WORC/resources/fastr_tools/worc/bin/PlotRankedScores.py +++ /dev/null @@ -1,95 +0,0 @@ -#!/usr/bin/env python - -# Copyright 2017-2018 Biomedical Imaging Group Rotterdam, Departments of -# Medical Informatics and Radiology, Erasmus MC, Rotterdam, The Netherlands -# -# 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. - -from WORC.plotting.plot_ranked_scores import plot_ranked_scores -import argparse - - -def main(): - parser = argparse.ArgumentParser(description='Plot the ranked scores of an estimator') - parser.add_argument('-estimator', '--estimator', metavar='estimator', - nargs='+', dest='estimator', type=str, required=True, - help='Estimator file (HDF)') - parser.add_argument('-pinfo', '--pinfo', metavar='pinfo', - nargs='+', dest='pinfo', type=str, required=True, - help='Patient Info File (txt)') - parser.add_argument('-ensemble', '--ensemble', metavar='ensemble', - nargs='+', dest='ensemble', type=str, required=False, - help='Length of ensemble (int)') - parser.add_argument('-scores', '--scores', metavar='scores', - nargs='+', dest='scores', type=str, required=False, - help='Type of scoring used: percentages or posteriors (string)') - parser.add_argument('-label_type', '--label_type', metavar='label_type', - nargs='+', dest='label_type', type=str, required=False, - help='Label name that is predicted (string)') - parser.add_argument('-images', '--images', metavar='images', - nargs='+', dest='images', type=str, required=False, - help='Paths to images (ITK Image files)') - parser.add_argument('-segmentations', '--segmentations', - metavar='segmentations', nargs='+', - dest='segmentations', type=str, required=False, - help='Paths to segmentations (ITK Image files)') - parser.add_argument('-output_csv', '--output_csv', metavar='output_csv', - nargs='+', dest='output_csv', type=str, required=False, - help='File to write output to (csv)') - parser.add_argument('-output_zip', '--output_zip', metavar='output_zip', - nargs='+', dest='output_zip', type=str, required=False, - help='File to write output to (zip)') - args = parser.parse_args() - - # convert inputs that should be single arguments to lists - pinfo = args.pinfo - if type(pinfo) is list: - pinfo = ''.join(pinfo) - - estimator = args.estimator - if type(estimator) is list: - estimator = ''.join(estimator) - - ensemble = args.ensemble - if type(ensemble) is list: - ensemble = int(ensemble[0]) - - label_type = args.label_type - if type(label_type) is list: - label_type = ''.join(label_type) - - scores = args.scores - if type(scores) is list: - scores = ''.join(scores) - - output_csv = args.output_csv - if type(output_csv) is list: - output_csv = ''.join(output_csv) - - output_zip = args.output_zip - if type(output_zip) is list: - output_zip = ''.join(output_zip) - - plot_ranked_scores(estimator=estimator, - pinfo=pinfo, - label_type=label_type, - scores=scores, - images=args.images, - segmentations=args.segmentations, - ensemble=ensemble, - output_csv=output_csv, - output_zip=output_zip) - - -if __name__ == '__main__': - main() diff --git a/build/lib/WORC/resources/fastr_tools/worc/bin/PlotSVM.py b/build/lib/WORC/resources/fastr_tools/worc/bin/PlotSVM.py deleted file mode 100644 index 203c336c..00000000 --- a/build/lib/WORC/resources/fastr_tools/worc/bin/PlotSVM.py +++ /dev/null @@ -1,70 +0,0 @@ -#!/usr/bin/env python - -# Copyright 2017-2018 Biomedical Imaging Group Rotterdam, Departments of -# Medical Informatics and Radiology, Erasmus MC, Rotterdam, The Netherlands -# -# 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. - -from WORC.plotting.plot_SVM import plot_SVM -import argparse -import json - - -def main(): - parser = argparse.ArgumentParser(description='Plot the SVM Curve of an estimator') - parser.add_argument('-prediction', '--prediction', metavar='prediction', - nargs='+', dest='prediction', type=str, required=True, - help='Prediction file (HDF)') - parser.add_argument('-pinfo', '--pinfo', metavar='pinfo', - nargs='+', dest='pinfo', type=str, required=True, - help='Patient Info File (txt)') - parser.add_argument('-ensemble', '--ensemble', metavar='ensemble', - nargs='+', dest='ensemble', type=str, required=True, - help='Length of ensemble (int)') - parser.add_argument('-label_type', '--label_type', metavar='label_type', - nargs='+', dest='label_type', type=str, required=True, - help='Label name that is predicted (string)') - parser.add_argument('-output_json', '--output_json', metavar='output_json', - nargs='+', dest='output_json', type=str, required=False, - help='File to write output to (json)') - args = parser.parse_args() - - # Convert inputs to strings - if type(args.prediction) is list: - args.prediction = ''.join(args.prediction) - - if type(args.pinfo) is list: - args.pinfo = ''.join(args.pinfo) - - if type(args.ensemble) is list: - args.ensemble = int(args.ensemble[0]) - # ensemble = ''.join(ensemble) - - if type(args.output_json) is list: - args.output_json = ''.join(args.output_json) - - if type(args.label_type) is list: - args.label_type = ''.join(args.label_type) - - # Plot the statistics - stats = plot_SVM(prediction=args.prediction, - label_data=args.pinfo, - ensemble=args.ensemble, - label_type=args.label_type) - - with open(args.output_json, 'w') as fp: - json.dump(stats, fp, indent=4) - - -if __name__ == '__main__': - main() diff --git a/build/lib/WORC/resources/fastr_tools/worc/bin/RTStructReader_Tool.py b/build/lib/WORC/resources/fastr_tools/worc/bin/RTStructReader_Tool.py deleted file mode 100644 index c389bcf5..00000000 --- a/build/lib/WORC/resources/fastr_tools/worc/bin/RTStructReader_Tool.py +++ /dev/null @@ -1,49 +0,0 @@ -#!/usr/bin/env python - -# Copyright 2011-2018 Biomedical Imaging Group Rotterdam, Departments of -# Medical Informatics and Radiology, Erasmus MC, Rotterdam, The Netherlands -# -# 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 argparse -from WORC.processing.RTStructReader import RTStructReader - - -def main(): - parser = argparse.ArgumentParser(description='RTStruct Reader') - parser.add_argument('-rt', '--rt', metavar='rt', nargs='+', - dest='rt', type=str, required=False, - help='RT Struct file to read (DICOM)') - parser.add_argument('-roiname', '--roiname', metavar='roiname', - dest='roiname', - type=str, required=False, nargs='+', - help='Name of ROI to extract (string)') - parser.add_argument('-out', '--out', metavar='out', - dest='out', type=str, required=False, - help='Image output (ITK Image)') - args = parser.parse_args() - - if type(args.rt) is list: - args.rt = ''.join(args.rt) - - if type(args.roiname) is list: - args.roiname = ''.join(args.roiname) - - if type(args.out) is list: - args.out = ''.join(args.out) - - RTStructReader(args.rt, args.roiname) - - -if __name__ == '__main__': - main() diff --git a/build/lib/WORC/resources/fastr_tools/worc/bin/TrainClassifier.py b/build/lib/WORC/resources/fastr_tools/worc/bin/TrainClassifier.py deleted file mode 100644 index 562718e5..00000000 --- a/build/lib/WORC/resources/fastr_tools/worc/bin/TrainClassifier.py +++ /dev/null @@ -1,64 +0,0 @@ -#!/usr/bin/env python - -# Copyright 2017-2018 Biomedical Imaging Group Rotterdam, Departments of -# Medical Informatics and Radiology, Erasmus MC, Rotterdam, The Netherlands -# -# 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 argparse -from WORC.classification.trainclassifier import trainclassifier - - -def main(): - parser = argparse.ArgumentParser(description='Radiomics classification') - parser.add_argument('-feat_train', '--feat_train', metavar='features_train', - nargs='+', dest='feat_train', type=str, required=True, - help='Patient features input of first modality (HDF)') - parser.add_argument('-feat_test', '--feat_test', metavar='features_test', - nargs='+', dest='feat_test', type=str, required=False, - default=None, - help='Patient features input of second modality (HDF)') - parser.add_argument('-pc_train', '--pc_train', metavar='Patientinfo', - dest='pc_train', - type=str, required=True, nargs='+', - help='Classification of patient') - parser.add_argument('-pc_test', '--pc_test', metavar='Patientinfo', - dest='pc_test', - type=str, required=False, nargs='+', - help='Classification of patient') - parser.add_argument('-cf', '--conf', metavar='config', nargs='+', - dest='cf', type=str, required=True, - help='Configuration') - parser.add_argument('-c', '--class', metavar='classification', - dest='hdf', type=str, required=True, nargs='+', - help='Classification (HDF)') - parser.add_argument('-perf', '--perf', metavar='performance', - dest='perf', type=str, required=True, nargs='+', - help='Performance (JSON)') - parser.add_argument('-fs', '--fs', metavar='fixedsplits', - dest='fs', type=str, required=False, nargs='+', - help='File containing fixed splits for iterations (XLSX)') - args = parser.parse_args() - - trainclassifier(feat_train=args.feat_train, - patientinfo_train=args.pc_train, - config=args.cf, - output_hdf=args.hdf, output_json=args.perf, - feat_test=args.feat_test, - patientinfo_test=args.pc_test, - verbose=False, - fixedsplits=args.fs) - - -if __name__ == '__main__': - main() diff --git a/build/lib/WORC/resources/fastr_tools/worc/bin/combineresults.py b/build/lib/WORC/resources/fastr_tools/worc/bin/combineresults.py deleted file mode 100644 index b625706d..00000000 --- a/build/lib/WORC/resources/fastr_tools/worc/bin/combineresults.py +++ /dev/null @@ -1,228 +0,0 @@ -#!/usr/bin/env python - -# Copyright 2017-2018 Biomedical Imaging Group Rotterdam, Departments of -# Medical Informatics and Radiology, Erasmus MC, Rotterdam, The Netherlands -# -# 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 pandas as pd -import json -import csv -import argparse -from natsort import natsorted -import glob -import os - - -def main(): - parser = argparse.ArgumentParser(description='Radiomics results') - parser.add_argument('-svm', '--svm', metavar='svm', - nargs='+', dest='svm', type=str, required=True, - help='SVM file (HDF)') - parser.add_argument('-perf', '--perf', metavar='Performance', nargs='+', - dest='perf', type=str, required=True, - help='Performance (Parameters + Statistics)') - parser.add_argument('-ts', '--ts', metavar='ts', nargs='+', - dest='ts', type=str, required=False, - help='Total Sensitivity from PCE Analysis (.csv)') - parser.add_argument('-res', '--res', metavar='Results', nargs='+', - dest='res', type=str, required=True, - help='Results') - args = parser.parse_args() - - if type(args.svm) is list: - args.svm = ''.join(args.svm) - - if type(args.ts) is list: - args.ts = ''.join(args.ts) - - if type(args.perf) is list: - args.perf = ''.join(args.perf) - - # If input is dir, use glob - print args.svm - if os.path.isdir(args.svm): - args.svm = glob.glob(args.svm + '/svm_*.hdf5') - args.svm = natsorted(args.svm) - - if os.path.isdir(args.perf): - args.perf = glob.glob(args.perf + '/performance_*.json') - args.perf = natsorted(args.perf) - - if args.ts is not None: - if os.path.isdir(args.ts): - args.ts = glob.glob(args.ts + '/TS_*.csv') - args.ts = natsorted(args.ts) - else: - args.ts = [None] * len(args.svm) - - # Remove provenance - temp = list() - for pf in args.perf: - if 'prov' not in pf: - temp.append(pf) - - args.perf = temp - - # Read the inputs: labels of SVM, parameters, sensitivity - feature_labels = list() - # TODO: Fix "Too Few Features" SVMs - all_feature_labels = list() - pftemp = list() - tstemp = list() - for svmfile, tsfile, pffile in zip(args.svm, args.ts, args.perf): - svm = pd.read_hdf(svmfile) - if 'Too Few Features.' in svm.keys() or ' Too Few Features.' in svm.keys(): - print(("Too few features in {}.").format(svmfile)) - else: - print svm - labels = svm[svm.keys()[0]].ix['feature_labels'] # .tolist() - feature_labels.append(labels) - all_feature_labels = all_feature_labels + list(set(labels) - set(all_feature_labels)) - pftemp.append(pffile) - tstemp.append(tsfile) - - args.perf = pftemp - args.ts = tstemp - parameters = list() - statistics = list() - alwaysright = list() - alwayswrong = list() - ar_labels = list() - aw_labels = list() - for parafile in args.perf: - with open(parafile) as fp: - parameters_temp = json.load(fp) - - parameters.append(parameters_temp['Parameters']) - statistics.append(parameters_temp['Statistics']) - - # Extract always right and wrong labels - ar_temp = parameters_temp['Statistics']['Always right'] - aw_temp = parameters_temp['Statistics']['Always wrong'] - - ar = dict() - aw = dict() - for k in ar_temp.keys(): - ar[k + ' (Right)'] = ar_temp[k] - if (k + ' (Right)') not in ar_labels: - ar_labels.append(k + ' (Right)') - - for k in aw_temp.keys(): - aw[k + ' (Wrong)'] = aw_temp[k] - if (k + ' (Wrong)') not in aw_labels: - aw_labels.append(k + ' (Wrong)') - - # Set patient ID labels - alwaysright.append(ar) - alwayswrong.append(aw) - - parameter_labels = parameters[0].keys() - statistics_labels = statistics[0].keys() - - # Fill in the missing patient labels - - # Read in total sensitivity - if args.ts[0] is not None: - ts = list() - for tsfile in args.ts: - ts_temp = list() - with open(tsfile, 'rb') as f: - reader = csv.reader(f) - for row in reader: - ts_temp.append(row[0]) - ts.append(ts_temp) - - # Combine the svm labels with the ts values in one dictionary - sensitivity = list() - for label, values in zip(feature_labels, ts): - sensitivity_temp = dict() - for key, item in zip(label, values): - sensitivity_temp[key] = item - sensitivity.append(sensitivity_temp) - - else: - sensitivity = [None] - - # Join all labels and values - # if type(patient_labels) == dict: - # patient_labels = patient_labels.keys() - # - # patient_labels_right = list() - # patient_labels_wrong = list() - # for k in patient_labels: - # patient_labels_right.append(k + ' (Right)') - # patient_labels_wrong.append(k + ' (Wrong)') - - if sensitivity[0] is not None: - all_labels = parameter_labels + statistics_labels +\ - natsorted(ar_labels) + natsorted(aw_labels) +\ - natsorted(all_feature_labels) - - parameter_grid = list() - for para, stat, sens, right, wrong in zip(parameters, statistics, - sensitivity, alwaysright, - alwayswrong): - z = dict() - for d in [para, stat, sens, right, wrong]: - for k, v in d.iteritems(): - z[k] = v - - # Fill in missing values in dict with blanks - for key in all_labels: - if key not in z.keys(): - z[key] = '' - - parameter_grid.append(z) - else: - all_labels = parameter_labels + statistics_labels +\ - natsorted(ar_labels) + natsorted(aw_labels) - - parameter_grid = list() - for para, stat, right, wrong in zip(parameters, statistics, - alwaysright, - alwayswrong): - z = dict() - for d in [para, stat, right, wrong]: - for k, v in d.iteritems(): - z[k] = v - - # Fill in missing values in dict with blanks - for key in all_labels: - if key not in z.keys(): - z[key] = '' - - parameter_grid.append(z) - - # Writing to csv file - if type(args.res) == list: - args.res = ''.join(args.res) - - with open(args.res, 'w') as f: - writer = csv.DictWriter(f, fieldnames=all_labels) - writer.writeheader() - for parameter_point in parameter_grid: - writer.writerow(parameter_point) - - print("Done writing results!") - - -if __name__ == '__main__': - main() - - -# 'python' '/scratch/mstarmans/WORC/fastr_Tools/worc/bin/combineresults.py' '--svm' 'svm_13.hdf5' 'svm_1.hdf5' 'svm_12.hdf5' 'svm_11.hdf5' 'svm_18.hdf5' 'svm_15.hdf5' 'svm_10.hdf5' 'svm_14.hdf5' 'svm_0.hdf5' 'svm_19.hdf5' 'svm_17.hdf5' 'svm_5.hdf5' 'svm_2.hdf5' 'svm_4.hdf5' 'svm_7.hdf5' 'svm_6.hdf5' 'svm_3.hdf5' 'svm_9.hdf5' 'svm_8.hdf5' '--perf' 'performance_13.json' 'performance_1.json' 'performance_12.json' 'performance_11.json' 'performance_18.json' 'performance_15.json' 'performance_10.json' 'performance_14.json' 'performance_0.json' 'performance_19.json' 'performance_17.json' 'performance_5.json' 'performance_2.json' 'performance_4.json' 'performance_7.json' 'performance_6.json' 'performance_3.json' 'performance_9.json' 'performance_8.json' '--ts' 'TS_13.csv' 'TS_1.csv' 'TS_12.csv' 'TS_11.csv' 'TS_18.csv' 'TS_15.csv' 'TS_0.csv' 'TS_14.csv' 'TS_10.csv' 'TS_19.csv' 'TS_17.csv' 'TS_5.csv' 'TS_2.csv' 'TS_4.csv' 'TS_7.csv' 'TS_6.csv' 'TS_3.csv' 'TS_9.csv' 'TS_8.csv' '--res' 'results.csv' - -# 'python' '/scratch/mstarmans/WORC/fastr_Tools/worc/bin/combineresults.py' '--svm' 'svm_13.hdf5' 'svm_1.hdf5' 'svm_12.hdf5' 'svm_11.hdf5' 'svm_15.hdf5' 'svm_10.hdf5' 'svm_14.hdf5' 'svm_0.hdf5' 'svm_19.hdf5' 'svm_17.hdf5' 'svm_5.hdf5' 'svm_2.hdf5' 'svm_4.hdf5' 'svm_7.hdf5' 'svm_6.hdf5' 'svm_3.hdf5' 'svm_9.hdf5' 'svm_8.hdf5' '--perf' 'performance_13.json' 'performance_1.json' 'performance_12.json' 'performance_11.json' 'performance_15.json' 'performance_10.json' 'performance_14.json' 'performance_0.json' 'performance_19.json' 'performance_17.json' 'performance_5.json' 'performance_2.json' 'performance_4.json' 'performance_7.json' 'performance_6.json' 'performance_3.json' 'performance_9.json' 'performance_8.json' '--ts' 'TS_13.csv' 'TS_1.csv' 'TS_12.csv' 'TS_11.csv' 'TS_15.csv' 'TS_0.csv' 'TS_14.csv' 'TS_10.csv' 'TS_19.csv' 'TS_17.csv' 'TS_5.csv' 'TS_2.csv' 'TS_4.csv' 'TS_7.csv' 'TS_6.csv' 'TS_3.csv' 'TS_9.csv' 'TS_8.csv' '--res' 'results.csv' - -# 'python' '/home/mstarmans/WORC/fastr_Tools/worc/bin/combineresults.py' '--svm' '/archive/mstarmans/Output/CLM_0503_M1_GL' '--perf' '/archive/mstarmans/Output/CLM_0503_M1_GL' '--ts' '/archive/mstarmans/Output/CLM_0503_M1_GL' '--res' 'results_CLM_0503F1_GL.csv' diff --git a/build/lib/WORC/resources/fastr_tools/worc/bin/fitandscore_tool.py b/build/lib/WORC/resources/fastr_tools/worc/bin/fitandscore_tool.py deleted file mode 100644 index 26fe637d..00000000 --- a/build/lib/WORC/resources/fastr_tools/worc/bin/fitandscore_tool.py +++ /dev/null @@ -1,84 +0,0 @@ -#!/usr/bin/env python - -# Copyright 2016-2019 Biomedical Imaging Group Rotterdam, Departments of -# Medical Informatics and Radiology, Erasmus MC, Rotterdam, The Netherlands -# -# 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 argparse -import json -import pandas as pd -from joblib import Parallel, delayed -from WORC.classification.fitandscore import fit_and_score - - -def main(): - parser = argparse.ArgumentParser(description='Radiomics classification') - parser.add_argument('-ed', '--ed', metavar='ed', - dest='ed', type=str, required=True, - help='Estimator data in (HDF)') - parser.add_argument('-tt', '--tt', metavar='tt', - dest='tt', type=str, required=True, - help='Train- and testdata in (HDF)') - parser.add_argument('-para', '--para', metavar='para', - dest='para', type=str, required=True, - help='Parameters (JSON)') - parser.add_argument('-out', '--out', metavar='out', - dest='out', type=str, required=True, - help='Output: fitted estimator (HDF)') - args = parser.parse_args() - - # Convert lists into strings - if type(args.ed) is list: - args.ed = ''.join(args.ed) - if type(args.tt) is list: - args.tt = ''.join(args.tt) - if type(args.para) is list: - args.para = ''.join(args.para) - if type(args.out) is list: - args.out = ''.join(args.out) - - # Read the data - data = pd.read_hdf(args.ed) - traintest = pd.read_hdf(args.tt) - with open(args.para, 'rb') as fp: - para = json.load(fp) - - n_cores = 1 - ret = Parallel( - n_jobs=n_cores, verbose=data['verbose'], - pre_dispatch=2*n_cores - )(delayed(fit_and_score)(X=data['X'], y=data['y'], - scoring=data['scoring'], - train=traintest['train'], - test=traintest['test'], verbose=data['verbose'], - para=parameters, fit_params=data['fit_params'], - return_train_score=data['return_train_score'], - return_parameters=data['return_parameters'], - return_n_test_samples=data['return_n_test_samples'], - return_times=data['return_times'], - error_score=data['error_score'], - return_all=False) - for parameters in para.values()) - - source_labels = ['RET'] - - source_data =\ - pd.Series([ret], - index=source_labels, - name='Fit and Score Output') - source_data.to_hdf(args.out, 'RET') - - -if __name__ == '__main__': - main() diff --git a/build/lib/WORC/resources/fastr_tools/worc/bin/preprocessing.py b/build/lib/WORC/resources/fastr_tools/worc/bin/preprocessing.py deleted file mode 100644 index baac6038..00000000 --- a/build/lib/WORC/resources/fastr_tools/worc/bin/preprocessing.py +++ /dev/null @@ -1,121 +0,0 @@ -#!/usr/bin/env python - -# Copyright 2017-2018 Biomedical Imaging Group Rotterdam, Departments of -# Medical Informatics and Radiology, Erasmus MC, Rotterdam, The Netherlands -# -# 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 SimpleITK as sitk -import argparse -import pydicom -import WORC.IOparser.config_preprocessing as config_io -import os - - -def main(): - parser = argparse.ArgumentParser(description='Feature extraction') - parser.add_argument('-im', '--im', metavar='image', nargs='+', - dest='im', type=str, required=False, - help='Images to calculate features on') - parser.add_argument('-md', '--md', metavar='metadata', dest='md', - type=str, required=False, nargs='+', - help='Clinical data on patient (DICOM)') - parser.add_argument('-mask', '--mask', metavar='mask', dest='mask', - type=str, required=False, nargs='+', - help='Mask that can be used in normalization') - parser.add_argument('-para', '--para', metavar='Parameters', nargs='+', - dest='para', type=str, required=True, - help='Parameters') - parser.add_argument('-out', '--out', metavar='Features', - dest='out', type=str, required=False, - help='Image output (ITK Image)') - args = parser.parse_args() - - # Convert list inputs to strings - if type(args.im) is list: - args.im = ''.join(args.im) - - if type(args.md) is list: - args.md = ''.join(args.md) - - if type(args.mask) is list: - args.mask = ''.join(args.mask) - - if type(args.para) is list: - args.para = ''.join(args.para) - - if type(args.out) is list: - args.out = ''.join(args.out) - - # Read the config, image and if given masks and metadata - config = config_io.load_config(args.para) - image = sitk.ReadImage(args.im) - - if args.md is not None: - metadata = pydicom.read_file(args.md) - - if args.mask is not None: - mask = sitk.ReadImage(args.mask) - - # Convert image to Hounsfield units if type is CT - image_type = config['ImageFeatures']['image_type'] - # NOTE: We only do this if the input is a DICOM folder - if 'CT' in image_type and not os.path.isfile(args.im): - print('Converting intensity to Hounsfield units.') - image = image*metadata.RescaleSlope +\ - metadata.RescaleIntercept - - # Apply the preprocessing - if config['Normalize']['ROI'] == 'Full': - print('Apply z-scoring on full image.') - image = sitk.Normalize(image) - elif config['Normalize']['ROI'] == 'True': - print('Apply scaling of image based on a Region Of Interest.') - if args.mask is None: - raise IOError('Mask input required for ROI normalization.') - else: - if config['Normalize']['Method'] == 'z_score': - print('Apply scaling using z-scoring based on the ROI') - - # Cast to float to allow proper processing - image = sitk.Cast(image, 9) - - LabelFilter = sitk.LabelStatisticsImageFilter() - LabelFilter.Execute(image, mask) - ROI_mean = LabelFilter.GetMean(1) - ROI_std = LabelFilter.GetSigma(1) - - image = sitk.ShiftScale(image, - shift=-ROI_mean, - scale=1.0/ROI_std) - elif config['Normalize']['Method'] == 'minmed': - print('Apply scaling using the minimum and mean of the ROI') - image = sitk.Cast(image, 9) - - LabelFilter = sitk.LabelStatisticsImageFilter() - LabelFilter.Execute(image, mask) - ROI_median = LabelFilter.GetMedian(1) - ROI_minimum = LabelFilter.GetMinimum(1) - - image = sitk.ShiftScale(image, - shift=-ROI_minimum, - scale=0.5/ROI_median) - else: - print('No preprocessing was applied.') - - # Save the output - sitk.WriteImage(image, args.out) - - -if __name__ == '__main__': - main() diff --git a/build/lib/WORC/resources/fastr_tools/worc/bin/slicer.py b/build/lib/WORC/resources/fastr_tools/worc/bin/slicer.py deleted file mode 100644 index 2ec530ad..00000000 --- a/build/lib/WORC/resources/fastr_tools/worc/bin/slicer.py +++ /dev/null @@ -1,171 +0,0 @@ -#!/usr/bin/env python - -# Copyright 2017-2018 Biomedical Imaging Group Rotterdam, Departments of -# Medical Informatics and Radiology, Erasmus MC, Rotterdam, The Netherlands -# -# 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 SimpleITK as sitk -import argparse -import matplotlib -matplotlib.use('agg') -import matplotlib.pyplot as plt -import numpy as np -from matplotlib.ticker import NullLocator -import matplotlib.colors as colors - - -def slicer(image, mask, output_name, output_name_zoom, thresholds=[-240, 160], - zoomfactor=4): - ''' - image and mask should both be arrays - ''' - - # Determine figure size by spacing - spacing = float(image.GetSpacing()[0]) - imsize = [float(image.GetSize()[0]), float(image.GetSize()[1])] - figsize = (imsize[0]*spacing/100.0, imsize[1]*spacing/100.0) - # dpi = int(200/spacing) - dpi = 100.0 - - # Convert images to numpy arrays - image = sitk.GetArrayFromImage(image) - mask = sitk.GetArrayFromImage(mask) - - # Determine which axial slice has the largest area - areas = np.sum(mask, axis=1).tolist() - max_ind = areas.index(max(areas)) - imslice = image[max_ind, :, :] - maskslice = mask[max_ind, :, :] - - # Threshold the image if desired - if thresholds: - imslice[imslice < thresholds[0]] = thresholds[0] - imslice[imslice > thresholds[1]] = thresholds[1] - - # Plot the image and overlay the mask - fig = plot_im_and_overlay(imslice, maskslice, figsize=figsize) - - # Save Output - fig.savefig(output_name, bbox_inches='tight', pad_inches=0, dpi=dpi) - - # Save some memory - del fig - - # Create a bounding box and save zoomed image - imslice, maskslice = bbox_2D(imslice, maskslice, padding=[20, 20]) - imsize = [float(imslice.shape[0]), float(imslice.shape[1])] - - # NOTE: As these zoomed images get small, we double the spacing - spacing = spacing * zoomfactor - figsize = (imsize[0]*spacing/100.0, imsize[1]*spacing/100.0) - fig = plot_im_and_overlay(imslice, maskslice, figsize=figsize) - fig.savefig(output_name_zoom, bbox_inches='tight', pad_inches=0, dpi=dpi) - plt.close('all') - - # Save some memory - del fig, image, mask - return imslice, maskslice - - -def plot_im_and_overlay(image, mask, figsize=(3, 3), alpha=0.15): - ''' - Plot an image in a matplotlib figure and overlay with a mask. - ''' - # Create a normalized colormap for the image and mask - imin = np.min(image) - imax = np.max(image) - norm_im = colors.Normalize(vmin=imin, vmax=imax, clip=False) - - cmap = plt.get_cmap("Reds") - cmap.set_under(color="white", alpha=0) - cmap.set_over(color="r", alpha=1) - normO = colors.Normalize(vmin=0.5, vmax=0.75, clip=False) - - # Plot and save the full image - fig = plt.figure(figsize=figsize) - ax = fig.add_subplot(1, 1, 1) - ax.imshow(image, cmap=plt.cm.gray, norm=norm_im, interpolation="bilinear") - ax.imshow(mask, cmap=cmap, norm=normO, alpha=alpha, interpolation="bilinear") - - # Set locator to zero to make sure padding is removed upon saving - ax.xaxis.set_major_locator(NullLocator()) - ax.yaxis.set_major_locator(NullLocator()) - - # Turn axis grid of - ax.axis('off') - - return fig - - -def bbox_2D(img, mask, padding=[1, 1], img2=None): - rows = np.any(mask, axis=1) - cols = np.any(mask, axis=0) - - rmin, rmax = np.where(rows)[0][[0, -1]] - cmin, cmax = np.where(cols)[0][[0, -1]] - - # print rmin, rmax, cmin, cmax - rmin = max(0, rmin - padding[0]) - rmax = min(img.shape[0], rmax+padding[0]+1) - cmin = max(0, cmin - padding[1]) - cmax = min(img.shape[1], cmax+padding[1]+1) - - img = img[rmin:rmax, cmin:cmax] - mask = mask[rmin:rmax, cmin:cmax] - if img2 is None: - return img, mask - else: - img2 = img2[rmin:rmax, cmin:cmax] - return img, mask, img2 - - -def main(): - parser = argparse.ArgumentParser(description='Feature extraction') - parser.add_argument('-im', '--im', metavar='image', nargs='+', - dest='im', type=str, required=True, - help='Images to calculate features on') - parser.add_argument('-seg', '--seg', metavar='seg', dest='seg', - type=str, required=True, nargs='+', - help='Segmentation that can be used in normalization') - parser.add_argument('-out', '--out', metavar='out', - dest='out', type=str, required=True, - help='Image output (PNG)') - parser.add_argument('-outzoom', '--outzoom', metavar='outzoom', - dest='outzoom', type=str, required=False, - help='Image output zoomed in (PNG)') - args = parser.parse_args() - - # Convert list inputs to strings - if type(args.im) is list: - args.im = ''.join(args.im) - - if type(args.seg) is list: - args.seg = ''.join(args.seg) - - if type(args.out) is list: - args.out = ''.join(args.out) - - if type(args.outzoom) is list: - args.outzoom = ''.join(args.outzoom) - - # Load the image and segmentation - im = sitk.ReadImage(args.im) - seg = sitk.ReadImage(args.seg) - - # Apply slicing - slicer(im, seg, args.out, args.outzoom) - - -if __name__ == '__main__': - main() diff --git a/build/lib/WORC/resources/fastr_tools/worc/bin/worccastconvert.py b/build/lib/WORC/resources/fastr_tools/worc/bin/worccastconvert.py deleted file mode 100644 index 15b68e74..00000000 --- a/build/lib/WORC/resources/fastr_tools/worc/bin/worccastconvert.py +++ /dev/null @@ -1,43 +0,0 @@ -#!/usr/bin/env python - -# Copyright 2017-2018 Biomedical Imaging Group Rotterdam, Departments of -# Medical Informatics and Radiology, Erasmus MC, Rotterdam, The Netherlands -# -# 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 argparse -import SimpleITK as sitk - - -def main(): - parser = argparse.ArgumentParser(description='Image conversion') - parser.add_argument('-in', '--in', metavar='input', nargs='+', - dest='im', type=str, required=False, - help='Image in (ITK Image)') - parser.add_argument('-out', '--out', metavar='output', - dest='out', type=str, required=False, - help='Image out (ITK Image)') - args = parser.parse_args() - - if type(args.im) is list: - args.im = ''.join(args.im) - - if type(args.out) is list: - args.out = ''.join(args.out) - - image = sitk.ReadImage(args.im) - sitk.WriteImage(image, args.out) - - -if __name__ == '__main__': - main() diff --git a/build/lib/WORC/resources/fastr_tools/worc/combineresults.xml b/build/lib/WORC/resources/fastr_tools/worc/combineresults.xml deleted file mode 100644 index b740dd04..00000000 --- a/build/lib/WORC/resources/fastr_tools/worc/combineresults.xml +++ /dev/null @@ -1,36 +0,0 @@ - - Combine different performance results into a CSV file. - - - - - - - - - combineresults.py svm parameters SI - output = Radiomics classification - - - - - - - - - - - - - - - - - - - usage: combineresults.py [-h] -svm SVM.hdf5 -parameters PARA.json -SI SI.mat -res RESULTS.csv - - - - - diff --git a/build/lib/WORC/resources/fastr_tools/worc/fitandscore.xml b/build/lib/WORC/resources/fastr_tools/worc/fitandscore.xml deleted file mode 100644 index 0b93dd51..00000000 --- a/build/lib/WORC/resources/fastr_tools/worc/fitandscore.xml +++ /dev/null @@ -1,36 +0,0 @@ - - A wrapper around the _fit_and_score function of SKLearn. - - - - - - - - - fitandscore.py input output - output = fitted estimator - - - - - - - - - - - - - - - - - - - TODO - - - - - diff --git a/build/lib/WORC/resources/fastr_tools/worc/worccastconvert.xml b/build/lib/WORC/resources/fastr_tools/worc/worccastconvert.xml deleted file mode 100644 index 0d8a4593..00000000 --- a/build/lib/WORC/resources/fastr_tools/worc/worccastconvert.xml +++ /dev/null @@ -1,36 +0,0 @@ - - A wrapper around SimplITK for conversion of image types. - - - - - - - - - Description: - This program converts between many image formats. - This is done by reading in an image, possibly casting of the image, - and subsequently writing the image to the user-specified format. - - - - - - - - - - - - - - - - - - - - - - diff --git a/build/lib/WORC/resources/fastr_types/BValueFile.py b/build/lib/WORC/resources/fastr_types/BValueFile.py deleted file mode 100644 index 69054d09..00000000 --- a/build/lib/WORC/resources/fastr_types/BValueFile.py +++ /dev/null @@ -1,21 +0,0 @@ -# Copyright 2011-2014 Biomedical Imaging Group Rotterdam, Departments of -# Medical Informatics and Radiology, Erasmus MC, Rotterdam, The Netherlands -# -# 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. - -from fastr.datatypes import URLType - - -class BValueFile(URLType): - description = 'B-value file generated by dcm2nii' - extension = '.bval' diff --git a/build/lib/WORC/resources/fastr_types/BVectorFile.py b/build/lib/WORC/resources/fastr_types/BVectorFile.py deleted file mode 100644 index d0988d85..00000000 --- a/build/lib/WORC/resources/fastr_types/BVectorFile.py +++ /dev/null @@ -1,21 +0,0 @@ -# Copyright 2011-2014 Biomedical Imaging Group Rotterdam, Departments of -# Medical Informatics and Radiology, Erasmus MC, Rotterdam, The Netherlands -# -# 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. - -from fastr.datatypes import URLType - - -class BVectorFile(URLType): - description = 'B-vector file generated by dcm2nii' - extension = 'bvec' diff --git a/build/lib/WORC/resources/fastr_types/CSVFile.py b/build/lib/WORC/resources/fastr_types/CSVFile.py deleted file mode 100644 index 6611ff8b..00000000 --- a/build/lib/WORC/resources/fastr_types/CSVFile.py +++ /dev/null @@ -1,21 +0,0 @@ -# Copyright 2011-2014 Biomedical Imaging Group Rotterdam, Departments of -# Medical Informatics and Radiology, Erasmus MC, Rotterdam, The Netherlands -# -# 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. - -from fastr.datatypes import URLType - - -class CSVFile(URLType): - description = 'CSV file' - extension = 'csv' diff --git a/build/lib/WORC/resources/fastr_types/ConfigFile.py b/build/lib/WORC/resources/fastr_types/ConfigFile.py deleted file mode 100644 index e5e12a60..00000000 --- a/build/lib/WORC/resources/fastr_types/ConfigFile.py +++ /dev/null @@ -1,21 +0,0 @@ -# Copyright 2011-2014 Biomedical Imaging Group Rotterdam, Departments of -# Medical Informatics and Radiology, Erasmus MC, Rotterdam, The Netherlands -# -# 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. - -from fastr.datatypes import URLType - - -class ConfigFile(URLType): - description = 'Python Configuration File' - extension = 'ini' diff --git a/build/lib/WORC/resources/fastr_types/DataFile.py b/build/lib/WORC/resources/fastr_types/DataFile.py deleted file mode 100644 index c28c53c2..00000000 --- a/build/lib/WORC/resources/fastr_types/DataFile.py +++ /dev/null @@ -1,23 +0,0 @@ -# Copyright 2011-2014 Biomedical Imaging Group Rotterdam, Departments of -# Medical Informatics and Radiology, Erasmus MC, Rotterdam, The Netherlands -# -# 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. - - -from fastr.datatypes import TypeGroup - - -class DataFile(TypeGroup): - description = 'General data file for features, classifiers etcetera' - _members = frozenset(['HDF5', - 'RDF']) diff --git a/build/lib/WORC/resources/fastr_types/DicomImageDirectory.py b/build/lib/WORC/resources/fastr_types/DicomImageDirectory.py deleted file mode 100644 index 090ddc6d..00000000 --- a/build/lib/WORC/resources/fastr_types/DicomImageDirectory.py +++ /dev/null @@ -1,55 +0,0 @@ -# Copyright 2011-2014 Biomedical Imaging Group Rotterdam, Departments of -# Medical Informatics and Radiology, Erasmus MC, Rotterdam, The Netherlands -# -# 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 fastr -from fastr.data import url -from fastr.core.version import Version -from fastr.datatypes import URLType - - -class DicomImageDirectory(URLType): - description = 'Dicom Image directory' - extension = '' - - def _validate(self): - value = self.value - - if url.isurl(self.value): - value = url.get_path_from_url(value) - - try: - if not os.path.isdir(value): - return False - - contents = os.listdir(value) - return any(x.endswith('.dcm') for x in contents) - except ValueError: - return False - - def action(self, name): - if name is None: - pass - elif name == "ensure": - if url.isurl(self.value): - dir_name = url.get_path_from_url(self.value) - else: - dir_name = self.value - - fastr.log.debug('ensuring {} exists.'.format(dir_name)) - if not os.path.exists(dir_name): - os.makedirs(dir_name) - else: - fastr.log.warning("unknown action") diff --git a/build/lib/WORC/resources/fastr_types/DicomImageFile.py b/build/lib/WORC/resources/fastr_types/DicomImageFile.py deleted file mode 100644 index 28ae6cdf..00000000 --- a/build/lib/WORC/resources/fastr_types/DicomImageFile.py +++ /dev/null @@ -1,21 +0,0 @@ -# Copyright 2011-2014 Biomedical Imaging Group Rotterdam, Departments of -# Medical Informatics and Radiology, Erasmus MC, Rotterdam, The Netherlands -# -# 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. - -from fastr.datatypes import URLType - - -class DicomImageFile(URLType): - description = 'Single Dicom file' - extension = 'dcm' diff --git a/build/lib/WORC/resources/fastr_types/DummyFile.py b/build/lib/WORC/resources/fastr_types/DummyFile.py deleted file mode 100644 index 6611ff8b..00000000 --- a/build/lib/WORC/resources/fastr_types/DummyFile.py +++ /dev/null @@ -1,21 +0,0 @@ -# Copyright 2011-2014 Biomedical Imaging Group Rotterdam, Departments of -# Medical Informatics and Radiology, Erasmus MC, Rotterdam, The Netherlands -# -# 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. - -from fastr.datatypes import URLType - - -class CSVFile(URLType): - description = 'CSV file' - extension = 'csv' diff --git a/build/lib/WORC/resources/fastr_types/ElastixInput.py b/build/lib/WORC/resources/fastr_types/ElastixInput.py deleted file mode 100644 index 3974d6fb..00000000 --- a/build/lib/WORC/resources/fastr_types/ElastixInput.py +++ /dev/null @@ -1,22 +0,0 @@ -# Copyright 2011-2014 Biomedical Imaging Group Rotterdam, Departments of -# Medical Informatics and Radiology, Erasmus MC, Rotterdam, The Netherlands -# -# 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. - -from fastr.datatypes import TypeGroup - - -class ElastixInput(TypeGroup): - description = 'Input settings for Elastix' - _members = frozenset(['String', - 'ElastixParameterFile']) diff --git a/build/lib/WORC/resources/fastr_types/ElastixLogFile.py b/build/lib/WORC/resources/fastr_types/ElastixLogFile.py deleted file mode 100644 index 4f897aa6..00000000 --- a/build/lib/WORC/resources/fastr_types/ElastixLogFile.py +++ /dev/null @@ -1,25 +0,0 @@ -# Copyright 2011-2014 Biomedical Imaging Group Rotterdam, Departments of -# Medical Informatics and Radiology, Erasmus MC, Rotterdam, The Netherlands -# -# 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. - -from fastr.core.version import Version -from fastr.datatypes import URLType - - -class ElastixLogFile(URLType): - id = 'ElastixLogFile' - name = 'ElastixLogFile' - version = Version('1.0') - description = 'Log file from Elastix' - extension = 'log' diff --git a/build/lib/WORC/resources/fastr_types/ElastixParameterFile.py b/build/lib/WORC/resources/fastr_types/ElastixParameterFile.py deleted file mode 100644 index 4ca6e95e..00000000 --- a/build/lib/WORC/resources/fastr_types/ElastixParameterFile.py +++ /dev/null @@ -1,81 +0,0 @@ -# Copyright 2011-2014 Biomedical Imaging Group Rotterdam, Departments of -# Medical Informatics and Radiology, Erasmus MC, Rotterdam, The Netherlands -# -# 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 re -from fastr.datatypes import URLType - - -class ElastixParameterFile(URLType): - _re_line_parse = re.compile(r'\s*(\(.+\s+.*\))?\s*(//.*)?') - _re_keyvalue_parse = re.compile(r'\((\S+)\s+(.*)\)') - _re_value_parse = re.compile(r'(".*?"|-?\d+\.?\d*)') - - description = 'Elastix Parameter File' - extension = 'txt' - - def __eq__(self, other): - if type(other) is not ElastixParameterFile: - return NotImplemented - - return self._parse() == other._parse() - - def _parse(self, filename=None): - data = dict() - - if filename is None: - filename = self.parsed_value - - with open(filename, 'r') as input_file: - for linenr, line in enumerate(input_file): - match_obj = re.match(self._re_line_parse, line) - - if match_obj.group(1) is not None: - submatch = re.match(self._re_keyvalue_parse, match_obj.group(1)) - key = submatch.group(1) - value = re.findall(self._re_value_parse, submatch.group(2)) - - data[key] = tuple(self._parse_value(x) for x in value) - - initial_field = 'InitialTransformParametersFileName' - if initial_field in data: - initial_filename = data[initial_field][0] - - if initial_filename != 'NoInitialTransform': - if initial_filename[0] not in '\\/': - initial_filename = os.path.join(os.path.dirname(filename), initial_filename) - data[initial_field] = self._parse(initial_filename) - - return data - - def _parse_value(self, item): - if item is None: - return None - - if isinstance(item, (int, float)): - return item - - if item[0] == '"' and item[-1] == '"': - item = item[1:-1] - else: - try: - item = int(item) - except ValueError: - try: - item = float(item) - except ValueError: - item = str(item) - - return item diff --git a/build/lib/WORC/resources/fastr_types/ElastixTransformFile.py b/build/lib/WORC/resources/fastr_types/ElastixTransformFile.py deleted file mode 100644 index c139dadc..00000000 --- a/build/lib/WORC/resources/fastr_types/ElastixTransformFile.py +++ /dev/null @@ -1,81 +0,0 @@ -# Copyright 2011-2014 Biomedical Imaging Group Rotterdam, Departments of -# Medical Informatics and Radiology, Erasmus MC, Rotterdam, The Netherlands -# -# 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 re -from fastr.datatypes import URLType - - -class ElastixTransformFile(URLType): - _re_line_parse = re.compile(r'\s*(\(.+\s+.*\))?\s*(//.*)?') - _re_keyvalue_parse = re.compile(r'\((\S+)\s+(.*)\)') - _re_value_parse = re.compile(r'(".*?"|-?\d+\.?\d*)') - - description = 'Elastix Transform parameter file' - extension = 'txt' - - def __eq__(self, other): - if type(other) is not ElastixTransformFile: - return NotImplemented - - return self._parse() == other._parse() - - def _parse(self, filename=None): - data = dict() - - if filename is None: - filename = self.parsed_value - - with open(filename, 'r') as input_file: - for linenr, line in enumerate(input_file): - match_obj = re.match(self._re_line_parse, line) - - if match_obj.group(1) is not None: - submatch = re.match(self._re_keyvalue_parse, match_obj.group(1)) - key = submatch.group(1) - value = re.findall(self._re_value_parse, submatch.group(2)) - - data[key] = tuple(self._parse_value(x) for x in value) - - initial_field = 'InitialTransformParametersFileName' - if initial_field in data: - initial_filename = data[initial_field][0] - - if initial_filename != 'NoInitialTransform': - if initial_filename[0] not in '\\/': - initial_filename = os.path.join(os.path.dirname(filename), initial_filename) - data[initial_field] = self._parse(initial_filename) - - return data - - def _parse_value(self, item): - if item is None: - return None - - if isinstance(item, (int, float)): - return item - - if item[0] == '"' and item[-1] == '"': - item = item[1:-1] - else: - try: - item = int(item) - except ValueError: - try: - item = float(item) - except ValueError: - item = str(item) - - return item diff --git a/build/lib/WORC/resources/fastr_types/HDF5.py b/build/lib/WORC/resources/fastr_types/HDF5.py deleted file mode 100644 index 0139215f..00000000 --- a/build/lib/WORC/resources/fastr_types/HDF5.py +++ /dev/null @@ -1,22 +0,0 @@ -# Copyright 2011-2014 Biomedical Imaging Group Rotterdam, Departments of -# Medical Informatics and Radiology, Erasmus MC, Rotterdam, The Netherlands -# -# 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. - - -from fastr.datatypes import URLType - - -class HDF5(URLType): - description = 'Pandas HDF5 file' - extension = 'hdf5' diff --git a/build/lib/WORC/resources/fastr_types/MIGRASParameterFile.py b/build/lib/WORC/resources/fastr_types/MIGRASParameterFile.py deleted file mode 100644 index 71d8f09a..00000000 --- a/build/lib/WORC/resources/fastr_types/MIGRASParameterFile.py +++ /dev/null @@ -1,21 +0,0 @@ -# Copyright 2011-2014 Biomedical Imaging Group Rotterdam, Departments of -# Medical Informatics and Radiology, Erasmus MC, Rotterdam, The Netherlands -# -# 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. - -from fastr.datatypes import URLType - - -class MIGRASParameterFile(URLType): - description = 'Parameter file for MIGRAS' - extension = 'ini' diff --git a/build/lib/WORC/resources/fastr_types/MatlabFile.py b/build/lib/WORC/resources/fastr_types/MatlabFile.py deleted file mode 100644 index 1093943d..00000000 --- a/build/lib/WORC/resources/fastr_types/MatlabFile.py +++ /dev/null @@ -1,21 +0,0 @@ -# Copyright 2011-2014 Biomedical Imaging Group Rotterdam, Departments of -# Medical Informatics and Radiology, Erasmus MC, Rotterdam, The Netherlands -# -# 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. - -from fastr.datatypes import URLType - - -class MatlabFile(URLType): - description = 'General matlab data file' - extension = 'mat' diff --git a/build/lib/WORC/resources/fastr_types/MetaData.py b/build/lib/WORC/resources/fastr_types/MetaData.py deleted file mode 100644 index fea9cded..00000000 --- a/build/lib/WORC/resources/fastr_types/MetaData.py +++ /dev/null @@ -1,22 +0,0 @@ -# Copyright 2011-2014 Biomedical Imaging Group Rotterdam, Departments of -# Medical Informatics and Radiology, Erasmus MC, Rotterdam, The Netherlands -# -# 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. - -from fastr.datatypes import TypeGroup - - -class MetaData(TypeGroup): - description = 'Metadata on patient to use as features' - _members = frozenset(['DicomImageFile', - 'Text']) diff --git a/build/lib/WORC/resources/fastr_types/PREDICTParameterFile.py b/build/lib/WORC/resources/fastr_types/PREDICTParameterFile.py deleted file mode 100644 index 55b7277e..00000000 --- a/build/lib/WORC/resources/fastr_types/PREDICTParameterFile.py +++ /dev/null @@ -1,21 +0,0 @@ -# Copyright 2011-2014 Biomedical Imaging Group Rotterdam, Departments of -# Medical Informatics and Radiology, Erasmus MC, Rotterdam, The Netherlands -# -# 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. - -from fastr.datatypes import URLType - - -class PREDICTParameterFile(URLType): - description = 'Parameter file for PREDICT' - extension = 'ini' diff --git a/build/lib/WORC/resources/fastr_types/ParameterFile.py b/build/lib/WORC/resources/fastr_types/ParameterFile.py deleted file mode 100644 index ca8b2a5a..00000000 --- a/build/lib/WORC/resources/fastr_types/ParameterFile.py +++ /dev/null @@ -1,21 +0,0 @@ -# Copyright 2011-2014 Biomedical Imaging Group Rotterdam, Departments of -# Medical Informatics and Radiology, Erasmus MC, Rotterdam, The Netherlands -# -# 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. - -from fastr.datatypes import URLType - - -class ParameterFile(URLType): - description = 'General Parameter File' - extension = 'ini' diff --git a/build/lib/WORC/resources/fastr_types/PatientInfoFile.py b/build/lib/WORC/resources/fastr_types/PatientInfoFile.py deleted file mode 100644 index d2f91fdc..00000000 --- a/build/lib/WORC/resources/fastr_types/PatientInfoFile.py +++ /dev/null @@ -1,24 +0,0 @@ -# Copyright 2011-2014 Biomedical Imaging Group Rotterdam, Departments of -# Medical Informatics and Radiology, Erasmus MC, Rotterdam, The Netherlands -# -# 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. - - -from fastr.datatypes import URLType - - -class PatientInfoFile(URLType): - description = 'Patient info such as genetic data' - _members = frozenset(['TextFile', - 'CSVFile', - 'ConfigFile']) diff --git a/build/lib/WORC/resources/fastr_types/RDF.py b/build/lib/WORC/resources/fastr_types/RDF.py deleted file mode 100644 index 193ed569..00000000 --- a/build/lib/WORC/resources/fastr_types/RDF.py +++ /dev/null @@ -1,22 +0,0 @@ -# Copyright 2011-2014 Biomedical Imaging Group Rotterdam, Departments of -# Medical Informatics and Radiology, Erasmus MC, Rotterdam, The Netherlands -# -# 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. - - -from fastr.datatypes import URLType - - -class RDF(URLType): - description = 'RDF file' - extension = 'RDF' diff --git a/build/lib/WORC/resources/fastr_types/RTStructFile.py b/build/lib/WORC/resources/fastr_types/RTStructFile.py deleted file mode 100644 index 16446f3b..00000000 --- a/build/lib/WORC/resources/fastr_types/RTStructFile.py +++ /dev/null @@ -1,21 +0,0 @@ -# Copyright 2011-2014 Biomedical Imaging Group Rotterdam, Departments of -# Medical Informatics and Radiology, Erasmus MC, Rotterdam, The Netherlands -# -# 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. - -from fastr.datatypes import URLType - - -class RTStructFile(URLType): - description = 'RTStruct Dicom File' - extension = 'dcm' diff --git a/build/lib/WORC/resources/fastr_types/Shelve.py b/build/lib/WORC/resources/fastr_types/Shelve.py deleted file mode 100644 index 0089b6cc..00000000 --- a/build/lib/WORC/resources/fastr_types/Shelve.py +++ /dev/null @@ -1,22 +0,0 @@ -# Copyright 2011-2014 Biomedical Imaging Group Rotterdam, Departments of -# Medical Informatics and Radiology, Erasmus MC, Rotterdam, The Netherlands -# -# 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. - - -from fastr.datatypes import URLType - - -class Shelve(URLType): - description = 'Python shelve storage file' - extension = 'shelve' diff --git a/build/lib/WORC/resources/fastr_types/TexFile.py b/build/lib/WORC/resources/fastr_types/TexFile.py deleted file mode 100644 index 376f6ca6..00000000 --- a/build/lib/WORC/resources/fastr_types/TexFile.py +++ /dev/null @@ -1,21 +0,0 @@ -# Copyright 2017-2018 Biomedical Imaging Group Rotterdam, Departments of -# Medical Informatics and Radiology, Erasmus MC, Rotterdam, The Netherlands -# -# 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. - -from fastr.datatypes import URLType - - -class TexFile(URLType): - description = 'Latex file' - extension = 'tex' diff --git a/build/lib/WORC/resources/fastr_types/TextFile.py b/build/lib/WORC/resources/fastr_types/TextFile.py deleted file mode 100644 index 9b85eb63..00000000 --- a/build/lib/WORC/resources/fastr_types/TextFile.py +++ /dev/null @@ -1,22 +0,0 @@ -# Copyright 2011-2014 Biomedical Imaging Group Rotterdam, Departments of -# Medical Informatics and Radiology, Erasmus MC, Rotterdam, The Netherlands -# -# 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. - - -from fastr.datatypes import URLType - - -class TextFile(URLType): - description = 'Text file' - extension = 'txt' diff --git a/build/lib/WORC/resources/fastr_types/TransformixLogFile.py b/build/lib/WORC/resources/fastr_types/TransformixLogFile.py deleted file mode 100644 index 28dff11d..00000000 --- a/build/lib/WORC/resources/fastr_types/TransformixLogFile.py +++ /dev/null @@ -1,21 +0,0 @@ -# Copyright 2011-2014 Biomedical Imaging Group Rotterdam, Departments of -# Medical Informatics and Radiology, Erasmus MC, Rotterdam, The Netherlands -# -# 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. - -from fastr.datatypes import URLType - - -class TransformixLogFile(URLType): - description = 'Log file from Transformix' - extension = 'log' diff --git a/build/lib/WORC/resources/fastr_types/TransformixOutputPointFile.py b/build/lib/WORC/resources/fastr_types/TransformixOutputPointFile.py deleted file mode 100644 index 9544b692..00000000 --- a/build/lib/WORC/resources/fastr_types/TransformixOutputPointFile.py +++ /dev/null @@ -1,37 +0,0 @@ -# Copyright 2011-2014 Biomedical Imaging Group Rotterdam, Departments of -# Medical Informatics and Radiology, Erasmus MC, Rotterdam, The Netherlands -# -# 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 re - -from fastr.datatypes import URLType - - -class TransformixOutputPointFile(URLType): - description = 'Resulting point file from transformix' - extension = 'txt' - - def _validate(self): - if not super(TransformixOutputPointFile, self)._validate(): - return False - - try: - with open(self.parsed_value) as fin: - for line in fin: - if not re.match('Point\s+(?P\d+)\s+; InputIndex = \[(?P[\s\d]+)\]\s+; InputPoint = \[(?P[\s\d\.-]+)\]\s+; OutputIndexFixed = \[(?P[\s\d]+)\]\s+; OutputPoint = \[(?P[\s\d\.-]+)\]\s+; Deformation = \[(?P[\s\d\.-]+)\]', line): - return False - except IOError: - return False - - return True diff --git a/build/lib/WORC/resources/fastr_types/TransformixParam.py b/build/lib/WORC/resources/fastr_types/TransformixParam.py deleted file mode 100644 index df05e785..00000000 --- a/build/lib/WORC/resources/fastr_types/TransformixParam.py +++ /dev/null @@ -1,22 +0,0 @@ -# Copyright 2011-2014 Biomedical Imaging Group Rotterdam, Departments of -# Medical Informatics and Radiology, Erasmus MC, Rotterdam, The Netherlands -# -# 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. - - -from fastr.datatypes import URLType - - -class TransformixParam(URLType): - description = 'Parameter file for Transformix' - extension = 'txt' diff --git a/build/lib/WORC/resources/fastr_types/TransformixPointFile.py b/build/lib/WORC/resources/fastr_types/TransformixPointFile.py deleted file mode 100644 index 2383699a..00000000 --- a/build/lib/WORC/resources/fastr_types/TransformixPointFile.py +++ /dev/null @@ -1,51 +0,0 @@ -# Copyright 2011-2014 Biomedical Imaging Group Rotterdam, Departments of -# Medical Informatics and Radiology, Erasmus MC, Rotterdam, The Netherlands -# -# 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. - -from fastr.datatypes import URLType - - -class TransformixPointFile(URLType): - description = 'Text file to store point coordinates' - extension = 'txt' - - def _validate(self): - # Special case, for no points, but entire field - if not super(TransformixPointFile, self)._validate(): - return False - - try: - # Extract lines - lines = [] - with open(self.parsed_value) as fin: - for line in fin: - lines.append(line) - - # Check first line is index or point - if lines[0].strip() not in ['index', 'point']: - return False - - # Check second line is number of points - try: - nrpoints = int(lines[1]) - except ValueError: - return False - - # Check number of points in file - if len(lines) != nrpoints + 2: - return False - except IOError: - return False - - return True diff --git a/build/lib/WORC/resources/fastr_types/XlsxFile.py b/build/lib/WORC/resources/fastr_types/XlsxFile.py deleted file mode 100644 index 3994bf48..00000000 --- a/build/lib/WORC/resources/fastr_types/XlsxFile.py +++ /dev/null @@ -1,21 +0,0 @@ -# Copyright 2011-2014 Biomedical Imaging Group Rotterdam, Departments of -# Medical Informatics and Radiology, Erasmus MC, Rotterdam, The Netherlands -# -# 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. - -from fastr.datatypes import URLType - - -class XlsxFile(URLType): - description = 'Excel file with .xlsx extension' - extension = 'xlsx' diff --git a/build/lib/WORC/resources/fastr_types/ZipFile.py b/build/lib/WORC/resources/fastr_types/ZipFile.py deleted file mode 100644 index a9bb1842..00000000 --- a/build/lib/WORC/resources/fastr_types/ZipFile.py +++ /dev/null @@ -1,22 +0,0 @@ -# Copyright 2017-2018 Biomedical Imaging Group Rotterdam, Departments of -# Medical Informatics and Radiology, Erasmus MC, Rotterdam, The Netherlands -# -# 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. - - -from fastr.datatypes import URLType - - -class ZipFile(URLType): - description = 'Zip file' - extension = 'zip' diff --git a/build/lib/WORC/tools/Elastix.py b/build/lib/WORC/tools/Elastix.py deleted file mode 100644 index 844b2752..00000000 --- a/build/lib/WORC/tools/Elastix.py +++ /dev/null @@ -1,312 +0,0 @@ -#!/usr/bin/env python - -# Copyright 2017-2018 Biomedical Imaging Group Rotterdam, Departments of -# Medical Informatics and Radiology, Erasmus MC, Rotterdam, The Netherlands -# -# 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 SimpleITK as sitk -import fastr -import numpy as np -import os -import WORC.addexceptions as WORCexceptions - - -class Elastix(object): - def __init__(self): - # Which version of elastix and transformix tools should be used - self.elastix_toolname = 'Elastix' - self.transformix_toolname = 'Transformix' - - # self.Elastix = sitk.SimpleElastix() - self.create_network('pairwise') - self.FixedImage = [] - self.MovingImage = [] - self.FixedMask = [] - self.MovingMask = [] - self.ToTransform = [] - self.ParameterMaps = [] # sitk.VectorOfParameterMap() - - self.TransformedImage = 'vfs://tmp/WORC_Elastix/results/elastix_output_image_{sample_id}_{cardinality}.nii.gz' - self.TransformedSeg = 'vfs://tmp/WORC_Elastix/results/elastix_output_seg_{sample_id}_{cardinality}.nii.gz' - self.TransformParameters = 'vfs://tmp/WORC_Elastix/results/elastix_output_trans_{sample_id}_{cardinality}.txt' - self.fastr_tmpdir = os.path.join(fastr.config.mounts['tmp'], 'WORC_Elastix') - # TODO: Add initial transformation - - def getparametermap(self, model='affine', size=(512, 512, 128)): - nvoxels = size[0]*size[1]*size[2] - if model == 'rigid': - parameter_map = sitk.GetDefaultParameterMap("rigid") - parameter_map["AutomaticTransformInitialization"] = ["true"] - parameter_map["Metric"] = ["AdvancedMattesMutualInformation"] - parameter_map["NumberOfResolutions"] = ["4"] # save time/memory - parameter_map["NumberOfSpatialSamples"] = [str(nvoxels*0.0001)] # save time/memory - parameter_map["MaximumNumberOfIterations"] = ["1000"] # save time/memory - parameter_map["WriteResultImage"] = ["true"] # save time/memory - parameter_map["ErodeMask"] = ["true"] - - elif model == 'affine': - parameter_map = sitk.GetDefaultParameterMap("affine") - parameter_map["AutomaticTransformInitialization"] = ["false"] - parameter_map["Metric"] = ["AdvancedMattesMutualInformation"] - parameter_map["NumberOfResolutions"] = ["4"] # save time/memory - parameter_map["NumberOfSpatialSamples"] = [str(nvoxels*0.0001)] # save time/memory - parameter_map["MaximumNumberOfIterations"] = ["1000"] # save time/memory - parameter_map["WriteResultImage"] = ["true"] # save time/memory - parameter_map["ErodeMask"] = ["true"] - - elif model == 'bspline': - parameter_map = sitk.GetDefaultParameterMap("bspline") - parameter_map["AutomaticTransformInitialization"] = ["false"] - # parameter_map["Metric"] = ["AdvancedMattesMutualInformation"] - parameter_map["Metric"] = ["AdvancedMattesMutualInformation", "TransformBendingEnergyPenalty"] - parameter_map["Metric0Weight"] = ["1.0"] - parameter_map["Metric1Weight"] = ["750.0"] # *100 is about 5 percent - parameter_map["NumberOfResolutions"] = ["4"] # save time/memory - parameter_map["NumberOfSpatialSamples"] = [str(nvoxels*0.0001)] # save time/memory - parameter_map["WriteResultImage"] = ["true"] # save time/memory - parameter_map["MaximumNumberOfIterations"] = ["1000"] # save time/memory - # parameter_map["ImageSampler"] = ["RandomSamplerSparseMask"] - parameter_map["ErodeMask"] = ["true"] - - else: - raise KeyError("Model {} cannot be found!").format(model) - - return parameter_map - - def create_network(self, nettype): - if nettype == 'pairwise': - # Create the network - self.network = fastr.Network(id_="elastix_pair") - - # Create Sources - self.FixedImageSource = self.network.create_source('ITKImageFile', id_='FixedImage') - self.FixedMaskSource = self.network.create_source('ITKImageFile', id_='FixedMask') - self.MovingImageSource = self.network.create_source('ITKImageFile', id_='MovingImage') - self.MovingMaskSource = self.network.create_source('ITKImageFile', id_='MovingMask') - self.ToTransformSource = self.network.create_source('ITKImageFile', id_='ToTransform') - self.ParameterMapSource = self.network.create_source('ElastixParameterFile', id_='ParameterMaps', nodegroup='par') - # Elastix requires the output folder as a sink - # self.OutputFolderSource = self.network.create_sink('Directory', id_='Out') - - # Create Elastix node and links - self.elastix_node = self.network.create_node(self.elastix_toolname, id_='elastix') - self.elastix_node.inputs['fixed_image'] = self.FixedImageSource.output - self.elastix_node.inputs['fixed_mask'] = self.FixedMaskSource.output - self.elastix_node.inputs['moving_image'] = self.MovingImageSource.output - self.elastix_node.inputs['moving_mask'] = self.MovingMaskSource.output - # self.OutputFolderSource.input = self.elastix_node.outputs['directory'] - self.link_param = self.network.create_link(self.ParameterMapSource.output, self.elastix_node.inputs['parameters']) - self.link_param.collapse = 'par' - - # Create Sinks - self.outtrans = self.network.create_sink('ElastixTransformFile', id_='sink_trans') - self.outimage = self.network.create_sink('ITKImageFile', id_='sink_image') - self.outseg = self.network.create_sink('ITKImageFile', id_='sink_seg') - self.outtrans.inputs['input'] = self.elastix_node.outputs['transform'] - - # Transform output image - self.transformix_node = self.network.create_node(self.transformix_toolname, id_='transformix') - self.transformix_node.inputs['image'] = self.MovingImageSource.output - self.transformix_node.inputs['transform'] = self.elastix_node.outputs['transform'][-1] - self.outimage.inputs['input'] = self.transformix_node.outputs['image'] - - # First change the FinalBSplineInterpolationOrder to 0 for the segmentation - self.changeorder_node = self.network.create_node('EditElastixTransformFile', id_='editelpara') - self.link_trans = self.network.create_link(self.elastix_node.outputs['transform'][-1], self.changeorder_node.inputs['transform']) - # self.link_trans.converge = 0 - # self.link_trans.collapse = 'FixedImage' - # self.link_trans.expand = True - - # Co[y metadata from image to segmentation as Elastix uses this - self.copymetadata_node = self.network.create_node('CopyMetadata', id_='copymetadata') - self.copymetadata_node.inputs['source'] = self.MovingImageSource.output - self.copymetadata_node.inputs['destination'] = self.ToTransformSource.output - - # Then transform the segmentation - self.transformix_node_seg = self.network.create_node(self.transformix_toolname, id_='transformix_seg') - self.transformix_node_seg.inputs['image'] = self.copymetadata_node.outputs['output'] - self.transformix_node_seg.inputs['transform'] = self.changeorder_node.outputs['transform'][-1] - self.outseg.inputs['input'] = self.transformix_node_seg.outputs['image'] - else: - # Create the network - self.network = fastr.Network(id_="elastix_group") - - # Create Sources - self.FixedImageSource = self.network.create_source('ITKImageFile', id_='FixedImage') - self.FixedMaskSource = self.network.create_source('ITKImageFile', id_='FixedMask') - self.ToTransformSource = self.network.create_source('ITKImageFile', id_='ToTransform') - self.ParameterMapSource = self.network.create_source('ElastixParameterFile', id_='ParameterMaps', nodegroup='par') - # Elastix requires the output folder as a sink - # self.OutputFolderSource = self.network.create_sink('Directory', id_='Out') - - # Create Elastix node and links - self.elastix_node = self.network.create_node(self.elastix_toolname, id_='elastix') - self.elastix_node.inputs['fixed_image'] = self.FixedImageSource.output - self.elastix_node.inputs['fixed_mask'] = self.FixedMaskSource.output - self.elastix_node.inputs['moving_image'] = self.FixedImageSource.output - self.elastix_node.inputs['moving_mask'] = self.FixedMaskSource.output - # self.OutputFolderSource.input = self.elastix_node.outputs['directory'] - self.link_param = self.network.create_link(self.ParameterMapSource.output, self.elastix_node.inputs['parameters']) - self.link_param.collapse = 'par' - - # Create Sinks - self.outtrans = self.network.create_sink('ElastixTransformFile', id_='sink_trans') - self.outimage = self.network.create_sink('ITKImageFile', id_='sink_image') - self.outseg = self.network.create_sink('ITKImageFile', id_='sink_seg') - self.outtrans.inputs['input'] = self.elastix_node.outputs['transform'] - - # Transform output image - self.transformix_node = self.network.create_node(self.transformix_toolname, id_='transformix') - self.transformix_node.inputs['image'] = self.MovingImageSource.output - self.transformix_node.inputs['transform'] = self.elastix_node.outputs['transform'][-1] - self.outimage.inputs['input'] = self.transformix_node.outputs['image'] - - # First change the FinalBSplineInterpolationOrder to 0 for the segmentation - self.changeorder_node = self.network.create_node('EditElastixTransformFile', id_='editelpara') - self.changeorder_node.inputs['set'] = ["FinalBSplineInterpolationOrder=0"] - self.link_trans = self.network.create_link(self.elastix_node.outputs['transform'], self.changeorder_node.inputs['transform'][-1]) - # self.link_trans.converge = 0 - # self.link_trans.collapse = 'FixedImage' - # self.link_trans.expand = True - - # Co[y metadata from image to segmentation as Elastix uses this - self.copymetadata_node = self.network.create_node('CopyMetadata', id_='copymetadata') - self.copymetadata_node.inputs['source'] = self.MovingImageSource.output - self.copymetadata_node.inputs['destination'] = self.ToTransformSource.output - - # Then transform the segmentation - self.transformix_node_seg = self.network.create_node(self.transformix_toolname, id_='transformix_seg') - self.transformix_node_seg.inputs['image'] = self.copymetadata_node.outputs['output'] - self.transformix_node_seg.inputs['transform'] = self.changeorder_node.outputs['transform'][-1] - self.outseg.inputs['input'] = self.transformix_node_seg.outputs['image'] - - def addchangeorder(self): - # For the last file, change also the dependence on the previous files - N_parameterfiles = 1 - sources = list() - for num in range(0, N_parameterfiles): - if num != 0: - # We also need to refer to the correct initial transform files - intrans = 'InitialTransformParametersFileName=' +\ - os.path.join(self.fastr_tmpdir, 'editelpara', 'transform_' + str(num - 1) + '.txt') - sources.append("FinalBSplineInterpolationOrder=0" + intrans) - else: - sources.append("FinalBSplineInterpolationOrder=0") - - # self.set = self.network.create_source("AnyType", id_='setorder') - # self.source_data['setorder'] = sources - # self.changeorder_node.inputs['set'] = self.set.output - self.changeorder_node.inputs['set'] = sources - - def create_bbox(self, seg, pad=[2, 25, 25]): - ''' - Create a bounding box around an input segmentation - with a certain padding - ''' - segim = sitk.ReadImage(seg) - segim = sitk.GetArrayFromImage(segim) - segim[segim != 0] = 1 - - nonzero_x = np.nonzero(np.sum(segim, (1, 2)))[0] - nonzero_y = np.nonzero(np.sum(segim, (0, 2)))[0] - nonzero_z = np.nonzero(np.sum(segim, (0, 1)))[0] - - x1, x2 = nonzero_x[0], nonzero_x[-1] - y1, y2 = nonzero_y[0], nonzero_y[-1] - z1, z2 = nonzero_z[0], nonzero_z[-1] - mask = np.zeros(segim.shape) - x1 = max(0, x1 - pad[0]) - x2 = min(segim.shape[0], x2 + pad[0]) - y1 = max(0, y1 - pad[1]) - y2 = min(segim.shape[1], y2 + pad[1]) - z1 = max(0, z1 - pad[2]) - z2 = min(segim.shape[2], z2 + pad[2]) - mask[x1:x2, y1:y2, z1:z2] = 1 - mask = sitk.GetImageFromArray(mask) - - return mask - - def execute(self): - # Check if minimal input is supplied - if not self.FixedImage: - message = "You need to supply a fixed image for registration." - raise WORCexceptions.WORCNotImplementedError(message) - - if not self.MovingImage: - message = "You need to supply a moving image for registration." - raise WORCexceptions.WORCNotImplementedError(message) - - if len(self.ParameterMaps) == 0: - message = "You need to supply at leat one parameter map for registration." - raise WORCexceptions.WORCNotImplementedError(message) - - # Set moving and fixed image sources - self.source_data = dict() - self.source_data['FixedImage'] = self.FixedImage - self.source_data['MovingImage'] = self.MovingImage - - # Create a temporary directory to use - tempdir = os.path.join(fastr.config.mounts['tmp'], 'WORC_Elastix') - if not os.path.exists(tempdir): - os.makedirs(tempdir) - - # Set the parameter map sources - if type(self.ParameterMaps) is list: - # Files, thus just provide them to the elastix node - self.source_data['ParameterMaps'] = self.ParameterMaps - else: - # Use SimpleTransformix to save the maps and add them - SimpleElastix = sitk.SimpleElastix() - self.source_data['ParameterMaps'] = list() - for num, f in enumerate(self.ParameterMaps): - filename = ('ParameterMap{}.txt').format(str(num)) - fname = os.path.join(tempdir, filename) - SimpleElastix.WriteParameterFile(f, fname) - sourcename = 'vfs://tmp/WORC_Elastix/' + filename - self.source_data['ParameterMaps'].append(sourcename) - - # Based on number of parameterfiles, add nodes to train FinalBSplineInterpolationOrder - self.addchangeorder() - - # Set the mask sources if provided - # if self.FixedMask is not None: - self.source_data['FixedMask'] = self.FixedMask - - # if self.MovingMask is not None: - self.source_data['MovingMask'] = self.MovingMask - - # Add other images to transform if given - # if self.ToTransform is not None: - self.source_data['ToTransform'] = self.ToTransform - - # Set the network sinks - self.sink_data = dict() - self.sink_data['sink_trans'] = self.TransformParameters - self.sink_data['sink_image'] = self.TransformedImage - self.sink_data['sink_seg'] = self.TransformedSeg - - # Set outputfolder if given - # if self.OutputFolder: - # self.sink_data['Out'] = self.OutputFolder - # else: - # self.sink_data['Out'] = 'vfs://tmp/WORC_Elastix/output' - - # print self.sink_data['Out'] - - # Execute the network - self.network.draw_network('WORC_Elastix', img_format='svg', draw_dimension=True) - self.network.dumpf('{}.json'.format(self.network.id), indent=2) - self.network.execute(self.source_data, self.sink_data, tmpdir=self.fastr_tmpdir) - - # Automatically read in the images (and parameter maps if requested?) diff --git a/build/lib/WORC/tools/Evaluate.py b/build/lib/WORC/tools/Evaluate.py deleted file mode 100644 index 0e98e75a..00000000 --- a/build/lib/WORC/tools/Evaluate.py +++ /dev/null @@ -1,259 +0,0 @@ -#!/usr/bin/env python - -# Copyright 2016-2019 Biomedical Imaging Group Rotterdam, Departments of -# Medical Informatics and Radiology, Erasmus MC, Rotterdam, The Netherlands -# -# 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 WORC.addexceptions as WORCexceptions -import fastr -import os - -# NOTE: Very important to give images and segmentations as dict with patient names! - - -class Evaluate(object): - def __init__(self, label_type, ensemble=50, scores='percentages', - network=None, features=None, - fastr_plugin='ProcessPoolExecution', - name='Example'): - ''' - Build a network that evaluates the performance of an estimator. - - Parameters - ---------- - - network: fastr network, default None - If you input a network, the evaluate network is added - to the existing network. - - ''' - if network is not None: - self.network = network - self.mode = 'WORC' - else: - self.mode = 'StandAlone' - self.fastr_plugin = fastr_plugin - self.name = 'WORC_Evaluate_' + name - self.network = fastr.Network(id_=self.name) - self.fastr_tmpdir = os.path.join(fastr.config.mounts['tmp'], self.name) - - if features is None and self.mode == 'StandAlone': - raise WORCexceptions.IOError('Either features as input or a WORC network is required for the Evaluate network.') - - self.features = features - - self.label_type = label_type - self.ensemble = ensemble - - self.create_network() - - def create_network(self): - ''' - Add evaluate components to network. - ''' - - # Create all nodes - self.network.node_ROC =\ - self.network.create_node('PlotROC', memory='20G', id_='plot_ROC') - self.network.node_SVM =\ - self.network.create_node('PlotSVM', memory='20G', id_='plot_SVM') - self.network.node_Barchart =\ - self.network.create_node('PlotBarchart', memory='4G', id_='plot_Barchart') - self.network.node_STest =\ - self.network.create_node('StatisticalTestFeatures', memory='4G', id_='statistical_test_features') - self.network.node_Ranked_Percentages =\ - self.network.create_node('PlotRankedScores', memory='20G', id_='plot_ranked_percentages') - self.network.node_Ranked_Posteriors =\ - self.network.create_node('PlotRankedScores', memory='20G', id_='plot_ranked_posteriors') - - # Create sinks - self.network.sink_ROC_PNG =\ - self.network.create_sink('PNGFile', id_='ROC_PNG') - self.network.sink_ROC_Tex =\ - self.network.create_sink('TexFile', id_='ROC_Tex') - self.network.sink_ROC_CSV =\ - self.network.create_sink('CSVFile', id_='ROC_CSV') - - self.network.sink_SVM_Json =\ - self.network.create_sink('JsonFile', id_='SVM_Json') - - self.network.sink_Barchart_PNG =\ - self.network.create_sink('PNGFile', id_='Barchart_PNG') - self.network.sink_Barchart_Tex =\ - self.network.create_sink('TexFile', id_='Barchart_Tex') - - self.network.sink_STest_CSV =\ - self.network.create_sink('CSVFile', id_='StatisticalTestFeatures_CSV') - - self.network.sink_Ranked_Percentages_Zip =\ - self.network.create_sink('ZipFile', id_='RankedPercentages_Zip') - self.network.sink_Ranked_Percentages_CSV =\ - self.network.create_sink('CSVFile', id_='RankedPercentages_CSV') - - self.network.sink_Ranked_Posteriors_Zip =\ - self.network.create_sink('ZipFile', id_='RankedPosteriors_Zip') - self.network.sink_Ranked_Posteriors_CSV =\ - self.network.create_sink('CSVFile', id_='RankedPosteriors_CSV') - - # Create links to sinks - self.network.sink_ROC_PNG.input = self.network.node_ROC.outputs['output_png'] - self.network.sink_ROC_Tex.input = self.network.node_ROC.outputs['output_tex'] - self.network.sink_ROC_CSV.input = self.network.node_ROC.outputs['output_csv'] - - self.network.sink_SVM_Json.input = self.network.node_SVM.outputs['output_json'] - - self.network.sink_Barchart_PNG.input = self.network.node_Barchart.outputs['output_png'] - self.network.sink_Barchart_Tex.input = self.network.node_Barchart.outputs['output_tex'] - - self.network.sink_STest_CSV.input = self.network.node_STest.outputs['performance'] - - self.network.sink_Ranked_Percentages_Zip.input = self.network.node_Ranked_Percentages.outputs['output_zip'] - self.network.sink_Ranked_Percentages_CSV.input = self.network.node_Ranked_Percentages.outputs['output_csv'] - - self.network.sink_Ranked_Posteriors_Zip.input = self.network.node_Ranked_Posteriors.outputs['output_zip'] - self.network.sink_Ranked_Posteriors_CSV.input = self.network.node_Ranked_Posteriors.outputs['output_csv'] - - # Create two constant nodes - self.network.node_Ranked_Percentages.inputs['scores'] = ['percentages'] - self.network.node_Ranked_Posteriors.inputs['scores'] = ['posteriors'] - - # Create sources that are not in WORC and set them - self.network.source_LabelType = self.network.create_source('String', id_='LabelType') - self.network.source_Ensemble = self.network.create_source('String', id_='Ensemble') - self.network.source_LabelType.input = [self.label_type] - self.network.source_Ensemble.input = [self.ensemble] - - # Create sources if not supplied by a WORC network - if self.mode == 'StandAlone': - self.network.source_Estimator = self.network.create_source('HDF5', id_='Estimator') - self.network.source_PatientInfo = self.network.create_source('PatientInfoFile', id_='PatientInfo') - self.network.source_Images = self.network.create_source('ITKImageFile', id_='Images', nodegroup='patients') - self.network.source_Segmentations = self.network.create_source('ITKImageFile', id_='Segmentations', nodegroup='patients') - self.network.source_Config = self.network.create_source('ParameterFile', id_='Config') - - self.labels = list() - self.network.source_Features = list() - for idx in range(0, len(self.features)): - label = 'Features_' + str(idx) - self.labels.append(label) - self.network.source_Features.append(self.network.create_source('HDF5', id_=label, nodegroup='features')) - - # Create links to sources that are not supplied by a WORC network - self.network.node_ROC.inputs['ensemble'] = self.network.source_Ensemble.output - self.network.node_ROC.inputs['label_type'] = self.network.source_LabelType.output - - self.network.node_SVM.inputs['ensemble'] = self.network.source_Ensemble.output - self.network.node_SVM.inputs['label_type'] = self.network.source_LabelType.output - - self.network.node_Barchart.inputs['estimators'] = self.network.source_Ensemble.output - self.network.node_Barchart.inputs['label_type'] = self.network.source_LabelType.output - - self.network.node_Ranked_Percentages.inputs['ensemble'] = self.network.source_Ensemble.output - self.network.node_Ranked_Percentages.inputs['label_type'] = self.network.source_LabelType.output - - self.network.node_Ranked_Posteriors.inputs['ensemble'] = self.network.source_Ensemble.output - self.network.node_Ranked_Posteriors.inputs['label_type'] = self.network.source_LabelType.output - - # Create links to the sources that could be in a WORC network - if self.mode == 'StandAlone': - # Sources from the Evaluate network are used - self.network.node_ROC.inputs['prediction'] = self.network.source_Estimator.output - self.network.node_ROC.inputs['pinfo'] = self.network.source_PatientInfo.output - - self.network.node_SVM.inputs['prediction'] = self.network.source_Estimator.output - self.network.node_SVM.inputs['pinfo'] = self.network.source_PatientInfo.output - - self.network.node_Barchart.inputs['prediction'] = self.network.source_Estimator.output - - self.network.links_STest_Features = list() - for idx, label in enumerate(self.labels): - self.network.links_STest_Features.append(self.network.node_STest.inputs['features'][str(label)] << self.network.source_Features[idx].output) - self.network.links_STest_Features[idx].collapse = 'features' - self.network.node_STest.inputs['patientclass'] = self.network.source_PatientInfo.output - self.network.node_STest.inputs['config'] = self.network.source_Config.output - - self.network.node_Ranked_Percentages.inputs['estimator'] = self.network.source_Estimator.output - self.network.node_Ranked_Percentages.inputs['pinfo'] = self.network.source_PatientInfo.output - self.network.link_images_perc = self.network.create_link(self.network.source_Images.output, self.network.node_Ranked_Percentages.inputs['images']) - self.network.link_images_perc.collapse = 'patients' - self.network.link_segmentations_perc = self.network.create_link(self.network.source_Segmentations.output, self.network.node_Ranked_Percentages.inputs['segmentations']) - self.network.link_segmentations_perc.collapse = 'patients' - - self.network.node_Ranked_Posteriors.inputs['estimator'] = self.network.source_Estimator.output - self.network.node_Ranked_Posteriors.inputs['pinfo'] = self.network.source_PatientInfo.output - self.network.link_images_post = self.network.create_link(self.network.source_Images.output, self.network.node_Ranked_Posteriors.inputs['images']) - self.network.link_images_post.collapse = 'patients' - self.network.link_segmentations_post = self.network.create_link(self.network.source_Segmentations.output, self.network.node_Ranked_Posteriors.inputs['segmentations']) - self.network.link_segmentations_post.collapse = 'patients' - else: - # Sources from the WORC network are used - print('WIP') - - def set(self, estimator=None, pinfo=None, images=None, - segmentations=None, config=None, features=None, - sink_data={}): - ''' - Set the sources and sinks based on the provided attributes. - ''' - if self.mode == 'StandAlone': - self.source_data = dict() - self.sink_data = dict() - - self.source_data['Estimator'] = estimator - self.source_data['PatientInfo'] = pinfo - self.source_data['Images'] = images - self.source_data['Segmentations'] = segmentations - self.source_data['Config'] = config - self.source_data['LabelType'] = self.label_type - self.source_data['Ensemble'] = self.ensemble - - for feature, label in zip(features, self.labels): - self.source_data[label] = feature - - if 'ROC_PNG' not in sink_data.keys(): - self.sink_data['ROC_PNG'] = ("vfs://output/{}/ROC_{{sample_id}}_{{cardinality}}{{ext}}").format(self.name) - if 'ROC_Tex' not in sink_data.keys(): - self.sink_data['ROC_Tex'] = ("vfs://output/{}/ROC_{{sample_id}}_{{cardinality}}{{ext}}").format(self.name) - if 'ROC_CSV' not in sink_data.keys(): - self.sink_data['ROC_CSV'] = ("vfs://output/{}/ROC_{{sample_id}}_{{cardinality}}{{ext}}").format(self.name) - - if 'SVM_Json' not in sink_data.keys(): - self.sink_data['SVM_Json'] = ("vfs://output/{}/performance_{{sample_id}}_{{cardinality}}{{ext}}").format(self.name) - - if 'Barchart_PNG' not in sink_data.keys(): - self.sink_data['Barchart_PNG'] = ("vfs://output/{}/Barchart_{{sample_id}}_{{cardinality}}{{ext}}").format(self.name) - if 'Barchart_Tex' not in sink_data.keys(): - self.sink_data['Barchart_Tex'] = ("vfs://output/{}/Barchart_{{sample_id}}_{{cardinality}}{{ext}}").format(self.name) - - if 'StatisticalTestFeatures_CSV' not in sink_data.keys(): - self.sink_data['StatisticalTestFeatures_CSV'] = ("vfs://output/{}/StatisticalTestFeatures_{{sample_id}}_{{cardinality}}{{ext}}").format(self.name) - - if 'RankedPercentages_Zip' not in sink_data.keys(): - self.sink_data['RankedPercentages_Zip'] = ("vfs://output/{}/RankedPercentages_{{sample_id}}_{{cardinality}}{{ext}}").format(self.name) - if 'RankedPercentages_CSV' not in sink_data.keys(): - self.sink_data['RankedPercentages_CSV'] = ("vfs://output/{}/RankedPercentages_{{sample_id}}_{{cardinality}}{{ext}}").format(self.name) - - if 'RankedPosteriors_Zip' not in sink_data.keys(): - self.sink_data['RankedPosteriors_Zip'] = ("vfs://output/{}/RankedPosteriors_{{sample_id}}_{{cardinality}}{{ext}}").format(self.name) - if 'RankedPosteriors_CSV' not in sink_data.keys(): - self.sink_data['RankedPosteriors_CSV'] = ("vfs://output/{}/RankedPosteriors_{{sample_id}}_{{cardinality}}{{ext}}").format(self.name) - - else: - print('[WORC Warning] Evaluate set attribute not needed when WORC network is provided!') - - def execute(self): - """ Execute the network through the fastr.network.execute command. """ - # Draw and execute nwtwork - self.network.draw_network(self.network.id, draw_dimension=True) - self.network.execute(self.source_data, self.sink_data, execution_plugin=self.fastr_plugin, tmpdir=self.fastr_tmpdir) diff --git a/build/lib/WORC/tools/Slicer.py b/build/lib/WORC/tools/Slicer.py deleted file mode 100644 index e4150950..00000000 --- a/build/lib/WORC/tools/Slicer.py +++ /dev/null @@ -1,118 +0,0 @@ -#!/usr/bin/env python - -# Copyright 2016-2019 Biomedical Imaging Group Rotterdam, Departments of -# Medical Informatics and Radiology, Erasmus MC, Rotterdam, The Netherlands -# -# 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 WORC.addexceptions as WORCexceptions -import fastr -import os - - -class Slicer(object): - def __init__(self, images=None, segmentations=None, - network=None, - fastr_plugin='ProcessPoolExecution', - name='Example'): - ''' - Build a network that evaluates the performance of an estimator. - - Parameters - ---------- - - network: fastr network, default None - If you input a network, the evaluate network is added - to the existing network. - - ''' - if network is not None: - self.network = network - self.mode = 'WORC' - else: - self.mode = 'StandAlone' - self.fastr_plugin = fastr_plugin - self.name = 'WORC_Slicer_' + name - self.network = fastr.Network(id_=self.name) - self.fastr_tmpdir = os.path.join(fastr.config.mounts['tmp'], self.name) - - if images is None and self.mode == 'StandAlone': - message = 'Either images and segmentations as input or a WORC' +\ - 'network is required for the Evaluate network.' - raise WORCexceptions.IOError(message) - - self.image = images - self.segmentations = segmentations - - self.create_network() - - def create_network(self): - ''' - Add evaluate components to network. - ''' - - # Create all nodes - self.network.node_slicer =\ - self.network.create_node('Slicer', memory='20G', id_='Slicer') - - # Create sinks - self.network.sink_PNG =\ - self.network.create_sink('PNGFile', id_='PNG') - self.network.sink_PNGZoomed =\ - self.network.create_sink('PNGFile', id_='PNGZoomed') - - # Create links to sinks - self.network.sink_PNG.input = self.network.node_slicer.outputs['out'] - self.network.sink_PNGZoomed.input = self.network.node_slicer.outputs['outzoom'] - - # Create sources if not supplied by a WORC network - if self.mode == 'StandAlone': - self.network.source_images = self.network.create_source('ITKImage', id_='Images') - self.network.source_segmentations = self.network.create_source('ITKImage', id_='Segmentations') - - # Create links to sources that are not supplied by a WORC network - # Not needed in this network - - # Create links to the sources that could be in a WORC network - if self.mode == 'StandAlone': - # Sources from the Evaluate network are used - self.network.node_slicer.inputs['image'] = self.network.source_images.output - self.network.node_slicer.inputs['segmentation'] = self.network.source_segmentations.output - else: - # Sources from the WORC network are used - print('WIP') - - def set(self, images=None, segmentations=None, sink_data={}): - ''' - Set the sources and sinks based on the provided attributes. - ''' - if self.mode == 'StandAlone': - self.source_data = dict() - self.sink_data = dict() - - self.source_data['Images'] = images - self.source_data['Segmentations'] = segmentations - - if 'PNG' not in sink_data.keys(): - self.sink_data['PNG'] = ("vfs://output/{}/Slice_{{sample_id}}_{{cardinality}}{{ext}}").format(self.name) - if 'PNGZoomed' not in sink_data.keys(): - self.sink_data['PNGZoomed'] = ("vfs://output/{}/Slice_{{sample_id}}_{{cardinality}}_zoomed{{ext}}").format(self.name) - - else: - print('[WORC Warning] Slicer set attribute not needed when WORC network is provided!') - - def execute(self): - """ Execute the network through the fastr.network.execute command. """ - # Draw and execute nwtwork - self.network.draw_network(self.network.id, draw_dimension=True) - self.network.execute(self.source_data, self.sink_data, execution_plugin=self.fastr_plugin, tmpdir=self.fastr_tmpdir) diff --git a/build/lib/WORC/tools/Transformix.py b/build/lib/WORC/tools/Transformix.py deleted file mode 100644 index b6e4bc7f..00000000 --- a/build/lib/WORC/tools/Transformix.py +++ /dev/null @@ -1,49 +0,0 @@ -#!/usr/bin/env python - -# Copyright 2017-2018 Biomedical Imaging Group Rotterdam, Departments of -# Medical Informatics and Radiology, Erasmus MC, Rotterdam, The Netherlands -# -# 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 SimpleITK as sitk -import fastr -import numpy as np -import os -import WORC.addexceptions as WORCexceptions - -#WIP - -class Transformix(object): - def __init__(self): - self.network = self.create_network() - self.MovingImage = None - self.TransformParameterMap = None - - def create_network(self): - self.network = fastr.Network(id_="transformix") - - self.MovingImageSource = self.network.create_source('ITKImageFile', id_='MovingImage') - self.ParameterMapSource = self.network.create_source('ElastixTransformFile', id_='ParameterFile') - - self.transformix_node = self.network.create_node('transformix_dev', id_='transformix') - self.transformix_node.inputs['image'] = self.MovingImageSource.output - self.transformix_node.inputs['transform'] = self.ParameterMapSource.output - - self.outimage = self.network.create_sink('ITKImageFile', id_='sink_image') - self.outimage.inputs['input'] = self.transformix_node.outputs['image'] - - self.network.draw_network(img_format='svg') - self.network.dumpf('{}.json'.format(self.network.id), indent=2) - - def execute(self): - SimpleTransformix = sitk.SimpleTransformix() diff --git a/build/lib/WORC/tools/__init__.py b/build/lib/WORC/tools/__init__.py deleted file mode 100644 index e69de29b..00000000 diff --git a/dist/WORC-3.0.0-py3-none-any.whl b/dist/WORC-3.0.0-py3-none-any.whl deleted file mode 100644 index 06fec77b..00000000 Binary files a/dist/WORC-3.0.0-py3-none-any.whl and /dev/null differ diff --git a/readthedocs.yml b/readthedocs.yml new file mode 100644 index 00000000..2185ce66 --- /dev/null +++ b/readthedocs.yml @@ -0,0 +1,8 @@ +# .readthedocs.yml + +build: + image: latest + +python: + version: 3.7 + pip_install: true diff --git a/requirements.txt b/requirements.txt index 51cf6dec..2bd093df 100644 --- a/requirements.txt +++ b/requirements.txt @@ -1,3 +1,4 @@ +numpy>=1.16.3 fastr>=3.1.1 xnat>=0.2.2 configparser>=3.5.0 @@ -5,7 +6,6 @@ natsort>=5.0.1 drmaa>=0.7.6 nose>=1.3.7 nose-parameterized>=0.5.0 -numpy>=1.16.3 tqdm>=4.7.1 six>=1.10.0 sphinx>=1.4 @@ -16,11 +16,11 @@ xlrd>=1.2.0 tables>=3.5.1 pydicom>=1.2.2 ghalton>=0.6.1 -imbalanced-learn>=0.4.3 -scikit-learn>=0.20.3 +imbalanced-learn==0.4.3 +scikit-learn==0.20.3 scipy>=1.2.1 SimpleITK>=1.2.0 missingpy>=0.2.0 matplotlib2tikz>=0.7.4 lifelines>=0.21.1 -PREDICT>=3.0.0 +PREDICT>=3.1.1 diff --git a/setup.py b/setup.py index 765cca4f..551f5d01 100644 --- a/setup.py +++ b/setup.py @@ -52,7 +52,6 @@ def scan_dir(path, prefix=None): return file_list - # Determine the extra resources and scripts to pack resources_list = scan_dir('./WORC/resources') @@ -70,9 +69,12 @@ def scan_dir(path, prefix=None): ] } -# Determine the fastr config path -USER_DIR = os.path.expanduser(os.path.join('~', '.fastr')) -config_d = os.path.join(USER_DIR, 'config.d') +# Determine the fastr config path: create if non-existent +fastr_home = os.path.expanduser(os.path.join('~', '.fastr')) +if not os.path.exists(fastr_home): + os.makedirs(fastr_home) + +config_d = os.path.join(fastr_home, 'config.d') worc_config = os.path.join('WORC', 'fastrconfig', 'WORC_config.py') @@ -90,7 +92,7 @@ def run_tests(self): setup( name='WORC', - version='3.0.0', + version='3.1.0', description='Workflow for Optimal Radiomics Classification.', long_description=_description, url='https://github.com/MStarmans91/WORC', diff --git a/tests/tests.py b/tests/tests.py deleted file mode 100644 index 9e8a1cda..00000000 --- a/tests/tests.py +++ /dev/null @@ -1 +0,0 @@ -import WORC diff --git a/tests/tests.pyc b/tests/tests.pyc deleted file mode 100644 index 74e4c7a7..00000000 Binary files a/tests/tests.pyc and /dev/null differ diff --git a/version b/version index 4a36342f..fd2a0186 100644 --- a/version +++ b/version @@ -1 +1 @@ -3.0.0 +3.1.0