class gtractResampleFibersInputSpec(CommandLineInputSpec):
	inputForwardDeformationFieldVolume = File( exists = "True",argstr = "--inputForwardDeformationFieldVolume %s")
	inputReverseDeformationFieldVolume = File( exists = "True",argstr = "--inputReverseDeformationFieldVolume %s")
	inputTract = traits.Str( argstr = "--inputTract %s")
	outputTract = traits.Str( argstr = "--outputTract %s")
	writeXMLPolyDataFile = traits.Bool( argstr = "--writeXMLPolyDataFile ")
class StateMachine(traits.HasTraits):
    """runs in stimulus control process, communicates with user script via queues"""
    current_state = traits.Str('offline')

    def __init__(self, to_state_machine, from_state_machine,
                 stimulus_state_queue, stimulus_timeseries_queue,
                 display_text_queue):
        super(StateMachine, self).__init__()
        self.to_state_machine = to_state_machine
        self.from_state_machine = from_state_machine

        self.gain = -40.0
        self.offset = 0.0

        self.stripe_pos_degrees = 0.0
        self.last_time = time.time()

        self.current_state_finished_time = None

        self.stimulus_state_queue = stimulus_state_queue
        self.stimulus_timeseries_queue = stimulus_timeseries_queue
        self.display_text_queue = display_text_queue

        self.save_sequence = False
        self.save_sequence_t_start = None
        self.saved_sequence_times = []
        self.saved_sequence_positions = []
        self.saved_sequence_vels = []

    def _current_state_changed(self):
        # see ER_data_format.py
        self.stimulus_state_queue.put((time.time(), self.current_state))

    def tick(self, delta_degrees):
        # update stripe position...
        try:
            incoming_message = self.to_state_machine.get_nowait()
        except multiprocessing.queues.Empty:
            pass
        else:
            print 'got message', incoming_message
            if incoming_message.startswith('CL '):
                parts = incoming_message.split()
                tmp, gain, offset, duration_sec, save_sequence = parts
                self.gain = float(gain)
                self.offset = eval(
                    offset)  # could instantiate SinusoidalBias class
                duration_sec = float(duration_sec)
                self.save_sequence = bool(int(save_sequence))
                self.current_state = incoming_message
                now = time.time()
                self.current_state_finished_time = now + duration_sec
                print 'switching to closed loop'
                if save_sequence:
                    self.save_sequence_t_start = None
                    self.saved_sequence_times = []
                    self.saved_sequence_positions = []
                    self.saved_sequence_vels = []
                    print 'saving sequence for replay (cleared any old saved sequence)'
                self.display_text_queue.put(
                    'closed loop for %.1f sec (gain=%.1f, offset=%s)' %
                    (duration_sec, self.gain, self.offset))
            elif incoming_message == 'REPLAY':
                self.saved_sequence_times = np.array(self.saved_sequence_times)
                self.saved_sequence_vels = np.array(self.saved_sequence_vels)
                print 'replay times:', self.saved_sequence_times[
                    0], self.saved_sequence_times[-1]
                self.vel_interp = scipy.interpolate.interp1d(
                    self.saved_sequence_times, self.saved_sequence_vels)

                # interpolation is slightly tricky here...
                replay_rad = np.unwrap(
                    np.array(self.saved_sequence_positions) * D2R)
                self.pos_interp = scipy.interpolate.interp1d(
                    self.saved_sequence_times, replay_rad)

                duration_sec = self.saved_sequence_times[-1]
                now = time.time()
                self.current_state_finished_time = now + duration_sec
                self.save_sequence_t_start = None
                self.current_state = incoming_message
                self.display_text_queue.put('replaying saved stimulus')
            elif incoming_message.startswith('OLs '):
                parts = incoming_message.split()
                tmp, start_pos_deg, stop_pos_deg, velocity_dps = parts
                start_pos_deg, stop_pos_deg, velocity_dps = map(
                    float, (start_pos_deg, stop_pos_deg, velocity_dps))
                self.current_state = incoming_message
                total_deg = stop_pos_deg - start_pos_deg
                duration_sec = total_deg / velocity_dps
                if duration_sec < 0:
                    raise ValueError('impossible combination')
                self.gain = 0
                self.offset = velocity_dps
                self.stripe_pos_degrees = start_pos_deg
                now = time.time()
                self.current_state_finished_time = now + duration_sec
                print 'switching to open loop sweep'
                self.display_text_queue.put(
                    'open loop sweep from %.1f to %.1f at %.1f deg/sec for %.1f sec'
                    % (
                        start_pos_deg,
                        stop_pos_deg,
                        velocity_dps,
                        duration_sec,
                    ))
            else:
                raise ValueError('Unknown message: %s' % incoming_message)

        if self.current_state != 'offline':
            now = time.time()
            if now >= self.current_state_finished_time:
                print 'switching to offline because current state ended'
                outgoing_message = 'done ' + self.current_state
                self.from_state_machine.put(outgoing_message)
                self.current_state = 'offline'
                self.save_sequence = False

        now = time.time()

        if self.current_state == 'REPLAY':
            if self.save_sequence_t_start is None:
                self.save_sequence_t_start = now
            seq_t = now - self.save_sequence_t_start
            vel_dps = self.vel_interp(seq_t)
            pos_rad_wrapped = self.pos_interp(seq_t)
            self.stripe_pos_degrees = (pos_rad_wrapped * R2D + 180) % 360 - 180
        else:

            if isinstance(self.offset, SinusoidalBias):
                offset = self.offset.update(now)
            else:
                offset = self.offset

            # update self.vel every frame so that changes in gain and offset noticed
            vel_dps = delta_degrees * self.gain + offset

            # Compute stripe position.
            dt = now - self.last_time
            self.last_time = now

            self.stripe_pos_degrees += vel_dps * dt
            # put in range -180 <= angle < 180
            self.stripe_pos_degrees = (self.stripe_pos_degrees +
                                       180) % 360 - 180

            if self.save_sequence:
                if self.save_sequence_t_start is None:
                    self.save_sequence_t_start = now
                seq_t = now - self.save_sequence_t_start
                self.saved_sequence_times.append(seq_t)
                self.saved_sequence_positions.append(self.stripe_pos_degrees)
                self.saved_sequence_vels.append(vel_dps)

        return self.stripe_pos_degrees, vel_dps
class gtractCreateGuideFiberInputSpec(CommandLineInputSpec):
	inputFiber = traits.Str( argstr = "--inputFiber %s")
	numberOfPoints = traits.Int( argstr = "--numberOfPoints %d")
	outputFiber = traits.Str( argstr = "--outputFiber %s")
	writeXMLPolyDataFile = traits.Bool( argstr = "--writeXMLPolyDataFile ")
示例#4
0
class PipelineConfiguration(traits.HasTraits):

    # project settings
    project_dir = traits.Directory(
        exists=False, desc="data path to where the project is stored")

    # project metadata (for connectome file)
    project_metadata = traits.Dict(
        desc="project metadata to be stored in the connectome file")
    # DEPRECATED: this field is deprecated after version >1.0.2
    generator = traits.Str()

    # parcellation scheme
    parcellation_scheme = traits.Enum("NativeFreesurfer",
                                      ["Lausanne2008", "NativeFreesurfer"],
                                      desc="used parcellation scheme")

    # choose between 'L' (linear) and 'N' (non-linear) and 'B' (bbregister)
    registration_mode = traits.Enum(
        "Linear", ["Linear", "Nonlinear", "BBregister"],
        desc="registration mode: linear or non-linear or bbregister")

    # choose between 'L' (linear) and 'B' (bbregister)
    rsfmri_registration_mode = traits.Enum(
        "Linear", ["Linear", "BBregister"],
        desc="registration mode: linear or bbregister")

    diffusion_imaging_model = traits.Enum("DSI", ["DSI", "DTI", "QBALL"])

    # DSI
    nr_of_gradient_directions = traits.Str('515')
    nr_of_sampling_directions = traits.Str('181')
    odf_recon_param = traits.Str('-b0 1 -dsi -p 4 -sn 0')
    hardi_recon_param = traits.Str('-b0 1 -p 3 -sn 0')

    # DTI
    gradient_table_file = traits.File(exists=False)
    gradient_table = traits.Enum('siemens_64', [
        'custom', 'mgh_dti_006', 'mgh_dti_018', 'mgh_dti_030', 'mgh_dti_042',
        'mgh_dti_060', 'mgh_dti_072', 'mgh_dti_090', 'mgh_dti_120',
        'mgh_dti_144', 'siemens_06', 'siemens_12', 'siemens_20', 'siemens_256',
        'siemens_30', 'siemens_64'
    ])
    nr_of_b0 = traits.Str('1')
    max_b0_val = traits.Str('1000')
    dti_recon_param = traits.Str('')
    dtb_dtk2dir_param = traits.Str('')

    # tractography
    streamline_param = traits.Str('--angle 60  --seeds 32')

    # registration
    lin_reg_param = traits.Str('-usesqform -nosearch -dof 6 -cost mutualinfo')
    nlin_reg_bet_T2_param = traits.Str('-f 0.35 -g 0.15')
    nlin_reg_bet_b0_param = traits.Str('-f 0.2 -g 0.2')
    nlin_reg_fnirt_param = traits.Str(
        '--subsamp=8,4,2,2 --miter==5,5,5,5 --lambda=240,120,90,30 --splineorder=3 --applyinmask=0,0,1,1 --applyrefmask=0,0,1,1'
    )
    bb_reg_param = traits.Str('--init-header --dti')

    # dicom converter
    do_convert_diffusion = traits.Bool(True)
    do_convert_T1 = traits.Bool(True)
    do_convert_T2 = traits.Bool(False)
    do_convert_fMRI = traits.Bool(False)

    # rsfmri
    rsfmri_lin_reg_param = traits.Str(
        '-usesqform -nosearch -dof 6 -cost mutualinfo')
    rsfmri_bb_reg_param = traits.Str('--init-header --dti')
    do_save_mat = traits.Bool(True)

    # DEPRECATED:
    subject_raw_glob_diffusion = traits.Str("*.*")
    subject_raw_glob_T1 = traits.Str("*.*")
    subject_raw_glob_T2 = traits.Str("*.*")
    extract_diffusion_metadata = traits.Bool(False)

    # subject
    subject_name = traits.Str()
    subject_timepoint = traits.Str()
    subject_workingdir = traits.Directory()
    subject_logger = None
    subject_metadata = [
        KeyValue(key='description', value=''),
        KeyValue(key='', value=''),
        KeyValue(key='', value=''),
        KeyValue(key='', value=''),
        KeyValue(key='', value=''),
        KeyValue(key='', value=''),
    ]

    active_createfolder = traits.Bool(True)
    active_dicomconverter = traits.Bool(False)
    active_registration = traits.Bool(False)
    active_segmentation = traits.Bool(False)
    active_parcellation = traits.Bool(False)
    active_applyregistration = traits.Bool(False)
    active_reconstruction = traits.Bool(False)
    active_tractography = traits.Bool(False)
    active_fiberfilter = traits.Bool(False)
    active_connectome = traits.Bool(False)
    active_statistics = traits.Bool(False)
    active_rsfmri = traits.Bool(False)
    active_cffconverter = traits.Bool(False)
    skip_completed_stages = traits.Bool(False)

    # metadata
    creator = traits.Str()
    email = traits.Str()
    publisher = traits.Str()
    created = traits.Date()
    modified = traits.Date()
    license = traits.Str()
    #    rights = traits.Str()
    reference = traits.Str()
    #    relation =  traits.Str()
    species = traits.Str('H**o sapiens')
    description = traits.Str()

    # segmentation
    recon_all_param = traits.Str('-all -no-isrunning')

    # parcellation
    custompar_nrroi = traits.Int()
    custompar_nodeinfo = traits.File()
    custompar_volumeparcell = traits.File()

    # fiber filtering
    apply_splinefilter = traits.Bool(
        True, desc='apply the spline filtering from diffusion toolkit')
    apply_fiberlength = traits.Bool(True, desc='apply cutoff to fiber lengths')
    fiber_cutoff_lower = traits.Float(
        20.0,
        desc='cut fibers that are shorter in length than given length in mm')
    fiber_cutoff_upper = traits.Float(
        500.0,
        desc='cut fibers that are longer in length than given length in mm')

    # measures
    connection_P0 = traits.Bool(False)
    connection_gfa = traits.Bool(False)
    connection_kurtosis = traits.Bool(False)
    connection_skewness = traits.Bool(False)
    connection_adc = traits.Bool(False)
    connection_fa = traits.Bool(False)

    # cff converter
    cff_fullnetworkpickle = traits.Bool(
        True,
        desc='stores the full network pickle generated by connectome creation')
    cff_cmatpickle = traits.Bool(True)
    cff_originalfibers = traits.Bool(True, desc='stores original fibers')
    cff_filteredfibers = traits.Bool(True, desc='stores filtered fibers')
    cff_finalfiberlabels = traits.Bool(
        True, desc='stores final fibers and their labelarrays')
    cff_fiberarr = traits.Bool(True)
    cff_rawdiffusion = traits.Bool(True)
    cff_scalars = traits.Bool(True)
    cff_rawT1 = traits.Bool(True)
    cff_rawT2 = traits.Bool(True)
    cff_roisegmentation = traits.Bool(
        True, desc='stores multi-resolution parcellation volumes')
    cff_surfaces = traits.Bool(True,
                               desc='stores individually genertated surfaces')
    cff_surfacelabels = traits.Bool(
        True, desc='stores individually genertated surfaces')

    # do you want to do manual white matter mask correction?
    wm_handling = traits.Enum(
        1, [1, 2, 3],
        desc="in what state should the freesurfer step be processed")

    # custom parcellation
    parcellation = traits.Dict(
        desc="provide the dictionary with your parcellation.")

    # start up fslview
    inspect_registration = traits.Bool(
        False, desc='start fslview to inspect the the registration results')
    fsloutputtype = traits.Enum('NIFTI', ['NIFTI'])

    # connectome creation
    compute_curvature = traits.Bool(False)

    # email notification, needs a local smtp server
    # sudo apt-get install postfix
    emailnotify = traits.ListStr(
        [], desc='the email address to send stage completion status message')

    freesurfer_home = traits.Directory(exists=False, desc="path to Freesurfer")
    fsl_home = traits.Directory(exists=False, desc="path to FSL")
    dtk_home = traits.Directory(exists=False, desc="path to diffusion toolkit")

    # This file stores descriptions of the inputs/outputs to each stage of the
    # CMP pipeline.  It can be queried using the PipelineStatus python object
    pipeline_status_file = traits.Str("cmp.status")

    # Pipeline status object
    pipeline_status = pipeline_status.PipelineStatus()

    def _get_lausanne_parcellation(self, parcel="NativeFreesurfer"):

        if parcel == "Lausanne2008":
            return {
                'scale33': {
                    'number_of_regions':
                    83,
                    # contains name, url, color, freesurfer_label, etc. used for connection matrix
                    'node_information_graphml':
                    op.join(
                        self.get_lausanne_parcellation_path('resolution83'),
                        'resolution83.graphml'),
                    # scalar node values on fsaverage? or atlas?
                    'surface_parcellation':
                    None,
                    # scalar node values in fsaverage volume?
                    'volume_parcellation':
                    None,
                    # the subdirectory name from where to copy parcellations, with hemispheric wildcard
                    'fs_label_subdir_name':
                    'regenerated_%s_36',
                    # should we subtract the cortical rois for the white matter mask?
                    'subtract_from_wm_mask':
                    1,
                },
                'scale60': {
                    'number_of_regions':
                    129,
                    'node_information_graphml':
                    op.join(
                        self.get_lausanne_parcellation_path('resolution150'),
                        'resolution150.graphml'),
                    'surface_parcellation':
                    None,
                    'volume_parcellation':
                    None,
                    'fs_label_subdir_name':
                    'regenerated_%s_60',
                    'subtract_from_wm_mask':
                    1,
                },
                'scale125': {
                    'number_of_regions':
                    234,
                    'node_information_graphml':
                    op.join(
                        self.get_lausanne_parcellation_path('resolution258'),
                        'resolution258.graphml'),
                    'surface_parcellation':
                    None,
                    'volume_parcellation':
                    None,
                    'fs_label_subdir_name':
                    'regenerated_%s_125',
                    'subtract_from_wm_mask':
                    1,
                },
                'scale250': {
                    'number_of_regions':
                    463,
                    'node_information_graphml':
                    op.join(
                        self.get_lausanne_parcellation_path('resolution500'),
                        'resolution500.graphml'),
                    'surface_parcellation':
                    None,
                    'volume_parcellation':
                    None,
                    'fs_label_subdir_name':
                    'regenerated_%s_250',
                    'subtract_from_wm_mask':
                    1,
                },
                'scale500': {
                    'number_of_regions':
                    1015,
                    'node_information_graphml':
                    op.join(
                        self.get_lausanne_parcellation_path('resolution1015'),
                        'resolution1015.graphml'),
                    'surface_parcellation':
                    None,
                    'volume_parcellation':
                    None,
                    'fs_label_subdir_name':
                    'regenerated_%s_500',
                    'subtract_from_wm_mask':
                    1,
                },
            }
        else:
            return {
                'freesurferaparc': {
                    'number_of_regions':
                    83,
                    # contains name, url, color, freesurfer_label, etc. used for connection matrix
                    'node_information_graphml':
                    op.join(
                        self.get_lausanne_parcellation_path('freesurferaparc'),
                        'resolution83.graphml'),
                    # scalar node values on fsaverage? or atlas?
                    'surface_parcellation':
                    None,
                    # scalar node values in fsaverage volume?
                    'volume_parcellation':
                    None,
                }
            }

    def __init__(self, **kwargs):
        # NOTE: In python 2.6, object.__init__ no longer accepts input
        # arguments.  HasTraits does not define an __init__ and
        # therefore these args were being ignored.
        super(PipelineConfiguration, self).__init__(**kwargs)

        # the default parcellation provided
        self.parcellation = self._get_lausanne_parcellation(
            parcel="NativeFreesurfer")

        self.can_use_dipy = dipy_here

        # no email notify
        self.emailnotify = []

        # default gradient table for DTI
        self.gradient_table_file = self.get_cmp_gradient_table('siemens_64')

        # try to discover paths from environment variables
        try:
            self.freesurfer_home = op.join(os.environ['FREESURFER_HOME'])
            self.fsl_home = op.join(os.environ['FSLDIR'])
            self.dtk_home = os.environ['DTDIR']
            self.dtk_matrices = op.join(self.dtk_home, 'matrices')
        except KeyError:
            pass

        self.fsloutputtype = 'NIFTI'
        os.environ['FSLOUTPUTTYPE'] = self.fsloutputtype
        os.environ['FSLOUTPUTTYPE'] = 'NIFTI'

    def consistency_check(self):
        """ Provides a checking facility for configuration objects """

        # project name not empty
        if not op.exists(self.project_dir):
            msg = 'Your project directory does not exist!'
            raise Exception(msg)

        # check metadata
        if self.creator == '':
            raise Exception('You need to enter creator metadata!')
        if self.publisher == '':
            raise Exception('You need to enter publisher metadata!')
        if self.email == '':
            raise Exception('You need to enter email of a contact person!')

        # check if software paths exists
        pas = {
            'configuration.freesurfer_home': self.freesurfer_home,
            'configuration.fsl_home': self.fsl_home,
            'configuration.dtk_home': self.dtk_home,
            'configuration.dtk_matrices': self.dtk_matrices
        }
        for k, p in pas.items():
            if not op.exists(p):
                msg = 'Required software path for %s does not exists: %s' % (k,
                                                                             p)
                raise Exception(msg)

        if self.subject_workingdir == '':
            msg = 'No working directory defined for subject'
            raise Exception(msg)
#        else:
#            wdir = self.get_subj_dir()
#            if not op.exists(wdir):
#                msg = 'Working directory %s does not exists for subject' % (wdir)
#                raise Exception(msg)
#            else:
#                wdiff = op.join(self.get_raw_diffusion())
#                print wdiff
#                if not op.exists(wdiff):
#                    msg = 'Diffusion MRI subdirectory %s does not exists for the subject' % wdiff
#                    raise Exception(msg)
#                wt1 = op.join(self.get_rawt1())
#                if not op.exists(wt1):
#                    msg = 'Structural MRI subdirectory %s T1 does not exist in RAWDATA' % wt1
#                    raise Exception(msg)

    def get_cmp_home(self):
        """ Return the cmp home path """
        return op.dirname(__file__)

    def get_rawdata(self):
        """ Return raw data path for the subject """
        return op.join(self.get_subj_dir(), 'RAWDATA')

    def get_log(self):
        """ Get subject log dir """
        return op.join(self.get_subj_dir(), 'LOG')

    def get_logname(self, suffix='.log'):
        """ Get a generic name for the log and pickle files """
        a = dt.datetime.now()
        return 'pipeline-%s-%02i%02i-%s-%s%s' % (
            a.date().isoformat(), a.time().hour, a.time().minute,
            self.subject_name, self.subject_timepoint, suffix)

    def get_logger(self):
        """ Get the logger instance created """
        if self.subject_logger is None:
            # setup logger for the subject
            self.subject_logger = \
                getLog(os.path.join(self.get_log(), self.get_logname()))
            return self.subject_logger
        else:
            return self.subject_logger

    def get_rawglob(self, modality):
        """ DEPRECATED: Get the file name endings for modality """

        if modality == 'diffusion':
            if not self.subject_raw_glob_diffusion == '':
                return self.subject_raw_glob_diffusion
            else:
                raise Exception('No raw_glob_diffusion defined for subject')

        elif modality == 'T1':
            if not self.subject_raw_glob_T1 == '':
                return self.subject_raw_glob_T1
            else:
                raise Exception('No raw_glob_T1 defined for subject')

        elif modality == 'T2':
            if not self.subject_raw_glob_T2 == '':
                return self.subject_raw_glob_T2
            else:
                raise Exception('No raw_glob_T2 defined for subject')

    def get_dicomfiles(self, modality):
        """ Get a list of dicom files for the requested modality. Tries to
        discover them automatically
        """
        from glob import glob

        if modality == 'diffusion':
            pat = self.get_raw_diffusion()
        elif modality == 'T1':
            pat = self.get_rawt1()
        elif modality == 'T2':
            pat = self.get_rawt2()
        elif modality == 'fMRI':
            pat = self.get_rawrsfmri()

        # discover files with *.* and *
        difiles = sorted(glob(op.join(pat, '*.*')) + glob(op.join(pat, '*')))

        # exclude potential .nii and .nii.gz files
        difiles = [
            e for e in difiles
            if not e.endswith('.nii') and not e.endswith('.nii.gz')
        ]

        # check if no files and throw exception
        if len(difiles) == 0:
            raise Exception('Could not find any DICOM files in folder %s' %
                            pat)

        return difiles

    def get_rawrsfmri(self):
        """ Get raw functional MRI path for subject """
        return op.join(self.get_rawdata(), 'fMRI')

    def get_rawt1(self):
        """ Get raw structural MRI T1 path for subject """
        return op.join(self.get_rawdata(), 'T1')

    def get_rawt2(self):
        """ Get raw structural MRI T2 path for subject """
        return op.join(self.get_rawdata(), 'T2')

    def get_subj_dir(self):
        return self.subject_workingdir

    def get_raw_diffusion(self):
        """ Get the raw diffusion path for subject """
        if self.diffusion_imaging_model == 'DSI':
            return op.join(self.get_subj_dir(), 'RAWDATA', 'DSI')
        elif self.diffusion_imaging_model == 'DTI':
            return op.join(self.get_subj_dir(), 'RAWDATA', 'DTI')
        elif self.diffusion_imaging_model == 'QBALL':
            return op.join(self.get_subj_dir(), 'RAWDATA', 'QBALL')

    def get_fs(self):
        """ Returns the subject root folder path for freesurfer files """
        return op.join(self.get_subj_dir(), 'FREESURFER')

    def get_stats(self):
        """ Return statistic output path """
        return op.join(self.get_subj_dir(), 'STATS')

    def get_cffdir(self):
        """ Returns path to store connectome file """
        return op.join(self.get_cmp(), 'cff')

    def get_nifti(self):
        """ Returns the subject root folder path for nifti files """
        return op.join(self.get_subj_dir(), 'NIFTI')

    def get_nifti_trafo(self):
        """ Returns the path to the subjects transformation / registration matrices """
        return op.join(self.get_nifti(), 'transformations')

    def get_nifti_bbregister(self):
        """ Returns the path to the subjects transformation / registration matrices, bbregister mode """
        return op.join(self.get_nifti(), 'bbregister')

    def get_diffusion_metadata(self):
        """ Diffusion metadata, i.e. where gradient_table.txt is stored """
        return op.join(self.get_nifti(), 'diffusion_metadata')

    def get_nifti_wm_correction(self):
        """ Returns the path to the subjects wm_correction path """
        return op.join(self.get_nifti(), 'wm_correction')

    def get_cmp(self):
        return op.join(self.get_subj_dir(), 'CMP')

    def get_cmp_rawdiff(self, ):
        return op.join(self.get_cmp(), 'raw_diffusion')

    def get_cmp_rawdiff_reconout(self):
        """ Returns the output path for diffusion reconstruction without prefix"""
        if self.diffusion_imaging_model == 'DSI':
            return op.join(self.get_cmp(), 'raw_diffusion', 'odf_0')
        elif self.diffusion_imaging_model == 'DTI':
            return op.join(self.get_cmp(), 'raw_diffusion', 'dti_0')
        elif self.diffusion_imaging_model == 'QBALL':
            return op.join(self.get_cmp(), 'raw_diffusion', 'qball_0')

    def get_cmp_rawdiff_resampled(self):
        return op.join(self.get_cmp_rawdiff(), '2x2x2')

    def get_cmp_fsout(self):
        return op.join(self.get_cmp(), 'fs_output')

    def get_cmp_fibers(self):
        return op.join(self.get_cmp(), 'fibers')

    def get_cmp_scalars(self):
        return op.join(self.get_cmp(), 'scalars')

    def get_cmp_matrices(self):
        return op.join(self.get_cmp_fibers(), 'matrices')

    def get_cmp_fmri(self):
        return op.join(self.get_cmp(), 'fMRI')

    def get_cmp_tracto_mask(self):
        return op.join(self.get_cmp_fsout(), 'HR')

    def get_cmp_tracto_mask_tob0(self):
        return op.join(self.get_cmp_fsout(), 'HR__registered-TO-b0')

    def get_custom_gradient_table(self):
        """ Returns the absolute path to the custom gradient table
        with optional b-values in the 4th row """
        return self.gradient_table_file

    def get_cmp_gradient_table(self, name):
        """ Return default gradient tables shipped with CMP. These are mainly derived from
        Diffusion Toolkit """
        cmp_path = op.dirname(__file__)
        return op.join(cmp_path, 'data', 'diffusion', 'gradient_tables',
                       name + '.txt')

    def get_dtb_streamline_vecs_file(self, as_text=False):
        """ Returns the odf directions file used for DTB_streamline """
        cmp_path = op.dirname(__file__)
        if as_text:
            return op.join(cmp_path, 'data', 'diffusion', 'odf_directions',
                           '181_vecs.txt')
        else:
            return op.join(cmp_path, 'data', 'diffusion', 'odf_directions',
                           '181_vecs.dat')

    # XXX
    def get_cmp_scalarfields(self):
        """ Returns a list with tuples with the scalar field name and the
        absolute path to its nifti file """

        ret = []

        if self.diffusion_imaging_model == 'DSI':
            # add gfa per default
            ret.append(('gfa', op.join(self.get_cmp_scalars(),
                                       'dsi_gfa.nii.gz')))
            # XXX: add adc per default

        elif self.diffusion_imaging_model == 'DTI':
            # nothing to add yet for DTI
            pass

        return ret

    def get_dtk_dsi_matrix(self):
        """ Returns the DSI matrix from Diffusion Toolkit
        
        The parameters have to be set in the configuration object with keys:
        1. number of gradient directions : 'nr_of_gradient_directions'
        2. number of sampling directions : 'nr_of_sampling_directions'
        
        Example
        -------
        
        confobj.nr_of_gradient_directions = 515
        confobj.nr_of_sampling_directions = 181
        
        Returns matrix including absolute path to DSI_matrix_515x181.dat
        
        """

        grad = self.nr_of_gradient_directions
        samp = self.nr_of_sampling_directions
        fpath = op.join(self.dtk_matrices,
                        "DSI_matrix_%sx%s.dat" % (grad, samp))
        if not op.exists(fpath):
            msg = "DSI matrix does not exists: %s" % fpath
            raise Exception(msg)
        return fpath

    def get_lausanne_atlas(self, name=None):
        """ Return the absolute path to the lausanne parcellation atlas
        for the resolution name """

        cmp_path = op.dirname(__file__)

        provided_atlases = [
            'myatlas_36_rh.gcs', 'myatlasP1_16_rh.gcs', 'myatlasP17_28_rh.gcs',
            'myatlasP29_36_rh.gcs', 'myatlas_60_rh.gcs', 'myatlas_125_rh.gcs',
            'myatlas_250_rh.gcs', 'myatlas_36_lh.gcs', 'myatlasP1_16_lh.gcs',
            'myatlasP17_28_lh.gcs', 'myatlasP29_36_lh.gcs',
            'myatlas_60_lh.gcs', 'myatlas_125_lh.gcs', 'myatlas_250_lh.gcs'
        ]

        if name in provided_atlases:
            return op.join(cmp_path, 'data', 'colortable_and_gcs',
                           'my_atlas_gcs', name)
        else:
            msg = "Atlas %s does not exists" % name
            raise Exception(msg)

    def get_freeview_lut(self, name):
        """ Returns the Look-Up-Table as text file for a given parcellation scheme
        in  a dictionary """

        cmp_path = op.dirname(__file__)
        if name == "NativeFreesurfer":
            return {
                'freesurferaparc':
                op.join(cmp_path, 'data', 'parcellation', 'nativefreesurfer',
                        'freesurferaparc', 'FreeSurferColorLUT_adapted.txt')
            }
        else:
            return ""

    def get_lausanne_parcellation_path(self, parcellationname):

        cmp_path = op.dirname(__file__)

        if self.parcellation_scheme == "Lausanne2008":
            allowed_default_parcel = [
                'resolution83', 'resolution150', 'resolution258',
                'resolution500', 'resolution1015'
            ]
            if parcellationname in allowed_default_parcel:
                return op.join(cmp_path, 'data', 'parcellation',
                               'lausanne2008', parcellationname)
            else:
                msg = "Not a valid default parcellation name for the lausanne2008 parcellation scheme"
                raise Exception(msg)

        else:
            allowed_default_parcel = ['freesurferaparc']
            if parcellationname in allowed_default_parcel:
                return op.join(cmp_path, 'data', 'parcellation',
                               'nativefreesurfer', parcellationname)
            else:
                msg = "Not a valid default parcellation name for the NativeFreesurfer parcellation scheme"
                raise Exception(msg)

    def get_cmp_binary_path(self):
        """ Returns the path to the binary files for the current platform
        and architecture """

        if sys.platform == 'linux2':

            import platform as pf
            if '32' in pf.architecture()[0]:
                return op.join(op.dirname(__file__), "binary", "linux2",
                               "bit32")
            elif '64' in pf.architecture()[0]:
                return op.join(op.dirname(__file__), "binary", "linux2",
                               "bit64")
        else:
            raise ('No binary files compiled for your platform!')

    def get_pipeline_status_file(self):
        """Returns the absolute path of the pipeline status file"""
        return op.join(self.get_subj_dir(), self.pipeline_status_file)

    def init_pipeline_status(self):
        """Create the 'cmp.status'.  The 'cmp.status' file contains information
        about the inputs/outputs of each pipeline stage"""
        status_file = op.join(self.get_subj_dir(), self.pipeline_status_file)
        self.pipeline_status.Pipeline.name = "cmp"
        self.pipeline_status.SaveToFile(status_file)

    def update_pipeline_status(self):
        """Update the pipeline status on disk with the current status in memory"""
        status_file = op.join(self.get_subj_dir(), self.pipeline_status_file)
        self.pipeline_status.SaveToFile(status_file)
示例#5
0
	outputTransform = traits.Either(traits.Bool, File, argstr = "--outputTransform %s")
	outputLandmarksInInputSpace = traits.Either(traits.Bool, File, argstr = "--outputLandmarksInInputSpace %s")
	outputLandmarksInACPCAlignedSpace = traits.Either(traits.Bool, File, argstr = "--outputLandmarksInACPCAlignedSpace %s")
	inputLandmarksPaired = File( exists = "True",argstr = "--inputLandmarksPaired %s")
	outputLandmarksPaired = traits.Either(traits.Bool, File, argstr = "--outputLandmarksPaired %s")
	outputMRML = traits.Either(traits.Bool, File, argstr = "--outputMRML %s")
	outputVerificationScript = traits.Either(traits.Bool, File, argstr = "--outputVerificationScript %s")
	mspQualityLevel = traits.Int( argstr = "--mspQualityLevel %d")
	otsuPercentileThreshold = traits.Float( argstr = "--otsuPercentileThreshold %f")
	acLowerBound = traits.Float( argstr = "--acLowerBound %f")
	cutOutHeadInOutputVolume = traits.Bool( argstr = "--cutOutHeadInOutputVolume ")
	outputUntransformedClippedVolume = traits.Either(traits.Bool, File, argstr = "--outputUntransformedClippedVolume %s")
	rescaleIntensities = traits.Bool( argstr = "--rescaleIntensities ")
	trimRescaledIntensities = traits.Float( argstr = "--trimRescaledIntensities %f")
	rescaleIntensitiesOutputRange = traits.List("traits.Int", sep = ",",argstr = "--rescaleIntensitiesOutputRange %d")
	backgroundFillValueString = traits.Str( argstr = "--BackgroundFillValue %s")
	interpolationMode = traits.Enum("NearestNeighbor","Linear","ResampleInPlace","BSpline","WindowedSinc", argstr = "--interpolationMode %s")
	forceACPoint = traits.List("traits.Float", sep = ",",argstr = "--forceACPoint %f")
	forcePCPoint = traits.List("traits.Float", sep = ",",argstr = "--forcePCPoint %f")
	forceVN4Point = traits.List("traits.Float", sep = ",",argstr = "--forceVN4Point %f")
	forceRPPoint = traits.List("traits.Float", sep = ",",argstr = "--forceRPPoint %f")
	inputLandmarksEMSP = File( exists = "True",argstr = "--inputLandmarksEMSP %s")
	forceHoughEyeDetectorReportFailure = traits.Bool( argstr = "--forceHoughEyeDetectorReportFailure ")
	radiusMPJ = traits.Float( argstr = "--rmpj %f")
	radiusAC = traits.Float( argstr = "--rac %f")
	radiusPC = traits.Float( argstr = "--rpc %f")
	radiusVN4 = traits.Float( argstr = "--rVN4 %f")
	debug = traits.Bool( argstr = "--debug ")
	verbose = traits.Bool( argstr = "--verbose ")
	writeBranded2DImage = traits.Either(traits.Bool, File, argstr = "--writeBranded2DImage %s")
	resultsDir = traits.Either(traits.Bool, File, argstr = "--resultsDir %s")
示例#6
0
class Parameters(t.HasTraits, object):
    """A class to comfortably access some parameters as attributes"""
    name = t.Str("UnnamedFile")

    def __init__(self, dictionary={}):
        super(Parameters, self).__init__()
        self.load_dictionary(dictionary)

    def load_dictionary(self, dictionary):
        for key, value in dictionary.iteritems():
            if isinstance(value, dict):
                value = Parameters(value)
            self.__setattr__(key, value)

    def _get_print_items(self, padding='', max_len=20):
        """Prints only the attributes that are not methods"""
        string = ''
        eon = len([
            par for par in self.__dict__
            if isinstance(self.__dict__[par], Parameters)
        ])
        eoi = len(self.__dict__)
        i = 0
        j = 0
        for item, value in self.__dict__.iteritems():
            if type(item) != types.MethodType:
                if isinstance(value, Parameters):
                    if i == eon - 1:
                        symbol = '└── '
                    else:
                        symbol = '├── '
                    string += '%s%s%s\n' % (padding, symbol, item)
                    i += 1
                    if i == eon:
                        string += value._get_print_items(padding + '    ')
                    else:
                        string += value._get_print_items(padding + '│   ')
                else:
                    if j == eoi - 1:
                        symbol = '└── '
                    else:
                        symbol = '├── '
                    strvalue = str(value)
                    if len(strvalue) > max_len:
                        value = '%s ... %s' % (strvalue[:max_len],
                                               strvalue[-max_len:])
                    string += "%s%s%s = %s\n" % (padding, symbol, item, value)
            j += 1
        return string

    def __repr__(self):
        return self._get_print_items()

    def _get_parameters_dictionary(self):
        par_dict = {}
        for item, value in self.__dict__.iteritems():
            if type(item) != types.MethodType:
                if isinstance(value, Parameters):
                    value = value._get_parameters_dictionary()
                par_dict.__setitem__(item, value)
        return par_dict

    def add_node(self, node_path):
        keys = node_path.split('/')
        current_dict = self.__dict__
        for key in keys:
            if key not in current_dict:
                current_dict[key] = Parameters()
            current_dict = current_dict[key].__dict__
示例#7
0
class PluginInfoBase(traits.HasTraits):
    """abstract base class to create plugins for strokelitude GUI"""
    name = traits.Str('generic strokelitude plugin')

    def __init__(self):
        self.quit_event = multiprocessing.Event()
        self.child = None
        self.server = None

    def get_hastraits_class(self):
        raise NotImplementedError('must be overriden by derived class')

    def shutdown(self):
        self.quit_event.set()
        if self.child is not None:
            print 'joining child...'
            print '  self.child', self.child
            print '  self.child.join', self.child.join
            self.child.join()
            print '...done joining child'
            self.child = None
        if self.server is not None:
            self.server = None  # close

    def startup(self):
        klass_proxy, klass_worker = self.get_hastraits_class()
        if hasattr(self, 'get_worker_table_descriptions'):
            descr_dict = self.get_worker_table_descriptions()
        else:
            descr_dict = {}

        save_data_queues = {}
        for name, description in descr_dict.iteritems():
            save_data_queues[name] = multiprocessing.Queue()
        display_text_queue = multiprocessing.Queue()
        do_hostname = 'localhost'
        do_port = 8112
        if self.child is not None:
            raise ValueError('cannot start a second child')
        if self.server is not None:
            raise ValueError('cannot start a second server')

        self.quit_event.clear()
        oname = 'obj'
        key = random.randint(-sys.maxint, sys.maxint)
        data_queue = multiprocessing.Queue()

        child = multiprocessing.Process(
            target=mainloop,
            args=(klass_proxy, klass_worker, do_hostname, do_port, oname,
                  data_queue, save_data_queues, display_text_queue, key,
                  self.quit_event))
        child.start()  # fork subprocess
        try:
            view_hostname = 'localhost'
            view_port = 8113
            server = remote_traits.ServerObj(view_hostname, view_port, key=key)

            hastraits_proxy = server.get_proxy_hastraits_instance(do_hostname,
                                                                  do_port,
                                                                  oname,
                                                                  key=key)
        except:
            self.quit_event.set()  # close the child process
            raise

        # Keep these asignments delayed -- if the above steps fail, we
        # don't want to set self.child and self.server

        self.child = child
        self.server = server
        return (hastraits_proxy, data_queue, save_data_queues, descr_dict,
                display_text_queue)
示例#8
0
class DataAxis(t.HasTraits):
    name = t.Str()
    units = t.Str()
    scale = t.Float()
    offset = t.Float()
    size = t.Int()
    index_in_array = t.Int()
    low_value = t.Float()
    high_value = t.Float()
    value = t.Range('low_value', 'high_value')
    low_index = t.Int(0)
    high_index = t.Int()
    slice = t.Instance(slice)
    slice_bool = t.Bool(False)

    index = t.Range('low_index', 'high_index')
    axis = t.Array()

    def __init__(self,
                 size,
                 index_in_array,
                 name='',
                 scale=1.,
                 offset=0.,
                 units='undefined',
                 slice_bool=False):
        super(DataAxis, self).__init__()

        self.name = name
        self.units = units
        self.scale = scale
        self.offset = offset
        self.size = size
        self.high_index = self.size - 1
        self.low_index = 0
        self.index = 0
        self.index_in_array = index_in_array
        self.update_axis()

        self.on_trait_change(self.update_axis, ['scale', 'offset', 'size'])
        self.on_trait_change(self.update_value, 'index')
        self.on_trait_change(self.set_index_from_value, 'value')
        self.on_trait_change(self._update_slice, 'slice_bool')
        self.on_trait_change(self.update_index_bounds, 'size')
        self.slice_bool = slice_bool

    def __repr__(self):
        if self.name is not None:
            return self.name + ' index: ' + str(self.index_in_array)

    def update_index_bounds(self):
        self.high_index = self.size - 1

    def update_axis(self):
        self.axis = generate_axis(self.offset, self.scale, self.size)
        self.low_value, self.high_value = self.axis.min(), self.axis.max()


#        self.update_value()

    def _update_slice(self, value):
        if value is True:
            self.slice = slice(None)
        else:
            self.slice = None

    def get_axis_dictionary(self):
        adict = {
            'name': self.name,
            'scale': self.scale,
            'offset': self.offset,
            'size': self.size,
            'units': self.units,
            'index_in_array': self.index_in_array,
            'slice_bool': self.slice_bool
        }
        return adict

    def update_value(self):
        self.value = self.axis[self.index]

    def value2index(self, value):
        """Return the closest index to the given value if between the limits,
        otherwise it will return either the upper or lower limits

        Parameters
        ----------
        value : float

        Returns
        -------
        int
        """
        if value is None:
            return None
        else:
            index = int(round((value - self.offset) / \
            self.scale))
            if self.size > index >= 0:
                return index
            elif index < 0:
                messages.warning("The given value is below the axis limits")
                return 0
            else:
                messages.warning("The given value is above the axis limits")
                return int(self.size - 1)

    def index2value(self, index):
        return self.axis[index]

    def set_index_from_value(self, value):
        self.index = self.value2index(value)
        # If the value is above the limits we must correct the value
        self.value = self.index2value(self.index)

    def calibrate(self, value_tuple, index_tuple, modify_calibration=True):
        scale = (value_tuple[1] - value_tuple[0]) /\
        (index_tuple[1] - index_tuple[0])
        offset = value_tuple[0] - scale * index_tuple[0]
        if modify_calibration is True:
            self.offset = offset
            self.scale = scale
        else:
            return offset, scale

    traits_view = \
    tui.View(
        tui.Group(
            tui.Group(
                tui.Item(name = 'name'),
                tui.Item(name = 'size', style = 'readonly'),
                tui.Item(name = 'index_in_array', style = 'readonly'),
                tui.Item(name = 'index'),
                tui.Item(name = 'value', style = 'readonly'),
                tui.Item(name = 'units'),
                tui.Item(name = 'slice_bool', label = 'slice'),
            show_border = True,),
            tui.Group(
                tui.Item(name = 'scale'),
                tui.Item(name = 'offset'),
            label = 'Calibration',
            show_border = True,),
        label = "Data Axis properties",
        show_border = True,),
    )
示例#9
0
class QuadMeshDecimationInputSpec(CommandLineInputSpec):
    inputSurface = traits.Str(argstr="--inputSurface %s")
    numberOfElements = traits.Int(argstr="--numberOfElements %d")
    topologyChange = traits.Bool(argstr="--topologyChange ")
    outputSurface = traits.Str(argstr="--outputSurface %s")
class itkBinaryImageMorphologyOutputSpec(TraitedSpec):
    outFilename = traits.Str(desc="outFilename", exists=True)
示例#11
0
class itkConstantImageMathInputSpec(CommandLineInputSpec):
    inFilename = File(argstr='%s', desc = "inFilename", exists = True, mandatory = True, position = 0)
    fileMode = traits.Str(argstr='%s', desc = "fileMode", exists = True, mandatory = True, position = 1)
    value = traits.Int(argstr='%s', desc = "value", exists = True, mandatory = True, position = 2)
    operation = traits.String(argstr='%s', desc = "operation", exists = True, mandatory = True, position = 3)
    outFilename = traits.Str(argstr='%s', desc = "outFilename", exists = True, mandatory = True, position = 4)
示例#12
0
class ForwardAnalysis(AbstractAnalysis):
    """
    Forward analysis of scan-activation of place-field potentiation
    """

    label = 'forward analysis'

    min_quality = traits.Str('fair')

    def __init__(self, *args, **traits):
        AbstractAnalysis.__init__(self, *args, **traits)
        self.results['there_is_no_spoon'] = True
        self.finished = True

    def collect_data(self):
        """Iterate across all scan–cell pairs, find scans with unexpectedly high levels
        of cell firing, then compute the predictive power of high scan firing for the
        existence of a subsequent potentiation event
        """
        # self.create_scan_cell_table()
        # self.create_outcome_table()

    def create_scan_cell_table(self, scan_phase='scan'):
        """For every scan–cell pair, compute the relative index of cell firing that
        occurred during the scan and previous cell firing on the track
        """
        scan_table_description = {
            'id': tb.UInt32Col(pos=1),
            'scan_id': tb.UInt16Col(pos=2),
            'rat': tb.UInt16Col(pos=3),
            'day': tb.UInt16Col(pos=4),
            'session': tb.UInt16Col(pos=5),
            'session_start_angle': tb.FloatCol(pos=6),
            'session_end_angle': tb.FloatCol(pos=7),
            'tc': tb.StringCol(itemsize=8, pos=8),
            'type': tb.StringCol(itemsize=4, pos=9),
            'expt_type': tb.StringCol(itemsize=4, pos=10),
            'area': tb.StringCol(itemsize=4, pos=11),
            'subdiv': tb.StringCol(itemsize=4, pos=12),
            'duration': tb.FloatCol(pos=13),
            'magnitude': tb.FloatCol(pos=14),
            'angle': tb.FloatCol(pos=15)
        }

        def add_scan_index_column_descriptors(descr):
            pos = 16
            for name in ScanIndex.AllNames:
                descr[name] = tb.FloatCol(pos=pos)
                pos += 1

        add_scan_index_column_descriptors(scan_table_description)

        data_file = self.get_data_file(mode='a')
        scan_cell_table = create_table(data_file,
                                       '/',
                                       'scan_cell_info',
                                       scan_table_description,
                                       title='Metadata for Scan-Cell Pairs')
        scan_cell_table._v_attrs['scan_phase'] = scan_phase
        row = scan_cell_table.row
        row_id = 0

        scans_table = get_node('/behavior', 'scans')
        sessions_table = get_node('/metadata', 'sessions')
        tetrodes_table = get_node('/metadata', 'tetrodes')

        cornu_ammonis_query = '(area=="CA1")|(area=="CA3")'
        hippocampal_datasets = unique_datasets('/metadata',
                                               'tetrodes',
                                               condn=cornu_ammonis_query)

        quality_place_cells = AND(get_min_quality_criterion(self.min_quality),
                                  PlaceCellCriteria)

        index = ScanIndex(scan_phase=scan_phase)

        for dataset in hippocampal_datasets:
            dataset_query = '(rat==%d)&(day==%d)' % dataset

            hippocampal_tetrodes = unique_values(
                tetrodes_table,
                column='tt',
                condn='(%s)&(%s)' % (dataset_query, cornu_ammonis_query))
            cluster_criteria = AND(
                quality_place_cells,
                get_tetrode_restriction_criterion(hippocampal_tetrodes))

            for maze in get_maze_list(*dataset):
                rds = dataset + (maze, )
                session = SessionData(rds=rds)
                place_cells = session.get_clusters(cluster_criteria)
                session_start_angle = np.median(
                    session.trajectory.alpha_unwrapped[:5])
                session_end_angle = np.median(
                    session.trajectory.alpha_unwrapped[-5:])

                self.out('Computing scan index for %s...' %
                         session.data_group._v_pathname)

                for scan in scans_table.where(session.session_query):
                    self.out.printf('|', color='cyan')

                    for cell in place_cells:
                        cluster = session.cluster_data(cell)

                        tt, cl = parse_cell_name(cluster.name)
                        tetrode = get_unique_row(
                            tetrodes_table, '(rat==%d)&(day==%d)&(tt==%d)' %
                            (rds[0], rds[1], tt))

                        row['id'] = row_id
                        row['scan_id'] = scan['id']
                        row['rat'], row['day'], row['session'] = rds
                        row['session_start_angle'] = session_start_angle
                        row['session_end_angle'] = session_end_angle
                        row['tc'] = cluster.name
                        row['type'] = session.attrs['type']
                        row['expt_type'] = get_unique_row(
                            sessions_table, session.session_query)['expt_type']
                        row['area'] = tetrode['area']
                        row['subdiv'] = tetrode['area'] + tetrode['subdiv'][:1]
                        row['angle'] = session.F_('alpha_unwrapped')(
                            session.T_(scan['start']))
                        row['duration'] = scan['duration']
                        row['magnitude'] = scan['magnitude']

                        for index_name in ScanIndex.AllNames:
                            row[index_name] = index.compute(
                                index_name, session, scan, cluster)

                        self.out.printf('.', color='green')
                        row_id += 1
                        row.append()

                        if row_id % 100 == 0:
                            scan_cell_table.flush()

                self.out.printf('\n')

        scan_cell_table.flush()
        self.out('Finished creating %s.' % scan_cell_table._v_pathname)

    def generate_index_validation_set(self, N=100):
        data_file = self.get_data_file(mode='r')
        scan_cell_table = data_file.root.scan_cell_info
        scan_table = get_node('/behavior', 'scans')
        index = ScanFiringDeviationIndex()

        def get_subdir(name):
            subdir = os.path.join(self.datadir, name)
            if not os.path.isdir(subdir):
                os.makedirs(subdir)
            return subdir

        output_dir = get_subdir('index_validation')
        figure_dir = get_subdir(os.path.join('index_validation', 'figures'))

        spreadsheet = DataSpreadsheet(
            os.path.join(output_dir, 'scan_index_sample.csv'),
            [('sample', 'd'), ('rat', 'd'), ('day', 'd'), ('session', 'd'),
             ('cell', 's'), ('scan_number', 'd'), ('scan_start', 'd'),
             ('surprise', 'f')])
        rec = spreadsheet.get_record()

        sample_ix = np.random.permutation(scan_cell_table.nrows)[:N]
        scan_index = scan_cell_table.col('S')[sample_ix]
        sample_ix = sample_ix[np.argsort(scan_index)]

        plt.ioff()
        figure_files = []
        sample_id = 1

        self.out('Generating sample records and figures...')
        for ix in sample_ix:
            self.out.printf('.')

            row = scan_cell_table[ix]
            rds = row['rat'], row['day'], row['session']
            scan = scan_table[row['scan_id']]

            rec['sample'] = sample_id
            rec['rat'], rec['day'], rec['session'] = rds
            rec['cell'] = row['tc']
            rec['scan_number'] = scan['number']
            rec['scan_start'] = scan['start']
            rec['surprise'] = row['S']
            spreadsheet.write_record(rec)

            session = SessionData.get(rds)
            cluster = session.cluster_data(row['tc'])
            index.compute(session, scan, cluster, plot=True)
            figure_fn = os.path.join(figure_dir,
                                     'distros_%03d.pdf' % sample_id)
            figure_files.append(figure_fn)
            plt.savefig(figure_fn)
            plt.close()

            sample_id += 1

        self.out.printf('\n')
        spreadsheet.close()
        plt.ion()

        def concatenate_distro_figures_into_report():
            pdftk = '/opt/local/bin/pdftk'
            if os.path.exists(pdftk):
                distro_report = os.path.join(output_dir, 'distro_figures.pdf')
                retcode = subprocess.call([pdftk] + figure_files +
                                          ['cat', 'output', distro_report])
                if retcode == 0:
                    self.out('Saved distribution figures to:\n%s' %
                             distro_report)
                else:
                    self.out('Error saving figure report.', error=True)

        concatenate_distro_figures_into_report()

    def create_outcome_table(self,
                             event_table='potentiation',
                             half_windows=HALF_WINDOWS_DEFAULT):
        outcome_table_description = dict(scan_cell_id=tb.UInt32Col(pos=1))
        window_cols = map(lambda h: 'window_%d' % h, half_windows)

        def add_halfwindow_column_descriptors(descr):
            pos = 2
            for col in window_cols:
                descr[col] = tb.BoolCol(pos=pos)
                pos += 1

        add_halfwindow_column_descriptors(outcome_table_description)
        data_file = self.get_data_file(mode='a')
        outcome_table = create_table(data_file,
                                     '/',
                                     'hit_outcome',
                                     outcome_table_description,
                                     title='Place-Field Event (Hit) Outcomes')
        row = outcome_table.row

        scan_cell_table = data_file.root.scan_cell_info
        scans = get_node('/behavior', 'scans')
        potentiation = get_node('/physiology', event_table)
        outcome_table._v_attrs['event_table'] = event_table

        # Adjust hit angle for depotentiation hack, in which event is actually last active traversal
        hit_angle = -360.0  # forward one lap
        if event_table == 'depotentiation':
            hti_angle = 0.0  # same lap

        def precache_sessions():
            [
                SessionData.get(rds, load_clusters=False)
                for rds in unique_sessions(scan_cell_table)
            ]

        precache_sessions()

        @memoize
        def cell_query(session, tc):
            return '(%s)&(tc=="%s")' % (session.session_query, tc)

        def print_test_indicator(result):
            color = result and 'green' or 'red'
            self.out.printf(u'\u25a1', color=color)

        def test_for_event_hit(scan_angle, h, bounds):
            window = tuple(scan_angle + hit_angle + np.array([h, -h]))
            start_before = bounds[0] >= window[1]
            end_after = bounds[1] <= window[0]
            return start_before and end_after

        for pair in scan_cell_table.iterrows():
            self.out.printf('|', color='cyan')

            rds = pair['rat'], pair['day'], pair['session']
            session = SessionData.get(rds, load_clusters=False)
            event_bounds = lambda t: tuple(
                session.F_('alpha_unwrapped')(session.T_(t)))

            scan_angle = pair['angle']
            row['scan_cell_id'] = pair['id']

            for event in potentiation.where(cell_query(session, pair['tc'])):
                self.out.printf('|', color='lightgray')
                bounds = event_bounds(event['tlim'])

                for h, col in zip(half_windows, window_cols):
                    row[col] = test_for_event_hit(scan_angle, h, bounds)
                    print_test_indicator(row[col])

            row.append()
            if pair['id'] % 100 == 0:
                outcome_table.flush()
                self.out.printf(' [flush]\n%d / %d scan-cell pairs\n' %
                                (outcome_table.nrows, scan_cell_table.nrows),
                                color='lightgray')

        self.out.printf('\n')
        self.close_data_file()

    def _find_half_windows(self, outcome_table):
        window_match = re.compile('window_(\d+)')
        h_col_map = {}
        for col in outcome_table.colnames:
            match = re.match(window_match, col)
            if match:
                h_col_map[int(match.groups()[0])] = col
        return h_col_map

    def _roc_array_name(self, name, h):
        return '%s_roc_window_%d' % (name, h)

    def _auc_array_name(self, name):
        return '%s_auc' % name

    def _rat_roc_array_name(self, rat, index_name):
        return 'rat%03d_%s_roc' % (rat, index_name)

    def _column_data(self, dtable, colname, qtable, condn):
        """Retrieve scan-cell-pair data from a column (colname) of a data table
        (dtable) using an optional query filter (condn) based on another
        scan-cell-pair table (qtable).
        """
        data = dtable.col(colname)
        if condn is not None:
            data = data[qtable.getWhereList(condn)]
        return data

    def _get_roc_criteria(self, x, decimation):
        return np.unique(np.r_[x.min(), x[::decimation], x.max()])

    def _roc_curve(self, index, outcome, criteria, test='ge'):
        TPR = np.empty(criteria.size, 'd')
        FPR = np.empty_like(TPR)
        P = np.sum(outcome)
        N = outcome.size - P
        f = getattr(op, test)
        for i, thr in enumerate(criteria):
            call = f(index, thr)
            TP = np.sum(np.logical_and(call, outcome))
            FP = np.sum(np.logical_and(call, np.logical_not(outcome)))
            TPR[i] = TP / P
            FPR[i] = FP / N
        return FPR, TPR

    def _get_roc_data_array(self, index, outcome, criteria, test_op):
        if np.all(outcome) or np.all(np.logical_not(outcome)):
            return np.array([[], []])
        return np.vstack(
            self._roc_curve(index, outcome, criteria, test=test_op))

    def _exclude_marginal_laps(self, do_exclusion, condn, events):
        if do_exclusion:
            if events == 'potentiation':
                query = '(angle<session_start_angle-360)&(angle>session_end_angle+1080)'
            elif events == 'depotentiation':
                query = '(angle<session_start_angle-720)&(angle>session_end_angle+1080)'
            else:
                self.out('Warning: marginal laps undefined for %s events' %
                         events)
                query = ''
            if condn is None:
                condn = query
            elif query:
                condn = '(%s)&(%s)' % (query, condn)
        return condn

    def generate_roc_curves(self,
                            randomize=False,
                            decimation=20,
                            exclude_margin_laps=True,
                            test_operator='ge',
                            condn=None):

        data_file = self.get_data_file(mode='a')
        index_table = data_file.root.scan_cell_info
        outcome_table = data_file.root.hit_outcome
        event_table = outcome_table._v_attrs['event_table']

        h_to_colname = self._find_half_windows(outcome_table)
        h_windows = sorted(h_to_colname.keys())
        self.out('Found half-windows: %s' % str(h_windows))

        condn = self._exclude_marginal_laps(exclude_margin_laps, condn,
                                            event_table)
        if condn is not None:
            self.out('Using scan-cell-pair filter: "%s"' % condn)

        if hasattr(data_file.root, 'roc_curves'):
            data_file.removeNode(data_file.root, 'roc_curves', recursive=True)

        for index_name in ScanIndex.ActiveNames:

            scan_index = self._column_data(index_table, index_name,
                                           index_table, condn)
            self.out('Found %d scan-cell pairs.' % scan_index.size)

            if randomize:
                scan_index = np.random.permutation(scan_index)

            criteria = self._get_roc_criteria(scan_index, decimation)

            for h in h_windows:

                outcome = self._column_data(outcome_table, h_to_colname[h],
                                            index_table, condn)

                arr = create_array(data_file,
                                   '/roc_curves',
                                   self._roc_array_name(index_name, h),
                                   self._get_roc_data_array(
                                       scan_index, outcome, criteria,
                                       test_operator),
                                   title='%s ROC for Half-Window %d' %
                                   (index_name.title(), h),
                                   createparents=True)

                self.out('Saved %s.' % arr._v_pathname)
                data_file.flush()

        attrs = data_file.root.roc_curves._v_attrs
        attrs['randomize'] = randomize
        attrs['decimation'] = decimation
        attrs['exclude_margin_laps'] = exclude_margin_laps
        attrs['test_operator'] = test_operator
        attrs['condn'] = condn
        attrs['event_table'] = outcome_table._v_attrs['event_table']

        self.close_data_file()

    def generate_rat_roc_curves(self,
                                h=15,
                                clear=True,
                                index_name='R',
                                decimation=5,
                                condn=None,
                                randomize=False,
                                exclude_margin_laps=True,
                                test_operator='ge'):
        assert index_name in ScanIndex.ActiveNames, 'invalid scan index: %s' % index_name

        data_file = self.get_data_file(mode='a')
        index_table = data_file.root.scan_cell_info
        outcome_table = data_file.root.hit_outcome
        event_table = outcome_table._v_attrs['event_table']

        h_to_colname = self._find_half_windows(outcome_table)

        def validate_half_window(h):
            if h in h_to_colname:
                self.out('Using half-window %d data ("%s")' %
                         (h, h_to_colname[h]))
            else:
                raise ValueError, 'missing outcome data for half-window %d.' % h

        validate_half_window(h)

        condn = self._exclude_marginal_laps(exclude_margin_laps, condn,
                                            event_table)

        def rat_query(rat):
            query = 'rat==%d' % rat
            if condn is not None:
                query = '(%s)&(%s)' % (query, condn)
            return query

        if hasattr(data_file.root, 'rat_roc_curves') and clear:
            data_file.removeNode(data_file.root,
                                 'rat_roc_curves',
                                 recursive=True)

        rat_list = unique_rats(index_table)
        self.out('Generating ROC curves for %d rats...' % len(rat_list))

        for rat in rat_list:

            query = rat_query(rat)
            scan_index = self._column_data(index_table, index_name,
                                           index_table, query)

            if randomize:
                scan_index = np.random.permutation(scan_index)

            outcome = self._column_data(outcome_table, h_to_colname[h],
                                        index_table, query)
            criteria = self._get_roc_criteria(scan_index, decimation)

            if not np.any(outcome):
                self.out('Skipping rat %d, no events...' % rat)
                continue

            arr = create_array(data_file,
                               '/rat_roc_curves',
                               self._rat_roc_array_name(rat, index_name),
                               self._get_roc_data_array(
                                   scan_index, outcome, criteria,
                                   test_operator),
                               title='%s ROC for Rat %d, Half-Window %d' %
                               (index_name.title(), rat, h),
                               createparents=True)

            self.out('Saved %s.' % arr._v_pathname)
            data_file.flush()

        attrs = data_file.root.rat_roc_curves._v_attrs
        attrs['decimation'] = decimation
        attrs['h_window'] = h
        attrs['condn'] = condn
        attrs['randomize'] = randomize
        attrs['test_operator'] = test_operator
        attrs['event_table'] = outcome_table._v_attrs['event_table']

        self.close_data_file()

    def _make_figure_title(self,
                           index,
                           h,
                           condn,
                           phase,
                           events,
                           test,
                           randomized=False,
                           paren=''):
        title = 'ROC Curves %s: %s Events for %s %s Criterion' % (
            paren and paren + ' ' or '', snake2title(events),
            snake2title(index), dict(ge=">=", gt=">", le="<=", lt="<")[test])
        if randomized:
            title = '[Randomized] ' + title
        if np.iterable(h) and len(h) > 10:
            h_str = '[%s, ..., %s]' % (', '.join(map(str, h[:3])), ', '.join(
                map(str, h[-3:])))
        else:
            h_str = str(h)
        title += '\nHalf-Window = %s' % h_str
        if condn:
            title += '\nScan-Cell Filter: "%s"' % condn
        if phase != 'scan':
            title += '\nScan Phase: %s' % phase.title()
        return title

    def _compute_AUC(self, TPR, FPR, test):
        assert test in ('ge', 'gt', 'le',
                        'lt'), "bad test operation: '%s'" % test
        if test in ('ge', 'gt'):
            return -1 * np.trapz(TPR, FPR)
        elif test in ('le', 'lt'):
            return np.trapz(TPR, FPR)

    def plot_roc_curves(self, ylim=(0.5, 1.0), skinny_sweep_ax=False):
        self.start_logfile('roc_auc')

        data_file = self.get_data_file(mode='a')
        roc_group = data_file.root.roc_curves
        outcome_table = data_file.root.hit_outcome

        scan_phase = data_file.root.scan_cell_info._v_attrs['scan_phase']
        roc_attrs = roc_group._v_attrs
        scan_cell_condn = roc_attrs['condn']
        is_randomized = roc_attrs['randomize']
        test = roc_attrs['test_operator']
        event_table = roc_attrs['event_table']

        h_to_colname = self._find_half_windows(outcome_table)
        h_windows = sorted(h_to_colname.keys())

        self.close_figures()
        plt.ioff()
        if type(self.figure) is not dict:
            self.figure = {}

        fmt = dict(lw=2, ls='-')  #, drawstyle='steps-mid')
        ndfmt = dict(c='0.4', ls='--', lw=1.5, zorder=-1)
        colors = plt.cm.coolwarm(np.linspace(0, 1, len(h_windows)))

        for index_name in ScanIndex.ActiveNames:

            f = self.new_figure('%s_ROC_curves' % index_name,
                                self._make_figure_title(
                                    index_name,
                                    h_windows,
                                    scan_cell_condn,
                                    scan_phase,
                                    event_table,
                                    test,
                                    randomized=is_randomized),
                                figsize=(11, 8))

            ax_roc = f.add_subplot(121)
            if skinny_sweep_ax:
                ax_auc = f.add_subplot(2, 5, 10)
            else:
                ax_auc = f.add_subplot(224)

            AUC = np.empty(len(h_windows), 'd')
            ndline = ax_roc.plot([0, 1], [0, 1], **ndfmt)

            for i, h in enumerate(h_windows):
                FPR, TPR = data_file.getNode(
                    roc_group, self._roc_array_name(index_name, h)).read()
                AUC[i] = self._compute_AUC(TPR, FPR, test)
                ax_roc.plot(FPR,
                            TPR,
                            label=str(h),
                            c=colors[i],
                            zorder=len(h_windows) - i,
                            **fmt)
                self.out('%s index, window %d: AUC = %f' %
                         (snake2title(index_name), h, AUC[i]))

            arr = create_array(
                data_file,
                '/roc_curves',
                self._auc_array_name(index_name),
                AUC,
                title='ROC-AUC Across Half-Windows for %s Index' % index_name)
            self.out('Saved %s.' % arr._v_pathname)

            if len(h_windows) < 11:
                ax_roc.legend(loc='lower right')

            ax_roc.set(xlim=(0, 1), ylim=(0, 1))
            ax_roc.set_ylabel('TPR')
            ax_roc.set_xlabel('FPR')
            ax_roc.axis('scaled')

            chance_line = ax_auc.axhline(0.5, **ndfmt)
            ax_auc.plot(h_windows,
                        AUC,
                        '-',
                        c='steelblue',
                        lw=3,
                        solid_capstyle='round')
            ax_auc.set(xlabel='Half-Window, degrees',
                       ylabel="AUC",
                       xlim=(0, h_windows[-1] + h_windows[0]),
                       ylim=ylim,
                       xticks=h_windows,
                       xticklabels=([h_windows[0]] + [''] *
                                    (len(h_windows) - 2) + [h_windows[-1]]))

        plt.ion()
        plt.show()

        self.close_logfile()
        self.close_data_file()

    def plot_rat_roc_curves(self, index_name='R', ylim=(0.5, 1.0)):

        data_file = self.get_data_file(mode='r')
        roc_group = data_file.root.rat_roc_curves

        scan_phase = data_file.root.scan_cell_info._v_attrs['scan_phase']
        roc_attrs = roc_group._v_attrs
        scan_cell_condn = roc_attrs['condn']
        half_window = roc_attrs['h_window']
        is_randomized = roc_attrs['randomize']
        event_table = roc_attrs['event_table']
        test = roc_attrs['test_operator']

        suffix = is_randomized and 'randomized' or 'stats'
        self.start_logfile('rat_%s_auc_%s' % (index_name, suffix))

        def get_rats_with_roc_curves():
            rat_list = unique_rats(data_file.root.scan_cell_info)
            remove = []
            for rat in rat_list:
                try:
                    data_file.getNode(
                        roc_group, self._rat_roc_array_name(rat, index_name))
                except tb.NoSuchNodeError:
                    remove.append(rat)
            [rat_list.remove(rat) for rat in remove]
            return rat_list

        rat_list = get_rats_with_roc_curves()
        N_rats = len(rat_list)
        if N_rats == 0:
            raise ValueError, 'no matching ROC curves for "%s" index' % index_name
        self.out('Found %d per-rat ROC curves for "%s" index and H = %d.' %
                 (N_rats, index_name, half_window))

        plt.ioff()
        f = self.new_figure('rat_%s_ROC_curves' % index_name,
                            self._make_figure_title(index_name,
                                                    half_window,
                                                    scan_cell_condn,
                                                    scan_phase,
                                                    event_table,
                                                    test,
                                                    randomized=is_randomized,
                                                    paren='(N=%d)' % N_rats),
                            figsize=(11, 8))
        ax_roc = f.add_subplot(121)
        ax_auc = f.add_subplot(224)

        colors = plt.cm.Dark2(np.linspace(0, 1, N_rats))
        ndfmt = dict(c='0.4', ls='--', lw=1.5)
        ndline = ax_roc.plot([0, 1], [0, 1], zorder=-1, **ndfmt)
        fmt = dict(lw=2, ls='-')  #, drawstyle='steps-mid')

        AUC = np.empty(N_rats, 'd')

        for i, rat in enumerate(rat_list):

            FPR, TPR = data_file.getNode(
                roc_group, self._rat_roc_array_name(rat, index_name)).read()
            ax_roc.plot(FPR, TPR, label=str(rat), c=colors[i], **fmt)
            AUC[i] = self._compute_AUC(TPR, FPR, test)
            self.out('Rat %d AUC = %f' % (rat, AUC[i]))

        ax_roc.set(xlim=(0, 1), ylim=(0, 1), xlabel='FPR', ylabel='TPR')
        ax_roc.axis('scaled')

        def plot_sorted_rat_aucs(ax):
            s = np.argsort(AUC)[::-1]
            x = np.arange(1, N_rats + 1)
            ax.plot(x,
                    AUC[s],
                    ls='',
                    marker='o',
                    mec='steelblue',
                    mfc='none',
                    mew=1.5,
                    ms=6,
                    zorder=10)
            ax.axhline(0.5, **ndfmt)
            ax.tick_params(top=False, right=False)
            ax.set_xticks(x)
            ax.set_xticklabels(map(lambda i: str(rat_list[i]), s), rotation=90)
            ax.set(xlabel='Rats, sorted',
                   ylabel="AUC",
                   xlim=(0, N_rats + 1),
                   ylim=ylim)

        plot_sorted_rat_aucs(ax_auc)

        plt.ion()
        plt.show()

        self.out('---')
        self.out('AUC = %f +/- %f' % (AUC.mean(), AUC.std()))
        self.out('T(%d) = %f, p < %e' %
                 ((N_rats - 1, ) + t_one_sample(AUC, 0.5, tails=1)))

        self.close_logfile()
        self.close_data_file()

    def compute_ranksum_statistics(self, randomize=False, condn=None):

        fn = randomize and 'ranksum-randomized' or 'ranksum'
        self.start_logfile(fn)

        data_file = self.get_data_file()
        scan_cell_table = data_file.root.scan_cell_info
        outcome_table = data_file.root.hit_outcome

        h_to_colname = self._find_half_windows(outcome_table)
        h_windows = sorted(h_to_colname.keys())

        for index_name in ScanIndex.ActiveNames:
            scan_index = self._column_data(scan_cell_table, index_name,
                                           scan_cell_table, condn)

            if randomize:
                scan_index = np.random.permutation(scan_index)

            for h in h_windows:
                outcomes = self._column_data(outcome_table, h_to_colname[h],
                                             scan_cell_table, condn)

                negatives = np.logical_not(outcomes)
                positives = outcomes

                U, p = st.mannwhitneyu(scan_index[negatives],
                                       scan_index[positives])

                self.out('%s index, half-window %d: U = %d, p < %f' %
                         (snake2title(index_name), h, U, p))

        self.out('Note p-values are one-sided, multiply by 2 for two-sided.')
        self.close_logfile()
        self.close_data_file()
示例#13
0
class Fit(traits.HasTraits):

    name = traits.Str(desc="name of fit")
    function = traits.Str(desc="function we are fitting with all parameters")
    variablesList = traits.List(Parameter)
    calculatedParametersList = traits.List(CalculatedParameter)
    xs = None  # will be a scipy array
    ys = None  # will be a scipy array
    zs = None  # will be a scipy array
    performFitButton = traits.Button("Perform Fit")
    getInitialParametersButton = traits.Button("Guess Initial Values")
    usePreviousFitValuesButton = traits.Button("Use Previous Fit")
    drawRequestButton = traits.Button("Draw Fit")
    setSizeButton = traits.Button("Set Initial Size")
    chooseVariablesButtons = traits.Button("choose logged variables")
    logLibrarianButton = traits.Button("librarian")
    logLastFitButton = traits.Button("log current fit")
    removeLastFitButton = traits.Button("remove last fit")
    autoFitBool = traits.Bool(
        False,
        desc=
        "Automatically perform this Fit with current settings whenever a new image is loaded"
    )
    autoGuessBool = traits.Bool(
        False,
        desc=
        "Whenever a fit is completed replace the guess values with the calculated values (useful for increasing speed of the next fit)"
    )
    autoDrawBool = traits.Bool(
        False,
        desc=
        "Once a fit is complete update the drawing of the fit or draw the fit for the first time"
    )
    autoSizeBool = traits.Bool(
        False,
        desc=
        "If TOF variable is read from latest XML and is equal to 0.11ms (or time set in Physics) then it will automatically update the physics sizex and sizey with the Sigma x and sigma y from the gaussian fit"
    )
    logBool = traits.Bool(
        False, desc="Log the calculated and fitted values with a timestamp")
    logName = traits.String(
        desc="name of the scan - will be used in the folder name")
    logDirectory = os.path.join("\\\\ursa", "AQOGroupFolder",
                                "Experiment Humphry", "Data", "eagleLogs")
    latestSequence = os.path.join("\\\\ursa", "AQOGroupFolder",
                                  "Experiment Humphry",
                                  "Experiment Control And Software",
                                  "currentSequence", "latestSequence.xml")

    logFile = traits.File(desc="file path of logFile")

    logAnalyserBool = traits.Bool(
        False, desc="only use log analyser script when True")
    logAnalysers = [
    ]  #list containing full paths to each logAnalyser file to run
    logAnalyserDisplayString = traits.String(
        desc=
        "comma separated read only string that is a list of all logAnalyser python scripts to run. Use button to choose files"
    )
    logAnalyserSelectButton = traits.Button("sel. analyser",
                                            image='@icons:function_node',
                                            style="toolbar")
    xmlLogVariables = []
    imageInspectorReference = None  #will be a reference to the image inspector
    fitting = traits.Bool(False)  #true when performing fit
    fitted = traits.Bool(
        False)  #true when current data displayed has been fitted
    fitSubSpace = traits.Bool(
        False)  #true when current data displayed has been fitted
    startX = traits.Int
    startY = traits.Int
    endX = traits.Int
    endY = traits.Int
    fittingStatus = traits.Str()
    fitThread = None
    fitTimeLimit = traits.Float(
        10.0,
        desc=
        "Time limit in seconds for fitting function. Only has an effect when fitTimeLimitBool is True"
    )
    fitTimeLimitBool = traits.Bool(
        True,
        desc=
        "If True then fitting functions will be limited to time limit defined by fitTimeLimit "
    )
    physics = traits.Instance(
        physicsProperties.physicsProperties.PhysicsProperties)
    #status strings
    notFittedForCurrentStatus = "Not Fitted for Current Image"
    fittedForCurrentImageStatus = "Fit Complete for Current Image"
    currentlyFittingStatus = "Currently Fitting..."
    failedFitStatus = "Failed to finish fit. See logger"
    timeExceededStatus = "Fit exceeded user time limit"

    lmfitModel = traits.Instance(
        lmfit.Model
    )  #reference to the lmfit model  must be initialised in subclass
    mostRecentModelResult = None  # updated to the most recent ModelResult object from lmfit when a fit thread is performed

    fitSubSpaceGroup = traitsui.VGroup(
        traitsui.Item("fitSubSpace", label="Fit Sub Space", resizable=True),
        traitsui.VGroup(traitsui.HGroup(
            traitsui.Item("startX", resizable=True),
            traitsui.Item("startY", resizable=True)),
                        traitsui.HGroup(traitsui.Item("endX", resizable=True),
                                        traitsui.Item("endY", resizable=True)),
                        visible_when="fitSubSpace"),
        label="Fit Sub Space",
        show_border=True)

    generalGroup = traitsui.VGroup(traitsui.Item("name",
                                                 label="Fit Name",
                                                 style="readonly",
                                                 resizable=True),
                                   traitsui.Item("function",
                                                 label="Fit Function",
                                                 style="readonly",
                                                 resizable=True),
                                   fitSubSpaceGroup,
                                   label="Fit",
                                   show_border=True)

    variablesGroup = traitsui.VGroup(traitsui.Item(
        "variablesList",
        editor=traitsui.ListEditor(style="custom"),
        show_label=False,
        resizable=True),
                                     show_border=True,
                                     label="parameters")

    derivedGroup = traitsui.VGroup(traitsui.Item(
        "calculatedParametersList",
        editor=traitsui.ListEditor(style="custom"),
        show_label=False,
        resizable=True),
                                   show_border=True,
                                   label="derived values")

    buttons = traitsui.VGroup(
        traitsui.HGroup(
            traitsui.Item("autoFitBool", label="Auto fit?", resizable=True),
            traitsui.Item("performFitButton", show_label=False,
                          resizable=True)),
        traitsui.HGroup(
            traitsui.Item("autoGuessBool", label="Auto guess?",
                          resizable=True),
            traitsui.Item("getInitialParametersButton",
                          show_label=False,
                          resizable=True)),
        traitsui.HGroup(
            traitsui.Item("autoDrawBool", label="Auto draw?", resizable=True),
            traitsui.Item("drawRequestButton",
                          show_label=False,
                          resizable=True)),
        traitsui.HGroup(
            traitsui.Item("autoSizeBool", label="Auto size?", resizable=True),
            traitsui.Item("setSizeButton", show_label=False, resizable=True)),
        traitsui.HGroup(
            traitsui.Item("usePreviousFitValuesButton",
                          show_label=False,
                          resizable=True)))

    logGroup = traitsui.VGroup(traitsui.HGroup(
        traitsui.Item("logBool", resizable=True),
        traitsui.Item("chooseVariablesButtons",
                      show_label=False,
                      resizable=True)),
                               traitsui.HGroup(
                                   traitsui.Item("logName", resizable=True)),
                               traitsui.HGroup(
                                   traitsui.Item("removeLastFitButton",
                                                 show_label=False,
                                                 resizable=True),
                                   traitsui.Item("logLastFitButton",
                                                 show_label=False,
                                                 resizable=True)),
                               traitsui.HGroup(
                                   traitsui.Item("logAnalyserBool",
                                                 label="analyser?",
                                                 resizable=True),
                                   traitsui.Item("logAnalyserDisplayString",
                                                 show_label=False,
                                                 style="readonly",
                                                 resizable=True),
                                   traitsui.Item("logAnalyserSelectButton",
                                                 show_label=False,
                                                 resizable=True)),
                               label="Logging",
                               show_border=True)

    actionsGroup = traitsui.VGroup(traitsui.Item("fittingStatus",
                                                 style="readonly",
                                                 resizable=True),
                                   logGroup,
                                   buttons,
                                   label="Fit Actions",
                                   show_border=True)
    traits_view = traitsui.View(traitsui.VGroup(generalGroup, variablesGroup,
                                                derivedGroup, actionsGroup),
                                kind="subpanel")

    def __init__(self, **traitsDict):
        super(Fit, self).__init__(**traitsDict)
        self.startX = 0
        self.startY = 0
        self.lmfitModel = lmfit.Model(self.fitFunc)

    def _set_xs(self, xs):
        self.xs = xs

    def _set_ys(self, ys):
        self.ys = ys

    def _set_zs(self, zs):
        self.zs = zs

    def _fittingStatus_default(self):
        return self.notFittedForCurrentStatus

    def _getInitialValues(self):
        """returns ordered list of initial values from variables List """
        return [_.initialValue for _ in self.variablesList]

    def _getParameters(self):
        """creates an lmfit parameters object based on the user input in variablesList """
        return lmfit.Parameters(
            {_.name: _.parameter
             for _ in self.variablesList})

    def _getCalculatedValues(self):
        """returns ordered list of fitted values from variables List """
        return [_.calculatedValue for _ in self.variablesList]

    def _intelligentInitialValues(self):
        """If possible we can auto set the initial parameters to intelligent guesses user can always overwrite them """
        self._setInitialValues(self._getIntelligentInitialValues())

    def _get_subSpaceArrays(self):
        """returns the arrays of the selected sub space. If subspace is not
        activated then returns the full arrays"""
        if self.fitSubSpace:
            xs = self.xs[self.startX:self.endX]
            ys = self.ys[self.startY:self.endY]
            logger.info("xs array sliced length %s " % (xs.shape))
            logger.info("ys array sliced length %s  " % (ys.shape))
            zs = self.zs[self.startY:self.endY, self.startX:self.endX]
            logger.info("zs sub space array %s,%s " % (zs.shape))

            return xs, ys, zs
        else:
            return self.xs, self.ys, self.zs

    def _getIntelligentInitialValues(self):
        """If possible we can auto set the initial parameters to intelligent guesses user can always overwrite them """
        logger.debug("Dummy function should not be called directly")
        return
        #in python this should be a pass statement. I.e. user has to overwrite this

    def fitFunc(self, data, *p):
        """Function that we are trying to fit to. """
        logger.error("Dummy function should not be called directly")
        return
        #in python this should be a pass statement. I.e. user has to overwrite this

    def _setCalculatedValues(self, modelFitResult):
        """updates calculated values with calculated argument """
        parametersResult = modelFitResult.params
        for variable in self.variablesList:
            variable.calculatedValue = parametersResult[variable.name].value

    def _setCalculatedValuesErrors(self, modelFitResult):
        """given the covariance matrix returned by scipy optimize fit
        convert this into stdeviation errors for parameters list and updated
        the stdevError attribute of variables"""
        parametersResult = modelFitResult.params
        for variable in self.variablesList:
            variable.stdevError = parametersResult[variable.name].stderr

    def _setInitialValues(self, guesses):
        """updates calculated values with calculated argument """
        c = 0
        for variable in self.variablesList:
            variable.initialValue = guesses[c]
            c += 1

    def deriveCalculatedParameters(self):
        """Wrapper for subclass definition of deriving calculated parameters
        can put more general calls in here"""
        if self.fitted:
            self._deriveCalculatedParameters()

    def _deriveCalculatedParameters(self):
        """Should be implemented by subclass. should update all variables in calculate parameters list"""
        logger.error("Should only be called by subclass")
        return

    def _fit_routine(self):
        """This function performs the fit in an appropriate thread and 
        updates necessary values when the fit has been performed"""
        self.fitting = True
        if self.fitThread and self.fitThread.isAlive():
            logger.warning(
                "Fitting is already running. You should wait till this fit has timed out before a new thread is started...."
            )
            #logger.warning("I will start a new fitting thread but your previous thread may finish at some undetermined time. you probably had bad starting conditions :( !")
            return
        self.fitThread = FitThread()  #new fitting thread
        self.fitThread.fitReference = self
        self.fitThread.isCurrentFitThread = True  # user can create multiple fit threads on a particular fit but only the latest one will have an effect in the GUI
        self.fitThread.start()
        self.fittingStatus = self.currentlyFittingStatus

    def _perform_fit(self):
        """Perform the fit using scipy optimise curve fit.
        We must supply x and y as one argument and zs as anothger. in the form
        xs: 0 1 2 0 1 2 0 
        ys: 0 0 0 1 1 1 2
        zs: 1 5 6 1 9 8 2
        Hence the use of repeat and tile in  positions and unravel for zs
        initially xs,ys is a linspace array and zs is a 2d image array
        """
        if self.xs is None or self.ys is None or self.zs is None:
            logger.warning(
                "attempted to fit data but had no data inside the Fit object. set xs,ys,zs first"
            )
            return ([], [])
        params = self._getParameters()
        if self.fitSubSpace:  #fit only the sub space
            #create xs, ys and zs which are appropriate slices of the arrays
            xs, ys, zs = self._get_subSpaceArrays()
        else:  #fit the whole array of data (slower)
            xs, ys, zs = self.xs, self.ys, self.zs
        positions = scipy.array([
            scipy.tile(xs, len(ys)),
            scipy.repeat(ys, len(xs))
        ])  #for creating data necessary for gauss2D function
        if self.fitTimeLimitBool:
            modelFitResult = self.lmfitModel.fit(scipy.ravel(zs),
                                                 positions=positions,
                                                 params=params,
                                                 iter_cb=self.getFitCallback(
                                                     time.time()))
        else:  #no iter callback
            modelFitResult = self.lmfitModel.fit(scipy.ravel(zs),
                                                 positions=positions,
                                                 params=params)
        return modelFitResult

    def getFitCallback(self, startTime):
        """returns the callback function that is called at every iteration of fit to check if it 
        has been running too long"""
        def fitCallback(params, iter, resid, *args, **kws):
            """check the time and compare to start time """
            if time.time() - startTime > self.fitTimeLimit:
                raise FitException("Fit time exceeded user limit")

        return fitCallback

    def _performFitButton_fired(self):
        self._fit_routine()

    def _getInitialParametersButton_fired(self):
        self._intelligentInitialValues()

    def _drawRequestButton_fired(self):
        """tells the imageInspector to try and draw this fit as an overlay contour plot"""
        self.imageInspectorReference.addFitPlot(self)

    def _setSizeButton_fired(self):
        """use the sigmaX and sigmaY from the current fit to overwrite the 
        inTrapSizeX and inTrapSizeY parameters in the Physics Instance"""
        self.physics.inTrapSizeX = abs(self.sigmax.calculatedValue)
        self.physics.inTrapSizeY = abs(self.sigmay.calculatedValue)

    def _getFitFuncData(self):
        """if data has been fitted, this returns the zs data for the ideal
        fitted function using the calculated paramters"""
        positions = [
            scipy.tile(self.xs, len(self.ys)),
            scipy.repeat(self.ys, len(self.xs))
        ]  #for creating data necessary for gauss2D function
        zsravelled = self.fitFunc(positions, *self._getCalculatedValues())
        return zsravelled.reshape(self.zs.shape)

    def _logAnalyserSelectButton_fired(self):
        """open a fast file editor for selecting many files """
        fileDialog = FileDialog(action="open files")
        fileDialog.open()
        if fileDialog.return_code == pyface.constant.OK:
            self.logAnalysers = fileDialog.paths
            logger.info("selected log analysers: %s " % self.logAnalysers)
        self.logAnalyserDisplayString = str(
            [os.path.split(path)[1] for path in self.logAnalysers])

    def runSingleAnalyser(self, module):
        """runs the logAnalyser module calling the run function and returns the 
        columnNames and values as a list"""
        exec("import logAnalysers.%s as currentAnalyser" % module)
        reload(
            currentAnalyser
        )  #in case it has changed..#could make this only when user requests
        #now the array also contains the raw image as this may be different to zs if you are using a processor
        if hasattr(self.imageInspectorReference, "rawImage"):
            rawImage = self.imageInspectorReference.rawImage
        else:
            rawImage = None
        return currentAnalyser.run([self.xs, self.ys, self.zs, rawImage],
                                   self.physics.variables, self.variablesList,
                                   self.calculatedParametersList)

    def runAnalyser(self):
        """ if logAnalyserBool is true we perform runAnalyser at the end of _log_fit
        runAnalyser checks that logAnalyser exists and is a python script with a valid run()function
        it then performs the run method and passes to the run function:
        -the image data as a numpy array
        -the xml variables dictionary
        -the fitted paramaters
        -the derived values"""
        for logAnalyser in self.logAnalysers:
            if not os.path.isfile(logAnalyser):
                logger.error(
                    "attempted to runAnalyser but could not find the logAnalyser File: %s"
                    % logAnalyser)
                return
        #these will contain the final column names and values
        finalColumns = []
        finalValues = []
        #iterate over each selected logAnalyser get the column names and values and add them to the master lists
        for logAnalyser in self.logAnalysers:
            directory, module = os.path.split(logAnalyser)
            module, ext = os.path.splitext(module)
            if ext != ".py":
                logger.error("file was not a python module. %s" % logAnalyser)
            else:
                columns, values = self.runSingleAnalyser(module)
                finalColumns.extend(columns)
                finalValues.extend(values)
        return finalColumns, finalValues

    def mostRecentModelFitReport(self):
        """returns the lmfit fit report of the most recent 
        lmfit model results object"""
        if self.mostRecentModelResult is not None:
            return lmfit.fit_report(self.mostRecentModelResult) + "\n\n"
        else:
            return "No fit performed"

    def getCalculatedParameters(self):
        """useful for print returns tuple list of calculated parameter name and value """
        return [(_.name, _.value) for _ in self.calculatedParametersList]

    def _log_fit(self):

        if self.logName == "":
            logger.warning("no log file defined. Will not log")
            return
        #generate folders if they don't exist
        logFolder = os.path.join(self.logDirectory, self.logName)
        if not os.path.isdir(logFolder):
            logger.info("creating a new log folder %s" % logFolder)
            os.mkdir(logFolder)

        imagesFolder = os.path.join(logFolder, "images")
        if not os.path.isdir(imagesFolder):
            logger.info("creating a new images Folder %s" % imagesFolder)
            os.mkdir(imagesFolder)

        commentsFile = os.path.join(logFolder, "comments.txt")
        if not os.path.exists(commentsFile):
            logger.info("creating a comments file %s" % commentsFile)
            open(commentsFile,
                 "a+").close()  #create a comments file in every folder!

        firstSequenceCopy = os.path.join(logFolder,
                                         "copyOfInitialSequence.ctr")
        if not os.path.exists(firstSequenceCopy):
            logger.info("creating a copy of the first sequence %s -> %s" %
                        (self.latestSequence, firstSequenceCopy))
            shutil.copy(self.latestSequence, firstSequenceCopy)

        if self.imageInspectorReference.model.imageMode == "process raw image":  #if we are using a processor, save the details of the processor used to the log folder
            processorParamtersFile = os.path.join(logFolder,
                                                  "processorOptions.txt")
            processorPythonScript = os.path.join(logFolder,
                                                 "usedProcessor.py")  #TODO!
            if not os.path.exists(processorParamtersFile):
                with open(processorParamtersFile, "a+") as processorParamsFile:
                    string = str(self.imageInspectorReference.model.
                                 chosenProcessor) + "\n"
                    string += str(self.imageInspectorReference.model.processor.
                                  optionsDict)
                    processorParamsFile.write(string)

        logger.debug("finished all checks on log folder")
        #copy current image
        try:
            shutil.copy(self.imageInspectorReference.selectedFile,
                        imagesFolder)
        except IOError as e:
            logger.error("Could not copy image. Got IOError: %s " % e.message)
        except Exception as e:
            logger.error("Could not copy image. Got %s: %s " %
                         (type(e), e.message))
            raise e
        logger.info("copying current image")
        self.logFile = os.path.join(logFolder, self.logName + ".csv")

        #analyser logic
        if self.logAnalyserBool:  #run the analyser script as requested
            logger.info(
                "log analyser bool enabled... will attempt to run analyser script"
            )
            analyserResult = self.runAnalyser()
            logger.info("analyser result = %s " % list(analyserResult))
            if analyserResult is None:
                analyserColumnNames = []
                analyserValues = []
                #analyser failed. continue as if nothing happened
            else:
                analyserColumnNames, analyserValues = analyserResult
        else:  #no analyser enabled
            analyserColumnNames = []
            analyserValues = []

        if not os.path.exists(self.logFile):
            variables = [_.name for _ in self.variablesList]
            calculated = [_.name for _ in self.calculatedParametersList]
            times = ["datetime", "epoch seconds"]
            info = ["img file name"]
            xmlVariables = self.xmlLogVariables
            columnNames = times + info + variables + calculated + xmlVariables + analyserColumnNames
            with open(
                    self.logFile, 'ab+'
            ) as logFile:  # note use of binary file so that windows doesn't write too many /r
                writer = csv.writer(logFile)
                writer.writerow(columnNames)
        #column names already exist so...
        logger.debug("copying current image")
        variables = [_.calculatedValue for _ in self.variablesList]
        calculated = [_.value for _ in self.calculatedParametersList]
        now = time.time()  #epoch seconds
        timeTuple = time.localtime(now)
        date = time.strftime("%Y-%m-%dT%H:%M:%S", timeTuple)
        times = [date, now]
        info = [self.imageInspectorReference.selectedFile]
        xmlVariables = [
            self.physics.variables[varName] for varName in self.xmlLogVariables
        ]
        data = times + info + variables + calculated + xmlVariables + analyserValues

        with open(self.logFile, 'ab+') as logFile:
            writer = csv.writer(logFile)
            writer.writerow(data)

    def _logLastFitButton_fired(self):
        """logs the fit. User can use this for non automated logging. i.e. log
        particular fits"""
        self._log_fit()

    def _removeLastFitButton_fired(self):
        """removes the last line in the log file """
        logFolder = os.path.join(self.logDirectory, self.logName)
        self.logFile = os.path.join(logFolder, self.logName + ".csv")
        if self.logFile == "":
            logger.warning("no log file defined. Will not log")
            return
        if not os.path.exists(self.logFile):
            logger.error(
                "cant remove a line from a log file that doesn't exist")
        with open(self.logFile, 'r') as logFile:
            lines = logFile.readlines()
        with open(self.logFile, 'wb') as logFile:
            logFile.writelines(lines[:-1])

    def saveLastFit(self):
        """saves result of last fit to a txt/csv file. This can be useful for live analysis
        or for generating sequences based on result of last fit"""
        try:
            with open(
                    self.imageInspectorReference.cameraModel + "-" +
                    self.physics.species + "-" + "lastFit.csv",
                    "wb") as lastFitFile:
                writer = csv.writer(lastFitFile)
                writer.writerow(["time", time.time()])
                for variable in self.variablesList:
                    writer.writerow([variable.name, variable.calculatedValue])
                for variable in self.calculatedParametersList:
                    writer.writerow([variable.name, variable.value])
        except Exception as e:
            logger.error("failed to save last fit to text file. message %s " %
                         e.message)

    def _chooseVariablesButtons_fired(self):
        self.xmlLogVariables = self.chooseVariables()

    def _usePreviousFitValuesButton_fired(self):
        """update the guess initial values with the value from the last fit """
        logger.info(
            "use previous fit values button fired. loading previous initial values"
        )
        self._setInitialValues(self._getCalculatedValues())

    def chooseVariables(self):
        """Opens a dialog asking user to select columns from a data File that has
        been selected. THese are then returned as a string suitable for Y cols input"""
        columns = self.physics.variables.keys()
        columns.sort()
        values = zip(range(0, len(columns)), columns)

        checklist_group = traitsui.Group(
            '10',  # insert vertical space
            traitsui.Label('Select the additional variables you wish to log'),
            traitsui.UItem('columns',
                           style='custom',
                           editor=traitsui.CheckListEditor(values=values,
                                                           cols=6)),
            traitsui.UItem('selectAllButton'))

        traits_view = traitsui.View(checklist_group,
                                    title='CheckListEditor',
                                    buttons=['OK'],
                                    resizable=True,
                                    kind='livemodal')

        col = ColumnEditor(numberOfColumns=len(columns))
        try:
            col.columns = [
                columns.index(varName) for varName in self.xmlLogVariables
            ]
        except Exception as e:
            logger.error(
                "couldn't selected correct variable names. Returning empty selection"
            )
            logger.error("%s " % e.message)
            col.columns = []
        col.edit_traits(view=traits_view)
        logger.debug("value of columns selected = %s ", col.columns)
        logger.debug("value of columns selected = %s ",
                     [columns[i] for i in col.columns])
        return [columns[i] for i in col.columns]

    def _logLibrarianButton_fired(self):
        """opens log librarian for current folder in logName box. """
        logFolder = os.path.join(self.logDirectory, self.logName)
        if not os.path.isdir(logFolder):
            logger.error(
                "cant open librarian on a log that doesn't exist.... Could not find %s"
                % logFolder)
            return
        librarian = plotObjects.logLibrarian.Librarian(logFolder=logFolder)
        librarian.edit_traits()
示例#14
0
class StandardizeImageIntensityInputSpec(CommandLineInputSpec):
    imageFilename = File(argstr='%s', desc = "ImageFilename", exists = True, mandatory = True, position = 0)
    brainLabelImageFilename = File(argstr='%s', desc = "BrainLabelImageFilename", exists = True, mandatory = True, position = 1)
    resultImageFilename = traits.Str(argstr='%s', desc = "ResultImageFilename", exists = True, mandatory = True, position = 2)
    minLabel = traits.Int(argstr='%s', desc = "MinLabel", exists = True, mandatory = True, position = 3)
    maxLabel = traits.Int(argstr='%s', desc = "MaxLabel", exists = True, mandatory = True, position = 4)
class Fit(traits.HasTraits):

    name = traits.Str(desc="name of fit")
    function = traits.Str(desc="function we are fitting with all parameters")
    variablesList = traits.List(FitVariable)
    calculatedParametersList = traits.List(CalculatedParameter)
    xs = None  # will be a scipy array
    ys = None  # will be a scipy array
    zs = None  # will be a scipy array
    performFitButton = traits.Button("Perform Fit")
    getInitialParametersButton = traits.Button("Guess Initial Values")
    drawRequestButton = traits.Button("Draw Fit")
    autoFitBool = traits.Bool(
        False,
        desc=
        "Automatically perform this Fit with current settings whenever a new image is loaded"
    )
    autoGuessBool = traits.Bool(
        False,
        desc=
        "Whenever a fit is completed replace the guess values with the calculated values (useful for increasing speed of the next fit)"
    )
    autoDrawBool = traits.Bool(
        False,
        desc=
        "Once a fit is complete update the drawing of the fit or draw the fit for the first time"
    )
    logBool = traits.Bool(
        False, desc="Log the calculated and fitted values with a timestamp")
    logFile = traits.File(desc="file path of logFile")

    imageInspectorReference = None  #will be a reference to the image inspector
    fitting = traits.Bool(False)  #true when performing fit
    fitted = traits.Bool(
        False)  #true when current data displayed has been fitted
    fitSubSpace = traits.Bool(
        False)  #true when current data displayed has been fitted
    startX = traits.Int
    startY = traits.Int
    endX = traits.Int
    endY = traits.Int
    fittingStatus = traits.Str()
    fitThread = None
    physics = traits.Instance(physicsProperties.PhysicsProperties)
    #status strings
    notFittedForCurrentStatus = "Not Fitted for Current Image"
    fittedForCurrentImageStatus = "Fit Complete for Current Image"
    currentlyFittingStatus = "Currently Fitting..."
    failedFitStatus = "Failed to finish fit. See logger"

    fitSubSpaceGroup = traitsui.VGroup(
        traitsui.Item("fitSubSpace", label="Fit Sub Space"),
        traitsui.VGroup(traitsui.HGroup(traitsui.Item("startX"),
                                        traitsui.Item("startY")),
                        traitsui.HGroup(traitsui.Item("endX"),
                                        traitsui.Item("endY")),
                        visible_when="fitSubSpace"),
        label="Fit Sub Space",
        show_border=True)

    generalGroup = traitsui.VGroup(traitsui.Item("name",
                                                 label="Fit Name",
                                                 style="readonly",
                                                 resizable=True),
                                   traitsui.Item("function",
                                                 label="Fit Function",
                                                 style="readonly",
                                                 resizable=True),
                                   fitSubSpaceGroup,
                                   label="Fit",
                                   show_border=True)

    variablesGroup = traitsui.VGroup(traitsui.Item(
        "variablesList",
        editor=traitsui.ListEditor(style="custom"),
        show_label=False,
        resizable=True),
                                     show_border=True,
                                     label="parameters")

    derivedGroup = traitsui.VGroup(traitsui.Item(
        "calculatedParametersList",
        editor=traitsui.ListEditor(style="custom"),
        show_label=False,
        resizable=True),
                                   show_border=True,
                                   label="derived values")

    buttons = traitsui.VGroup(
        traitsui.HGroup(traitsui.Item("autoFitBool"),
                        traitsui.Item("performFitButton")),
        traitsui.HGroup(traitsui.Item("autoGuessBool"),
                        traitsui.Item("getInitialParametersButton")),
        traitsui.HGroup(traitsui.Item("autoDrawBool"),
                        traitsui.Item("drawRequestButton")))

    logGroup = traitsui.HGroup(traitsui.Item("logBool"),
                               traitsui.Item("logFile",
                                             visible_when="logBool"),
                               label="Logging",
                               show_border=True)

    actionsGroup = traitsui.VGroup(traitsui.Item("fittingStatus",
                                                 style="readonly"),
                                   logGroup,
                                   buttons,
                                   label="Fit Actions",
                                   show_border=True)
    traits_view = traitsui.View(
        traitsui.VGroup(generalGroup, variablesGroup, derivedGroup,
                        actionsGroup))

    def __init__(self, **traitsDict):
        super(Fit, self).__init__(**traitsDict)
        self.startX = 0
        self.startY = 0

    def _set_xs(self, xs):
        self.xs = xs

    def _set_ys(self, ys):
        self.ys = ys

    def _set_zs(self, zs):
        self.zs = zs

    def _fittingStatus_default(self):
        return self.notFittedForCurrentStatus

    def _getInitialValues(self):
        """returns ordered list of initial values from variables List """
        return [_.initialValue for _ in self.variablesList]

    def _getCalculatedValues(self):
        """returns ordered list of initial values from variables List """
        return [_.calculatedValue for _ in self.variablesList]

    def _log_fit(self):
        if self.logFile == "":
            logger.warning("no log file defined. Will not log")
            return
        if not os.path.exists(self.logFile):
            variables = [_.name for _ in self.variablesList]
            calculated = [_.name for _ in self.calculatedParametersList]
            times = ["datetime", "epoch seconds"]
            info = ["img file name"]
            columnNames = times + info + variables + calculated
            with open(self.logFile, 'a+') as logFile:
                writer = csv.writer(logFile)
                writer.writerow(columnNames)
        #column names already exist so...
        variables = [_.calculatedValue for _ in self.variablesList]
        calculated = [_.value for _ in self.calculatedParametersList]
        now = time.time()  #epoch seconds
        timeTuple = time.localtime(now)
        date = time.strftime("%Y-%m-%dT%H:%M:%S", timeTuple)
        times = [date, now]
        info = [self.imageInspectorReference.selectedFile]
        data = times + info + variables + calculated
        with open(self.logFile, 'a+') as logFile:
            writer = csv.writer(logFile)
            writer.writerow(data)

    def _intelligentInitialValues(self):
        """If possible we can auto set the initial parameters to intelligent guesses user can always overwrite them """
        self._setInitialValues(self._getIntelligentInitialValues())

    def _get_subSpaceArrays(self):
        """returns the arrays of the selected sub space. If subspace is not
        activated then returns the full arrays"""
        if self.fitSubSpace:
            xs = self.xs[self.startX:self.endX]
            ys = self.ys[self.startY:self.endY]
            logger.debug("xs array sliced length %s " % (xs.shape))
            logger.debug("ys array sliced length %s  " % (ys.shape))
            zs = self.zs[self.startY:self.endY, self.startX:self.endX]
            print zs
            print zs.shape
            logger.debug("zs sub space array %s,%s " % (zs.shape))

            return xs, ys, zs
        else:
            return self.xs, self.ys, self.zs

    def _getIntelligentInitialValues(self):
        """If possible we can auto set the initial parameters to intelligent guesses user can always overwrite them """
        logger.debug("Dummy function should not be called directly")
        return

    def fitFunc(self, data, *p):
        """Function that we are trying to fit to. """
        logger.error("Dummy function should not be called directly")
        return

    def _setCalculatedValues(self, calculated):
        """updates calculated values with calculated argument """
        c = 0
        for variable in self.variablesList:
            variable.calculatedValue = calculated[c]
            c += 1

    def _setCalculatedValuesErrors(self, covarianceMatrix):
        """given the covariance matrix returned by scipy optimize fit
        convert this into stdeviation errors for parameters list and updated
        the stdevError attribute of variables"""
        logger.debug("covariance matrix -> %s " % covarianceMatrix)
        parameterErrors = scipy.sqrt(scipy.diag(covarianceMatrix))
        logger.debug("parameterErrors  -> %s " % parameterErrors)
        c = 0
        for variable in self.variablesList:
            variable.stdevError = parameterErrors[c]
            c += 1

    def _setInitialValues(self, guesses):
        """updates calculated values with calculated argument """
        c = 0
        for variable in self.variablesList:
            variable.initialValue = guesses[c]
            c += 1

    def deriveCalculatedParameters(self):
        """Wrapper for subclass definition of deriving calculated parameters
        can put more general calls in here"""
        if self.fitted:
            self._deriveCalculatedParameters()

    def _deriveCalculatedParameters(self):
        """Should be implemented by subclass. should update all variables in calculate parameters list"""
        logger.error("Should only be called by subclass")
        return

    def _fit_routine(self):
        """This function performs the fit in an appropriate thread and 
        updates necessary values when the fit has been performed"""
        self.fitting = True
        if self.fitThread and self.fitThread.isAlive():
            logger.warning(
                "Fitting is already running cannot kick off a new fit until it has finished!"
            )
            return
        else:
            self.fitThread = FitThread()
            self.fitThread.fitReference = self
            self.fitThread.start()
            self.fittingStatus = self.currentlyFittingStatus

    def _perform_fit(self):
        """Perform the fit using scipy optimise curve fit.
        We must supply x and y as one argument and zs as anothger. in the form
        xs: 0 1 2 0 1 2 0 
        ys: 0 0 0 1 1 1 2
        zs: 1 5 6 1 9 8 2

        Hence the use of repeat and tile in  positions and unravel for zs
        
        initially xs,ys is a linspace array and zs is a 2d image array
        """
        if self.xs is None or self.ys is None or self.zs is None:
            logger.warning(
                "attempted to fit data but had no data inside the Fit object. set xs,ys,zs first"
            )
            return ([], [])
        p0 = self._getInitialValues()
        if self.fitSubSpace:  #fit only the sub space
            #create xs, ys and zs which are appropriate slices of the arrays
            xs, ys, zs = self._get_subSpaceArrays()
            positions = [scipy.tile(xs, len(ys)),
                         scipy.repeat(ys, len(xs))
                         ]  #for creating data necessary for gauss2D function
            params2D, cov2D = scipy.optimize.curve_fit(self.fitFunc,
                                                       positions,
                                                       scipy.ravel(zs),
                                                       p0=p0)
            chi2 = scipy.sum(
                (scipy.ravel(zs) - self.fitFunc(positions, *params2D))**2 /
                self.fitFunc(positions, *params2D))
            logger.debug("TEMPORARY ::: CHI^2 = %s " % chi2)
        else:  #fit the whole array of data (slower)
            positions = [
                scipy.tile(self.xs, len(self.ys)),
                scipy.repeat(self.ys, len(self.xs))
            ]  #for creating data necessary for gauss2D function
            #note that it is necessary to ravel zs as curve_fit expects a flattened array
            params2D, cov2D = scipy.optimize.curve_fit(self.fitFunc,
                                                       positions,
                                                       scipy.ravel(self.zs),
                                                       p0=p0)

        return params2D, cov2D

    def _performFitButton_fired(self):
        self._fit_routine()

    def _getInitialParametersButton_fired(self):
        self._intelligentInitialValues()

    def _drawRequestButton_fired(self):
        """tells the imageInspector to try and draw this fit as an overlay contour plot"""
        self.imageInspectorReference.addFitPlot(self)

    def _getFitFuncData(self):
        """if data has been fitted, this returns the zs data for the ideal
        fitted function using the calculated paramters"""
        positions = [
            scipy.tile(self.xs, len(self.ys)),
            scipy.repeat(self.ys, len(self.xs))
        ]  #for creating data necessary for gauss2D function
        zsravelled = self.fitFunc(positions, *self._getCalculatedValues())
        return zsravelled.reshape(self.zs.shape)
示例#16
0
class QuadMeshSmoothingInputSpec(CommandLineInputSpec):
    inputSurface = traits.Str( argstr = "----inputSurface %s")
    numberOfIterations = traits.Int( argstr = "--numberOfIterations %d")
    relaxationFactor = traits.Float( argstr = "--relaxationFactor %f")
    delaunayConforming = traits.Bool( argstr = "----delaunayConforming ")
    outputSurface = traits.Str( argstr = "----outputSurface %s")
示例#17
0
class itkBinaryThresholdImageOutputSpec(TraitedSpec):
    outFilename = traits.Str(desc="outFilename", exists=True)
示例#18
0
class CameraUI(traits.HasTraits):
    """Camera settings defines basic camera settings
    """
    camera_control = traits.Instance(Camera, transient = True)
    
    cameras = traits.List([_NO_CAMERAS],transient = True)
    camera = traits.Any(value = _NO_CAMERAS, desc = 'camera serial number', editor = ui.EnumEditor(name = 'cameras'))
    
    search = traits.Button(desc = 'camera search action')

    _is_initialized= traits.Bool(False, transient = True)
    
    play = traits.Button(desc = 'display preview action')
    stop = traits.Button(desc = 'close preview action')
    on_off = traits.Button('On/Off', desc = 'initiate/Uninitiate camera action')

    gain = create_range_feature('gain',desc = 'camera gain',transient = True)
    shutter = create_range_feature('shutter', desc = 'camera exposure time',transient = True)
    format = create_mapped_feature('format',_FORMAT, desc = 'image format',transient = True)
    roi = traits.Instance(ROI,transient = True)
    
    im_shape = traits.Property(depends_on = 'format.value,roi.values')
    im_dtype = traits.Property(depends_on = 'format.value')
    
    capture = traits.Button()
    save_button = traits.Button('Save as...')
    
    message = traits.Str(transient = True)
    
    view = ui.View(ui.Group(ui.HGroup(ui.Item('camera', springy = True),
                           ui.Item('search', show_label = False, springy = True),
                           ui.Item('on_off', show_label = False, springy = True),
                           ui.Item('play', show_label = False, enabled_when = 'is_initialized', springy = True),
                           ui.Item('stop', show_label = False, enabled_when = 'is_initialized', springy = True),
                           ),
                    ui.Group(
                        ui.Item('gain', style = 'custom'),
                        ui.Item('shutter', style = 'custom'),
                        ui.Item('format', style = 'custom'),
                        ui.Item('roi', style = 'custom'),
                        ui.HGroup(ui.Item('capture',show_label = False),
                        ui.Item('save_button',show_label = False)),
                        enabled_when = 'is_initialized',
                        ),
                        ),
                resizable = True,
                statusbar = [ ui.StatusItem( name = 'message')],
                buttons = ['OK'])
    
    #default initialization    
    def __init__(self, **kw):
        super(CameraUI, self).__init__(**kw)
        self.search_cameras()

    def _camera_control_default(self):
        return Camera()

    def _roi_default(self):
        return ROI()
        
    #@display_cls_error 
    def _get_im_shape(self):
        top, left, width, height = self.roi.values
        shape = (height, width)
        try:
            colors = _COLORS[self.format.value] 
            if colors > 1:
                shape += (colors,)
        except KeyError:
            raise NotImplementedError('Unsupported format')  
        return shape
    
    #@display_cls_error    
    def _get_im_dtype(self):
        try:        
            return _DTYPE[self.format.value]
        except KeyError:
            raise NotImplementedError('Unsupported format')        
        
   
    def _search_fired(self):
        self.search_cameras()
        
    #@display_cls_error
    def search_cameras(self):
        """
        Finds cameras if any and selects first from list
        """
        try:
            cameras = get_number_cameras()
        except Exception as e:
            cameras = []
            raise e
        finally:
            if len(cameras) == 0:
                cameras = [_NO_CAMERAS]
            self.cameras = cameras
            self.camera = cameras[0]

    #@display_cls_error
    def _camera_changed(self):
        if self._is_initialized:
            self._is_initialized= False
            self.camera_control.close()
            self.message = 'Camera uninitialized'
    
    #@display_cls_error
    def init_camera(self):
        self._is_initialized= False
        if self.camera != _NO_CAMERAS:
            self.camera_control.init(self.camera)
            self.init_features()
            self._is_initialized= True
            self.message = 'Camera initialized'
            
    #@display_cls_error
    def _on_off_fired(self):
        if self._is_initialized:
            self._is_initialized= False
            self.camera_control.close()
            self.message = 'Camera uninitialized'
        else:
            self.init_camera()
            
    #@display_cls_error
    def init_features(self):
        """
        Initializes all features to values given by the camera
        """
        features = self.camera_control.get_camera_features()
        self._init_single_valued_features(features)
        self._init_roi(features)
    
    #@display_cls_error
    def _init_single_valued_features(self, features):
        """
        Initializes all single valued features to camera values
        """
        for name, id in list(_SINGLE_VALUED_FEATURES.items()):
            feature = getattr(self, name)
            feature.low, feature.high = features[id]['params'][0]
            feature.value = self.camera_control.get_feature(id)[0]
            
    #@display_cls_error
    def _init_roi(self, features):
        for i,name in enumerate(('top','left','width','height')):
            feature = getattr(self.roi, name)
            low, high = features[FEATURE_ROI]['params'][i]
            value = self.camera_control.get_feature(FEATURE_ROI)[i]
            try:
                feature.value = value
            finally:
                feature.low, feature.high = low, high
                       
    @traits.on_trait_change('format.value')
    def _on_format_change(self, object, name, value):
        if self._is_initialized:
            self.camera_control.set_preview_state(STOP_PREVIEW)
            self.camera_control.set_stream_state(STOP_STREAM)
            self.set_feature(FEATURE_PIXEL_FORMAT, [value])
            
    @traits.on_trait_change('gain.value,shutter.value')
    def _single_valued_feature_changed(self, object, name, value):
        if self._is_initialized:
            self.set_feature(object.id, [value])

    #@display_cls_error
    def set_feature(self, id, values, flags = 2):
        self.camera_control.set_feature(id, values, flags = flags)
            
    @traits.on_trait_change('roi.values')
    def a_roi_feature_changed(self, object, name, value):
        if self._is_initialized:
            self.set_feature(FEATURE_ROI, value)
            try:
                self._is_initialized= False
                self.init_features()
            finally:
                self._is_initialized= True
        
    #@display_cls_error                    
    def _play_fired(self):
        self.camera_control.set_preview_state(STOP_PREVIEW)
        self.camera_control.set_stream_state(STOP_STREAM)
        self.camera_control.set_stream_state(START_STREAM)
        self.camera_control.set_preview_state(START_PREVIEW)
        
    #@display_cls_error
    def _stop_fired(self): 
        self.camera_control.set_preview_state(STOP_PREVIEW)
        self.camera_control.set_stream_state(STOP_STREAM)
        self.error = ''
 
    #@display_cls_error
    def _format_changed(self, value):
        self.camera_control.set_preview_state(STOP_PREVIEW)
        self.camera_control.set_stream_state(STOP_STREAM)
        self.camera_control.set_feature(FEATURE_PIXEL_FORMAT, [value],2)
    
    #@display_cls_error
    def _capture_fired(self):
        self.camera_control.set_stream_state(STOP_STREAM)
        self.camera_control.set_stream_state(START_STREAM)
        im = self.capture_image()
        plt.imshow(im)
        plt.show()

    def capture_image(self):
        im = numpy.empty(shape = self.im_shape, dtype = self.im_dtype)
        self.camera_control.get_next_frame(im)
        return im.newbyteorder('>')
        
    def save_image(self, fname):
        """Captures image and saves to format guessed from filename extension"""
        im = self.capture_image()
        base, ext = os.path.splitext(fname)
        if ext == '.npy':
            numpy.save(fname, im)
        else:
            im = toimage(im)
            im.save(fname)

    def _save_button_fired(self):
        f = pyface.FileDialog(action = 'save as') 
                       #wildcard = self.filter)
        if f.open() == pyface.OK: 
            self.save_image(f.path)                 

    def capture_HDR(self):
        pass
                
    def __del__(self):
        try:
            self.camera_control.set_preview_state(STOP_PREVIEW)
            self.camera_control.set_stream_state(STOP_STREAM)
        except:
            pass
class EgertonPanel(t.HasTraits):
    define_background_window = t.Bool(False)
    bg_window_size_variation = t.Button()
    background_substracted_spectrum_name = t.Str('signal')
    extract_background = t.Button()    
    define_signal_window = t.Bool(False)
    signal_window_size_variation = t.Button()
    signal_name = t.Str('signal')
    extract_signal = t.Button()
    view = tu.View(tu.Group(
        tu.Group('define_background_window',
                 tu.Item('bg_window_size_variation', 
                         label = 'window size effect', show_label=False),
                 tu.Item('background_substracted_spectrum_name'),
                 tu.Item('extract_background', show_label=False),
                 ),
        tu.Group('define_signal_window',
                 tu.Item('signal_window_size_variation', 
                         label = 'window size effect', show_label=False),
                 tu.Item('signal_name', show_label=True),
                 tu.Item('extract_signal', show_label=False)),))
                 
    def __init__(self, SI):
        
        self.SI = SI
        
        # Background
        self.bg_span_selector = None
        self.pl = components.PowerLaw()
        self.bg_line = None
        self.bg_cube = None
                
        # Signal
        self.signal_span_selector = None
        self.signal_line = None
        self.signal_map = None
        self.map_ax = None
    
    def store_current_spectrum_bg_parameters(self, *args, **kwards):
        if self.define_background_window is False or \
        self.bg_span_selector.range is None: return
        pars = utils.two_area_powerlaw_estimation(
        self.SI, *self.bg_span_selector.range,only_current_spectrum = True)
        self.pl.r.value = pars['r']
        self.pl.A.value = pars['A']
                     
        if self.define_signal_window is True and \
        self.signal_span_selector.range is not None:
            self.plot_signal_map()
                     
    def _define_background_window_changed(self, old, new):
        if new is True:
            self.bg_span_selector = \
            drawing.widgets.ModifiableSpanSelector(
            self.SI.hse.spectrum_plot.left_ax,
            onselect = self.store_current_spectrum_bg_parameters,
            onmove_callback = self.plot_bg_removed_spectrum)
        elif self.bg_span_selector is not None:
            if self.bg_line is not None:
                self.bg_span_selector.ax.lines.remove(self.bg_line)
                self.bg_line = None
            if self.signal_line is not None:
                self.bg_span_selector.ax.lines.remove(self.signal_line)
                self.signal_line = None
            self.bg_span_selector.turn_off()
            self.bg_span_selector = None
                      
    def _bg_window_size_variation_fired(self):
        if self.define_background_window is False: return
        left = self.bg_span_selector.rect.get_x()
        right = left + self.bg_span_selector.rect.get_width()
        energy_window_dependency(self.SI, left, right, min_width = 10)
        
    def _extract_background_fired(self):
        if self.pl is None: return
        signal = self.SI() - self.pl.function(self.SI.energy_axis)
        i = self.SI.energy2index(self.bg_span_selector.range[1])
        signal[:i] = 0.
        s = Spectrum({'calibration' : {'data_cube' : signal}})
        s.get_calibration_from(self.SI)
        interactive_ns[self.background_substracted_spectrum_name] = s       
        
    def _define_signal_window_changed(self, old, new):
        if new is True:
            self.signal_span_selector = \
            drawing.widgets.ModifiableSpanSelector(
            self.SI.hse.spectrum_plot.left_ax, 
            onselect = self.store_current_spectrum_bg_parameters,
            onmove_callback = self.plot_signal_map)
            self.signal_span_selector.rect.set_color('blue')
        elif self.signal_span_selector is not None:
            self.signal_span_selector.turn_off()
            self.signal_span_selector = None
            
    def plot_bg_removed_spectrum(self, *args, **kwards):
        if self.bg_span_selector.range is None: return
        self.store_current_spectrum_bg_parameters()
        ileft = self.SI.energy2index(self.bg_span_selector.range[0])
        iright = self.SI.energy2index(self.bg_span_selector.range[1])
        ea = self.SI.energy_axis[ileft:]
        if self.bg_line is not None:
            self.bg_span_selector.ax.lines.remove(self.bg_line)
            self.bg_span_selector.ax.lines.remove(self.signal_line)
        self.bg_line, = self.SI.hse.spectrum_plot.left_ax.plot(
        ea, self.pl.function(ea), color = 'black')
        self.signal_line, = self.SI.hse.spectrum_plot.left_ax.plot(
        self.SI.energy_axis[iright:], self.SI()[iright:] - 
        self.pl.function(self.SI.energy_axis[iright:]), color = 'black')
        self.SI.hse.spectrum_plot.left_ax.figure.canvas.draw()

        
    def plot_signal_map(self, *args, **kwargs):
        if self.define_signal_window is True and \
        self.signal_span_selector.range is not None:
            ileft = self.SI.energy2index(self.signal_span_selector.range[0])
            iright = self.SI.energy2index(self.signal_span_selector.range[1])
            signal_sp = self.SI.data_cube[ileft:iright,...].squeeze().copy()
            if self.define_background_window is True:
                pars = utils.two_area_powerlaw_estimation(
                self.SI, *self.bg_span_selector.range, only_current_spectrum = False)
                x = self.SI.energy_axis[ileft:iright, np.newaxis, np.newaxis]
                A = pars['A'][np.newaxis,...]
                r = pars['r'][np.newaxis,...]
                self.bg_sp = (A*x**(-r)).squeeze()
                signal_sp -= self.bg_sp
            self.signal_map = signal_sp.sum(0)
            if self.map_ax is None:
                f = plt.figure()
                self.map_ax = f.add_subplot(111)
                if len(self.signal_map.squeeze().shape) == 2:
                    self.map = self.map_ax.imshow(self.signal_map.T, 
                                                  interpolation = 'nearest')
                else:
                    self.map, = self.map_ax.plot(self.signal_map.squeeze())
            if len(self.signal_map.squeeze().shape) == 2:
                    self.map.set_data(self.signal_map.T)
                    self.map.autoscale()
                    
            else:
                self.map.set_ydata(self.signal_map.squeeze())
            self.map_ax.figure.canvas.draw()
            
    def _extract_signal_fired(self):
        if self.signal_map is None: return
        if len(self.signal_map.squeeze().shape) == 2:
            s = Image(
            {'calibration' : {'data_cube' : self.signal_map.squeeze()}})
            s.xscale = self.SI.xscale
            s.yscale = self.SI.yscale
            s.xunits = self.SI.xunits
            s.yunits = self.SI.yunits
            interactive_ns[self.signal_name] = s
        else:
            s = Spectrum(
            {'calibration' : {'data_cube' : self.signal_map.squeeze()}})
            s.energyscale = self.SI.xscale
            s.energyunits = self.SI.xunits
            interactive_ns[self.signal_name] = s
示例#20
0
class StripePluginInfo(strokelitude_plugin_module.PluginInfoBase):
    name = traits.Str('Closed Loop Stripe Fixation')

    def get_hastraits_class(self):
        return StripeClass, StripeClassWorker
示例#21
0
class Signal(t.HasTraits, MVA):
    data = t.Any()
    axes_manager = t.Instance(AxesManager)
    original_parameters = t.Instance(Parameters)
    mapped_parameters = t.Instance(Parameters)
    physical_property = t.Str()

    def __init__(self, file_data_dict=None, *args, **kw):
        """All data interaction is made through this class or its subclasses


        Parameters:
        -----------
        dictionary : dictionary
           see load_dictionary for the format
        """
        super(Signal, self).__init__()
        self.mapped_parameters = Parameters()
        self.original_parameters = Parameters()
        if type(file_data_dict).__name__ == "dict":
            self.load_dictionary(file_data_dict)
        self._plot = None
        self.mva_results = MVA_Results()
        self._shape_before_unfolding = None
        self._axes_manager_before_unfolding = None

    def load_dictionary(self, file_data_dict):
        """Parameters:
        -----------
        file_data_dict : dictionary
            A dictionary containing at least a 'data' keyword with an array of
            arbitrary dimensions. Additionally the dictionary can contain the
            following keys:
                axes: a dictionary that defines the axes (see the
                    AxesManager class)
                attributes: a dictionary which keywords are stored as
                    attributes of the signal class
                mapped_parameters: a dictionary containing a set of parameters
                    that will be stored as attributes of a Parameters class.
                    For some subclasses some particular parameters might be
                    mandatory.
                original_parameters: a dictionary that will be accesible in the
                    original_parameters attribute of the signal class and that
                    typically contains all the parameters that has been
                    imported from the original data file.

        """
        self.data = file_data_dict['data']
        if 'axes' not in file_data_dict:
            file_data_dict['axes'] = self._get_undefined_axes_list()
        self.axes_manager = AxesManager(file_data_dict['axes'])
        if not 'mapped_parameters' in file_data_dict:
            file_data_dict['mapped_parameters'] = {}
        if not 'original_parameters' in file_data_dict:
            file_data_dict['original_parameters'] = {}
        if 'attributes' in file_data_dict:
            for key, value in file_data_dict['attributes'].iteritems():
                self.__setattr__(key, value)
        self.original_parameters.load_dictionary(
            file_data_dict['original_parameters'])
        self.mapped_parameters.load_dictionary(
            file_data_dict['mapped_parameters'])

    def _get_signal_dict(self):
        dic = {}
        dic['data'] = self.data.copy()
        dic['axes'] = self.axes_manager._get_axes_dicts()
        dic['mapped_parameters'] = \
        self.mapped_parameters._get_parameters_dictionary()
        dic['original_parameters'] = \
        self.original_parameters._get_parameters_dictionary()
        return dic

    def _get_undefined_axes_list(self):
        axes = []
        for i in xrange(len(self.data.shape)):
            axes.append({
                'name': 'undefined',
                'scale': 1.,
                'offset': 0.,
                'size': int(self.data.shape[i]),
                'units': 'undefined',
                'index_in_array': i,
            })
        return axes

    def __call__(self, axes_manager=None):
        if axes_manager is None:
            axes_manager = self.axes_manager
        return self.data.__getitem__(axes_manager._getitem_tuple)

    def _get_hse_1D_explorer(self, *args, **kwargs):
        islice = self.axes_manager._slicing_axes[0].index_in_array
        inslice = self.axes_manager._non_slicing_axes[0].index_in_array
        if islice > inslice:
            return self.data.squeeze()
        else:
            return self.data.squeeze().T

    def _get_hse_2D_explorer(self, *args, **kwargs):
        islice = self.axes_manager._slicing_axes[0].index_in_array
        data = self.data.sum(islice)
        return data

    def _get_hie_explorer(self, *args, **kwargs):
        isslice = [
            self.axes_manager._slicing_axes[0].index_in_array,
            self.axes_manager._slicing_axes[1].index_in_array
        ]
        isslice.sort()
        data = self.data.sum(isslice[1]).sum(isslice[0])
        return data

    def _get_explorer(self, *args, **kwargs):
        nav_dim = self.axes_manager.navigation_dimension
        if self.axes_manager.signal_dimension == 1:
            if nav_dim == 1:
                return self._get_hse_1D_explorer(*args, **kwargs)
            elif nav_dim == 2:
                return self._get_hse_2D_explorer(*args, **kwargs)
            else:
                return None
        if self.axes_manager.signal_dimension == 2:
            if nav_dim == 1 or nav_dim == 2:
                return self._get_hie_explorer(*args, **kwargs)
            else:
                return None
        else:
            return None

    def plot(self, axes_manager=None):
        if self._plot is not None:
            try:
                self._plot.close()
            except:
                # If it was already closed it will raise an exception,
                # but we want to carry on...
                pass

        if axes_manager is None:
            axes_manager = self.axes_manager

        if axes_manager.signal_dimension == 1:
            # Hyperspectrum

            self._plot = mpl_hse.MPL_HyperSpectrum_Explorer()
            self._plot.spectrum_data_function = self.__call__
            self._plot.spectrum_title = self.mapped_parameters.name
            self._plot.xlabel = '%s (%s)' % (
                self.axes_manager._slicing_axes[0].name,
                self.axes_manager._slicing_axes[0].units)
            self._plot.ylabel = 'Intensity'
            self._plot.axes_manager = axes_manager
            self._plot.axis = self.axes_manager._slicing_axes[0].axis

            # Image properties
            if self.axes_manager._non_slicing_axes:
                self._plot.image_data_function = self._get_explorer
                self._plot.image_title = ''
                self._plot.pixel_size = \
                self.axes_manager._non_slicing_axes[0].scale
                self._plot.pixel_units = \
                self.axes_manager._non_slicing_axes[0].units
            self._plot.plot()

        elif axes_manager.signal_dimension == 2:

            # Mike's playground with new plotting toolkits - needs to be a
            # branch.
            """
            if len(self.data.shape)==2:
                from drawing.guiqwt_hie import image_plot_2D
                image_plot_2D(self)

            import drawing.chaco_hie
            self._plot = drawing.chaco_hie.Chaco_HyperImage_Explorer(self)
            self._plot.configure_traits()
            """
            self._plot = mpl_hie.MPL_HyperImage_Explorer()
            self._plot.image_data_function = self.__call__
            self._plot.navigator_data_function = self._get_explorer
            self._plot.axes_manager = axes_manager
            self._plot.plot()

        else:
            messages.warning_exit('Plotting is not supported for this view')

    traits_view = tui.View(
        tui.Item('name'),
        tui.Item('physical_property'),
        tui.Item('units'),
        tui.Item('offset'),
        tui.Item('scale'),
    )

    def plot_residual(self, axes_manager=None):
        """Plot the residual between original data and reconstructed data

        Requires you to have already run PCA or ICA, and to reconstruct data
        using either the pca_build_SI or ica_build_SI methods.
        """

        if hasattr(self, 'residual'):
            self.residual.plot(axes_manager)
        else:
            print "Object does not have any residual information.  Is it a \
reconstruction created using either pca_build_SI or ica_build_SI methods?"

    def save(self, filename, only_view=False, **kwds):
        """Saves the signal in the specified format.

        The function gets the format from the extension. You can use:
            - hdf5 for HDF5
            - nc for NetCDF
            - msa for EMSA/MSA single spectrum saving.
            - bin to produce a raw binary file
            - Many image formats such as png, tiff, jpeg...

        Please note that not all the formats supports saving datasets of
        arbitrary dimensions, e.g. msa only suports 1D data.

        Parameters
        ----------
        filename : str
        msa_format : {'Y', 'XY'}
            'Y' will produce a file without the energy axis. 'XY' will also
            save another column with the energy axis. For compatibility with
            Gatan Digital Micrograph 'Y' is the default.
        only_view : bool
            If True, only the current view will be saved. Otherwise the full
            dataset is saved. Please note that not all the formats support this
            option at the moment.
        """
        io.save(filename, self, **kwds)

    def _replot(self):
        if self._plot is not None:
            if self._plot.is_active() is True:
                self.plot()

    def get_dimensions_from_data(self):
        """Get the dimension parameters from the data_cube. Useful when the
        data_cube was externally modified, or when the SI was not loaded from
        a file
        """
        dc = self.data
        for axis in self.axes_manager.axes:
            axis.size = int(dc.shape[axis.index_in_array])
            print("%s size: %i" % (axis.name, dc.shape[axis.index_in_array]))
        self._replot()

    def crop_in_pixels(self, axis, i1=None, i2=None):
        """Crops the data in a given axis. The range is given in pixels
        axis : int
        i1 : int
            Start index
        i2 : int
            End index

        See also:
        ---------
        crop_in_units
        """
        axis = self._get_positive_axis_index_index(axis)
        if i1 is not None:
            new_offset = self.axes_manager.axes[axis].axis[i1]
        # We take a copy to guarantee the continuity of the data
        self.data = self.data[(slice(None), ) * axis +
                              (slice(i1, i2), Ellipsis)].copy()

        if i1 is not None:
            self.axes_manager.axes[axis].offset = new_offset
        self.get_dimensions_from_data()

    def crop_in_units(self, axis, x1=None, x2=None):
        """Crops the data in a given axis. The range is given in the units of
        the axis

        axis : int
        i1 : int
            Start index
        i2 : int
            End index

        See also:
        ---------
        crop_in_pixels

        """
        i1 = self.axes_manager.axes[axis].value2index(x1)
        i2 = self.axes_manager.axes[axis].value2index(x2)
        self.crop_in_pixels(axis, i1, i2)

    def roll_xy(self, n_x, n_y=1):
        """Roll over the x axis n_x positions and n_y positions the former rows

        This method has the purpose of "fixing" a bug in the acquisition of the
        Orsay's microscopes and probably it does not have general interest

        Parameters
        ----------
        n_x : int
        n_y : int

        Note: Useful to correct the SI column storing bug in Marcel's
        acquisition routines.
        """
        self.data = np.roll(self.data, n_x, 0)
        self.data[:n_x, ...] = np.roll(self.data[:n_x, ...], n_y, 1)
        self._replot()

    # TODO: After using this function the plotting does not work
    def swap_axis(self, axis1, axis2):
        """Swaps the axes

        Parameters
        ----------
        axis1 : positive int
        axis2 : positive int
        """
        self.data = self.data.swapaxes(axis1, axis2)
        c1 = self.axes_manager.axes[axis1]
        c2 = self.axes_manager.axes[axis2]
        c1.index_in_array, c2.index_in_array =  \
            c2.index_in_array, c1.index_in_array
        self.axes_manager.axes[axis1] = c2
        self.axes_manager.axes[axis2] = c1
        self.axes_manager.set_signal_dimension()
        self._replot()

    def rebin(self, new_shape):
        """
        Rebins the data to the new shape

        Parameters
        ----------
        new_shape: tuple of ints
            The new shape must be a divisor of the original shape
        """
        factors = np.array(self.data.shape) / np.array(new_shape)
        self.data = utils.rebin(self.data, new_shape)
        for axis in self.axes_manager.axes:
            axis.scale *= factors[axis.index_in_array]
        self.get_dimensions_from_data()

    def split_in(self, axis, number_of_parts=None, steps=None):
        """Splits the data

        The split can be defined either by the `number_of_parts` or by the
        `steps` size.

        Parameters
        ----------
        number_of_parts : int or None
            Number of parts in which the SI will be splitted
        steps : int or None
            Size of the splitted parts
        axis : int
            The splitting axis

        Return
        ------
        tuple with the splitted signals
        """
        axis = self._get_positive_axis_index_index(axis)
        if number_of_parts is None and steps is None:
            if not self._splitting_steps:
                messages.warning_exit(
                    "Please provide either number_of_parts or a steps list")
            else:
                steps = self._splitting_steps
                print "Splitting in ", steps
        elif number_of_parts is not None and steps is not None:
            print "Using the given steps list. number_of_parts dimissed"
        splitted = []
        shape = self.data.shape

        if steps is None:
            rounded = (shape[axis] - (shape[axis] % number_of_parts))
            step = rounded / number_of_parts
            cut_node = range(0, rounded + step, step)
        else:
            cut_node = np.array([0] + steps).cumsum()
        for i in xrange(len(cut_node) - 1):
            data = self.data[(slice(None), ) * axis +
                             (slice(cut_node[i], cut_node[i + 1]), Ellipsis)]
            s = Signal({'data': data})
            # TODO: When copying plotting does not work
            #            s.axes = copy.deepcopy(self.axes_manager)
            s.get_dimensions_from_data()
            splitted.append(s)
        return splitted

    def unfold_if_multidim(self):
        """Unfold the datacube if it is >2D

        Returns
        -------

        Boolean. True if the data was unfolded by the function.
        """
        if len(self.axes_manager.axes) > 2:
            print "Automatically unfolding the data"
            self.unfold()
            return True
        else:
            return False

    def _unfold(self, steady_axes, unfolded_axis):
        """Modify the shape of the data by specifying the axes the axes which
        dimension do not change and the axis over which the remaining axes will
        be unfolded

        Parameters
        ----------
        steady_axes : list
            The indexes of the axes which dimensions do not change
        unfolded_axis : int
            The index of the axis over which all the rest of the axes (except
            the steady axes) will be unfolded

        See also
        --------
        fold
        """

        # It doesn't make sense unfolding when dim < 3
        if len(self.data.squeeze().shape) < 3:
            return False

        # We need to store the original shape and coordinates to be used by
        # the fold function only if it has not been already stored by a
        # previous unfold
        if self._shape_before_unfolding is None:
            self._shape_before_unfolding = self.data.shape
            self._axes_manager_before_unfolding = self.axes_manager

        new_shape = [1] * len(self.data.shape)
        for index in steady_axes:
            new_shape[index] = self.data.shape[index]
        new_shape[unfolded_axis] = -1
        self.data = self.data.reshape(new_shape)
        self.axes_manager = self.axes_manager.deepcopy()
        i = 0
        uname = ''
        uunits = ''
        to_remove = []
        for axis, dim in zip(self.axes_manager.axes, new_shape):
            if dim == 1:
                uname += ',' + axis.name
                uunits = ',' + axis.units
                to_remove.append(axis)
            else:
                axis.index_in_array = i
                i += 1
        self.axes_manager.axes[unfolded_axis].name += uname
        self.axes_manager.axes[unfolded_axis].units += uunits
        self.axes_manager.axes[unfolded_axis].size = \
                                                self.data.shape[unfolded_axis]
        for axis in to_remove:
            self.axes_manager.axes.remove(axis)

        self.data = self.data.squeeze()
        self._replot()

    def unfold(self):
        """Modifies the shape of the data by unfolding the signal and
        navigation dimensions separaterly

        """
        self.unfold_navigation_space()
        self.unfold_signal_space()

    def unfold_navigation_space(self):
        """Modify the shape of the data to obtain a navigation space of
        dimension 1
        """

        if self.axes_manager.navigation_dimension < 2:
            messages.information('Nothing done, the navigation dimension was '
                                 'already 1')
            return False
        steady_axes = [
            axis.index_in_array for axis in self.axes_manager._slicing_axes
        ]
        unfolded_axis = self.axes_manager._non_slicing_axes[-1].index_in_array
        self._unfold(steady_axes, unfolded_axis)

    def unfold_signal_space(self):
        """Modify the shape of the data to obtain a signal space of
        dimension 1
        """
        if self.axes_manager.signal_dimension < 2:
            messages.information('Nothing done, the signal dimension was '
                                 'already 1')
            return False
        steady_axes = [
            axis.index_in_array for axis in self.axes_manager._non_slicing_axes
        ]
        unfolded_axis = self.axes_manager._slicing_axes[-1].index_in_array
        self._unfold(steady_axes, unfolded_axis)

    def fold(self):
        """If the signal was previously unfolded, folds it back"""
        if self._shape_before_unfolding is not None:
            self.data = self.data.reshape(self._shape_before_unfolding)
            self.axes_manager = self._axes_manager_before_unfolding
            self._shape_before_unfolding = None
            self._axes_manager_before_unfolding = None
            self._replot()

    def _get_positive_axis_index_index(self, axis):
        if axis < 0:
            axis = len(self.data.shape) + axis
        return axis

    def iterate_axis(self, axis=-1):
        # We make a copy to guarantee that the data in contiguous, otherwise
        # it will not return a view of the data
        self.data = self.data.copy()
        axis = self._get_positive_axis_index_index(axis)
        unfolded_axis = axis - 1
        new_shape = [1] * len(self.data.shape)
        new_shape[axis] = self.data.shape[axis]
        new_shape[unfolded_axis] = -1
        # Warning! if the data is not contigous it will make a copy!!
        data = self.data.reshape(new_shape)
        for i in xrange(data.shape[unfolded_axis]):
            getitem = [0] * len(data.shape)
            getitem[axis] = slice(None)
            getitem[unfolded_axis] = i
            yield (data[getitem])

    def sum(self, axis, return_signal=False):
        """Sum the data over the specify axis

        Parameters
        ----------
        axis : int
            The axis over which the operation will be performed
        return_signal : bool
            If False the operation will be performed on the current object. If
            True, the current object will not be modified and the operation
             will be performed in a new signal object that will be returned.

        Returns
        -------
        Depending on the value of the return_signal keyword, nothing or a
        signal instance

        See also
        --------
        sum_in_mask, mean

        Usage
        -----
        >>> import numpy as np
        >>> s = Signal({'data' : np.random.random((64,64,1024))})
        >>> s.data.shape
        (64,64,1024)
        >>> s.sum(-1)
        >>> s.data.shape
        (64,64)
        # If we just want to plot the result of the operation
        s.sum(-1, True).plot()
        """
        if return_signal is True:
            s = self.deepcopy()
        else:
            s = self
        s.data = s.data.sum(axis)
        s.axes_manager.axes.remove(s.axes_manager.axes[axis])
        for _axis in s.axes_manager.axes:
            if _axis.index_in_array > axis:
                _axis.index_in_array -= 1
        s.axes_manager.set_signal_dimension()
        if return_signal is True:
            return s

    def mean(self, axis, return_signal=False):
        """Average the data over the specify axis

        Parameters
        ----------
        axis : int
            The axis over which the operation will be performed
        return_signal : bool
            If False the operation will be performed on the current object. If
            True, the current object will not be modified and the operation
            will be performed in a new signal object that will be returned.

        Returns
        -------
        Depending on the value of the return_signal keyword, nothing or a
        signal instance

        See also
        --------
        sum_in_mask, mean

        Usage
        -----
        >>> import numpy as np
        >>> s = Signal({'data' : np.random.random((64,64,1024))})
        >>> s.data.shape
        (64,64,1024)
        >>> s.mean(-1)
        >>> s.data.shape
        (64,64)
        # If we just want to plot the result of the operation
        s.mean(-1, True).plot()
        """
        if return_signal is True:
            s = self.deepcopy()
        else:
            s = self
        s.data = s.data.mean(axis)
        s.axes_manager.axes.remove(s.axes_manager.axes[axis])
        for _axis in s.axes_manager.axes:
            if _axis.index_in_array > axis:
                _axis.index_in_array -= 1
        s.axes_manager.set_signal_dimension()
        if return_signal is True:
            return s

    def copy(self):
        return (copy.copy(self))

    def deepcopy(self):
        return (copy.deepcopy(self))

#    def sum_in_mask(self, mask):
#        """Returns the result of summing all the spectra in the mask.
#
#        Parameters
#        ----------
#        mask : boolean numpy array
#
#        Returns
#        -------
#        Spectrum
#        """
#        dc = self.data_cube.copy()
#        mask3D = mask.reshape([1,] + list(mask.shape)) * np.ones(dc.shape)
#        dc = (mask3D*dc).sum(1).sum(1) / mask.sum()
#        s = Spectrum()
#        s.data_cube = dc.reshape((-1,1,1))
#        s.get_dimensions_from_cube()
#        utils.copy_energy_calibration(self,s)
#        return s
#
#    def mean(self, axis):
#        """Average the SI over the given axis
#
#        Parameters
#        ----------
#        axis : int
#        """
#        dc = self.data_cube
#        dc = dc.mean(axis)
#        dc = dc.reshape(list(dc.shape) + [1,])
#        self.data_cube = dc
#        self.get_dimensions_from_cube()
#
#    def roll(self, axis = 2, shift = 1):
#        """Roll the SI. see numpy.roll
#
#        Parameters
#        ----------
#        axis : int
#        shift : int
#        """
#        self.data_cube = np.roll(self.data_cube, shift, axis)
#        self._replot()
#

#
#    def get_calibration_from(self, s):
#        """Copy the calibration from another Spectrum instance
#        Parameters
#        ----------
#        s : spectrum instance
#        """
#        utils.copy_energy_calibration(s, self)
#
#    def estimate_variance(self, dc = None, gaussian_noise_var = None):
#        """Variance estimation supposing Poissonian noise
#
#        Parameters
#        ----------
#        dc : None or numpy array
#            If None the SI is used to estimate its variance. Otherwise, the
#            provided array will be used.
#        Note
#        ----
#        The gain_factor and gain_offset from the aquisition parameters are used
#        """
#        print "Variace estimation using the following values:"
#        print "Gain factor = ", self.acquisition_parameters.gain_factor
#        print "Gain offset = ", self.acquisition_parameters.gain_offset
#        if dc is None:
#            dc = self.data_cube
#        gain_factor = self.acquisition_parameters.gain_factor
#        gain_offset = self.acquisition_parameters.gain_offset
#        self.variance = dc*gain_factor + gain_offset
#        if self.variance.min() < 0:
#            if gain_offset == 0 and gaussian_noise_var is None:
#                print "The variance estimation results in negative values"
#                print "Maybe the gain_offset is wrong?"
#                self.variance = None
#                return
#            elif gaussian_noise_var is None:
#                print "Clipping the variance to the gain_offset value"
#                self.variance = np.clip(self.variance, np.abs(gain_offset),
#                np.Inf)
#            else:
#                print "Clipping the variance to the gaussian_noise_var"
#                self.variance = np.clip(self.variance, gaussian_noise_var,
#                np.Inf)
#
#    def calibrate(self, lcE = 642.6, rcE = 849.7, lc = 161.9, rc = 1137.6,
#    modify_calibration = True):
#        dispersion = (rcE - lcE) / (rc - lc)
#        origin = lcE - dispersion * lc
#        print "Energy step = ", dispersion
#        print "Energy origin = ", origin
#        if modify_calibration is True:
#            self.set_new_calibration(origin, dispersion)
#        return origin, dispersion
#

    def _correct_navigation_mask_when_unfolded(
        self,
        navigation_mask=None,
    ):
        #if 'unfolded' in self.history:
        if navigation_mask is not None:
            navigation_mask = navigation_mask.reshape((-1, ))
        return navigation_mask