Esempio n. 1
0
def plot_contrast_matrix(contrast_def, design_matrix, colorbar=False, ax=None):
    """Creates plot for contrast definition.

    Parameters
    ----------
    contrast_def : str or array of shape (n_col) or list of (string or
                   array of shape (n_col))
        where ``n_col`` is the number of columns of the design matrix,
        (one array per run). If only one array is provided when there
        are several runs, it will be assumed that the same contrast is
        desired for all runs. The string can be a formula compatible with
        the linear constraint of the Patsy library. Basically one can use
        the name of the conditions as they appear in the design matrix of
        the fitted model combined with operators /*+- and numbers.
        Please checks the patsy documentation for formula examples:
        http://patsy.readthedocs.io/en/latest/API-reference.html#patsy.DesignInfo.linear_constraint

    design_matrix: pandas DataFrame

    colorbar: Boolean, optional (default False)
        Include a colorbar in the contrast matrix plot.

    ax: matplotlib Axes object, optional (default None)
        Directory where plotted figures will be stored.

    Returns
    -------
    Plot Axes object
    """

    design_column_names = design_matrix.columns.tolist()
    if isinstance(contrast_def, str):
        di = DesignInfo(design_column_names)
        contrast_def = di.linear_constraint(contrast_def).coefs

    if ax is None:
        plt.figure(figsize=(8, 4))
        ax = plt.gca()

    maxval = np.max(np.abs(contrast_def))

    con_mx = np.asmatrix(contrast_def)
    mat = ax.matshow(con_mx, aspect='equal', extent=[0, con_mx.shape[1],
                     0, con_mx.shape[0]], cmap='gray', vmin=-maxval,
                     vmax=maxval)
    ax.set_label('conditions')
    ax.set_ylabel('')
    ax.set_yticklabels(['' for x in ax.get_yticklabels()])

    # Shift ticks to be at 0.5, 1.5, etc
    ax.xaxis.set(ticks=np.arange(1.0, len(design_column_names) + 1.0),
                 ticklabels=design_column_names)
    ax.set_xticklabels(design_column_names, rotation=90, ha='right')

    if colorbar:
        plt.colorbar(mat, fraction=0.025, pad=0.04)

    plt.tight_layout()

    return ax
Esempio n. 2
0
def _get_contrast(second_level_contrast, design_matrix):
    """ Check and return contrast when testing one contrast at the time """
    if isinstance(second_level_contrast, str):
        if second_level_contrast in design_matrix.columns.tolist():
            contrast = second_level_contrast
        else:
            raise ValueError('"' + second_level_contrast + '" is not a valid' +
                             ' contrast name')
    else:
        # Check contrast definition
        if second_level_contrast is None:
            if design_matrix.shape[1] == 1:
                second_level_contrast = np.ones([1])
            else:
                raise ValueError('No second-level contrast is specified.')
        elif (np.nonzero(second_level_contrast)[0]).size != 1:
            raise ValueError('second_level_contrast must be '
                             'a list of 0s and 1s')
        if isinstance(second_level_contrast, np.ndarray):
            con_val = np.asarray(second_level_contrast, dtype=bool)
        else:
            design_info = DesignInfo(design_matrix.columns.tolist())
            constraint = design_info.linear_constraint(second_level_contrast)
            con_val = np.asarray(constraint.coefs, dtype=bool).ravel()
        contrast = np.asarray(design_matrix.columns.tolist())[con_val][0]
    return contrast
Esempio n. 3
0
def compute_rfx_contrast(imgs, design_matrix, contrast_def, mask=None, noise_model='ols', stat_type='t', output_type='z_score'):

    design_info = DesignInfo(design_matrix.columns.tolist())
    if isinstance(imgs, list):
        Y = np.stack([i.get_data() for i in imgs]).reshape(len(imgs), -1)        
    elif isinstance(imgs, np.ndarray):
        Y = imgs
    else:
        raise ValueError(f"Unknown format for Y ({type(imgs)}).")

    X = design_matrix.values
    labels, results = run_glm(Y, X, noise_model=noise_model)

    if isinstance(contrast_def, (np.ndarray, str)):
        con_vals = [contrast_def]
    elif isinstance(contrast_def, (list, tuple)):
        con_vals = contrast_def
    else:
        raise ValueError('contrast_def must be an array or str or list of'
                         ' (array or str)')

    for cidx, con in enumerate(con_vals):
        if not isinstance(con, np.ndarray):
            con_vals[cidx] = design_info.linear_constraint(con).coefs

    contrast = compute_contrast(labels, results, con_vals, stat_type)

    values = getattr(contrast, output_type)()
    if isinstance(imgs, list):
        values = nib.Nifti1Image(values.reshape(imgs[0].shape), affine=imgs[0].affine)

    return values
Esempio n. 4
0
def _get_con_val(second_level_contrast, design_matrix):
    """ Check the contrast and return con_val when testing one contrast or more
    """
    if second_level_contrast is None:
        if design_matrix.shape[1] == 1:
            second_level_contrast = np.ones([1])
        else:
            raise ValueError('No second-level contrast is specified.')
    if isinstance(second_level_contrast, np.ndarray):
        con_val = second_level_contrast
        if np.all(con_val == 0):
            raise ValueError('Contrast is null')
    else:
        design_info = DesignInfo(design_matrix.columns.tolist())
        constraint = design_info.linear_constraint(second_level_contrast)
        con_val = constraint.coefs
    return con_val
Esempio n. 5
0
    def compute_fxe_contrast(self, contrast_def, stat_type='t', run=None, output_type='z_score'):
        """ Computes a fixed effect across multiple runs. """
        
        self.logger.info(f"Computing contrast: {contrast_def} for task {self.task} ...")
        if self.glm is None:
            raise ValueError("GLM has not been run yet!")

        if run is None:
            results = self.glm['results']
            labels = self.glm['labels']
            dms = self.glm['dms']
            design_info = DesignInfo(dms[0].columns.tolist())
        else:
            results = self.glm['results'][run]
            labels = self.glm['labels'][run]
            dms = self.glm['dms'][run]
            design_info = DesignInfo(dms.columns.tolist())

        if isinstance(contrast_def, (np.ndarray, str)):
            con_vals = [contrast_def]
        elif isinstance(contrast_def, (list, tuple)):
            con_vals = contrast_def
        else:
            raise ValueError('contrast_def must be an array or str or list of'
                             ' (array or str)')

        for cidx, con in enumerate(con_vals):
            if not isinstance(con, np.ndarray):
                con_vals[cidx] = design_info.linear_constraint(con).coefs

        if run is None:
            contrast = _fixed_effect_contrast(labels, results, con_vals, stat_type)
        else:
            contrast = compute_contrast(labels, results, con_vals, stat_type)

        values = getattr(contrast, output_type)()
        if self.mask is not None:
            return masking.unmask(values, self.mask)
        else:
            return values
Esempio n. 6
0
    def compute_contrast(self,
                         second_level_contrast=None,
                         first_level_contrast=None,
                         second_level_stat_type=None,
                         output_type='z_score'):
        """Generate different outputs corresponding to
        the contrasts provided e.g. z_map, t_map, effects and variance.

        Parameters
        ----------
        second_level_contrast: str or array of shape (n_col), optional
            Where ``n_col`` is the number of columns of the design matrix,
            The string can be a formula compatible with the linear constraint
            of the Patsy library. Basically one can use the name of the
            conditions as they appear in the design matrix of
            the fitted model combined with operators /\*+- and numbers.
            Please check the patsy documentation for formula examples:
            http://patsy.readthedocs.io/en/latest/API-reference.html#patsy.DesignInfo.linear_constraint
            The default (None) is accepted if the design matrix has a single
            column, in which case the only possible contrast array([1]) is
            applied; when the design matrix has multiple columns, an error is
            raised.

        first_level_contrast: str or array of shape (n_col) with respect to
                              FirstLevelModel, optional
                              
            In case a list of FirstLevelModel was provided as
            second_level_input, we have to provide a contrast to apply to
            the first level models to get the corresponding list of images
            desired, that would be tested at the second level. In case a
            pandas DataFrame was provided as second_level_input this is the
            map name to extract from the pandas dataframe map_name column.
            It has to be a 't' contrast.

        second_level_stat_type: {'t', 'F'}, optional
            Type of the second level contrast

        output_type: str, optional
            Type of the output map. Can be 'z_score', 'stat', 'p_value',
            'effect_size' or 'effect_variance'

        Returns
        -------
        output_image: Nifti1Image
            The desired output image

        """
        if self.second_level_input_ is None:
            raise ValueError('The model has not been fit yet')

        # first_level_contrast check
        if isinstance(self.second_level_input_[0], FirstLevelModel):
            if first_level_contrast is None:
                raise ValueError('If second_level_input was a list of '
                                 'FirstLevelModel, then first_level_contrast '
                                 'is mandatory. It corresponds to the '
                                 'second_level_contrast argument of the '
                                 'compute_contrast method of FirstLevelModel')

        # check contrast definition
        if second_level_contrast is None:
            if self.design_matrix_.shape[1] == 1:
                second_level_contrast = np.ones([1])
            else:
                raise ValueError('No second-level contrast is specified.')
        if isinstance(second_level_contrast, np.ndarray):
            con_val = second_level_contrast
            if np.all(con_val == 0):
                raise ValueError('Contrast is null')
        else:
            design_info = DesignInfo(self.design_matrix_.columns.tolist())
            constraint = design_info.linear_constraint(second_level_contrast)
            con_val = constraint.coefs
        # check output type
        if isinstance(output_type, _basestring):
            if output_type not in [
                    'z_score', 'stat', 'p_value', 'effect_size',
                    'effect_variance'
            ]:
                raise ValueError(
                    'output_type must be one of "z_score", "stat"'
                    ', "p_value", "effect_size" or "effect_variance"')
        else:
            raise ValueError('output_type must be one of "z_score", "stat",'
                             ' "p_value", "effect_size" or "effect_variance"')

        # Get effect_maps appropriate for chosen contrast
        effect_maps = _infer_effect_maps(self.second_level_input_,
                                         first_level_contrast)
        # Check design matrix X and effect maps Y agree on number of rows
        if len(effect_maps) != self.design_matrix_.shape[0]:
            raise ValueError(
                'design_matrix does not match the number of maps considered. '
                '%i rows in design matrix do not match with %i maps' %
                (self.design_matrix_.shape[0], len(effect_maps)))

        # Fit an Ordinary Least Squares regression for parametric statistics
        Y = self.masker_.transform(effect_maps)
        if self.memory:
            mem_glm = self.memory.cache(run_glm, ignore=['n_jobs'])
        else:
            mem_glm = run_glm
        labels, results = mem_glm(Y,
                                  self.design_matrix_.values,
                                  n_jobs=self.n_jobs,
                                  noise_model='ols')
        # We save memory if inspecting model details is not necessary
        if self.minimize_memory:
            for key in results:
                results[key] = SimpleRegressionResults(results[key])
        self.labels_ = labels
        self.results_ = results

        # We compute contrast object
        if self.memory:
            mem_contrast = self.memory.cache(compute_contrast)
        else:
            mem_contrast = compute_contrast
        contrast = mem_contrast(self.labels_, self.results_, con_val,
                                second_level_stat_type)

        # We get desired output from contrast object
        estimate_ = getattr(contrast, output_type)()

        # Prepare the returned images
        output = self.masker_.inverse_transform(estimate_)
        contrast_name = str(con_val)
        output.header['descrip'] = ('%s of contrast %s' %
                                    (output_type, contrast_name))
        return output
Esempio n. 7
0
    def compute_contrast(self,
                         contrast_def,
                         stat_type=None,
                         output_type='z_score'):
        """Generate different outputs corresponding to
        the contrasts provided e.g. z_map, t_map, effects and variance.
        In multi-session case, outputs the fixed effects map.

        Parameters
        ----------
        contrast_def : str or array of shape (n_col) or list of (string or
                       array of shape (n_col))
                       
            where ``n_col`` is the number of columns of the design matrix,
            (one array per run). If only one array is provided when there
            are several runs, it will be assumed that the same contrast is
            desired for all runs. The string can be a formula compatible with
            the linear constraint of the Patsy library. Basically one can use
            the name of the conditions as they appear in the design matrix of
            the fitted model combined with operators /\*+- and numbers.
            Please checks the patsy documentation for formula examples:
            http://patsy.readthedocs.io/en/latest/API-reference.html#patsy.DesignInfo.linear_constraint

        stat_type : {'t', 'F'}, optional
            type of the contrast

        output_type : str, optional
            Type of the output map. Can be 'z_score', 'stat', 'p_value',
            'effect_size', 'effect_variance' or 'all'

        Returns
        -------
        output : Nifti1Image or dict
            The desired output image(s). If ``output_type == 'all'``, then
            the output is a dictionary of images, keyed by the type of image.

        """
        if self.labels_ is None or self.results_ is None:
            raise ValueError('The model has not been fit yet')

        if isinstance(contrast_def, (np.ndarray, str)):
            con_vals = [contrast_def]
        elif isinstance(contrast_def, (list, tuple)):
            con_vals = contrast_def
        else:
            raise ValueError('contrast_def must be an array or str or list of'
                             ' (array or str)')

        # Translate formulas to vectors with patsy
        design_info = DesignInfo(self.design_matrices_[0].columns.tolist())
        for cidx, con in enumerate(con_vals):
            if not isinstance(con, np.ndarray):
                con_vals[cidx] = design_info.linear_constraint(con).coefs

        n_runs = len(self.labels_)
        if len(con_vals) != n_runs:
            warn('One contrast given, assuming it for all %d runs' % n_runs)
            con_vals = con_vals * n_runs

        # 'all' is assumed to be the final entry; if adding more, place before 'all'
        valid_types = [
            'z_score', 'stat', 'p_value', 'effect_size', 'effect_variance',
            'all'
        ]
        if output_type not in valid_types:
            raise ValueError(
                'output_type must be one of {}'.format(valid_types))

        contrast = _fixed_effect_contrast(self.labels_, self.results_,
                                          con_vals, stat_type)

        output_types = valid_types[:-1] if output_type == 'all' else [
            output_type
        ]

        outputs = {}
        for output_type_ in output_types:
            estimate_ = getattr(contrast, output_type_)()
            # Prepare the returned images
            output = self.masker_.inverse_transform(estimate_)
            contrast_name = str(con_vals)
            output.header['descrip'] = ('%s of contrast %s' %
                                        (output_type_, contrast_name))
            outputs[output_type_] = output

        return outputs if output_type == 'all' else output
Esempio n. 8
0
    def compute_contrast(self, contrast_def, stat_type=None,
                         output_type='z_score'):
        """Generate different outputs corresponding to
        the contrasts provided e.g. z_map, t_map, effects and variance.
        In multi-session case, outputs the fixed effects map.

        Parameters
        ----------
        contrast_def : str or array of shape (n_col) or list of (string or
                       array of shape (n_col))
                       
            where ``n_col`` is the number of columns of the design matrix,
            (one array per run). If only one array is provided when there
            are several runs, it will be assumed that the same contrast is
            desired for all runs. The string can be a formula compatible with
            the linear constraint of the Patsy library. Basically one can use
            the name of the conditions as they appear in the design matrix of
            the fitted model combined with operators /\*+- and numbers.
            Please checks the patsy documentation for formula examples:
            http://patsy.readthedocs.io/en/latest/API-reference.html#patsy.DesignInfo.linear_constraint

        stat_type : {'t', 'F'}, optional
            type of the contrast

        output_type : str, optional
            Type of the output map. Can be 'z_score', 'stat', 'p_value',
            'effect_size', 'effect_variance' or 'all'

        Returns
        -------
        output : Nifti1Image or dict
            The desired output image(s). If ``output_type == 'all'``, then
            the output is a dictionary of images, keyed by the type of image.

        """
        if self.labels_ is None or self.results_ is None:
            raise ValueError('The model has not been fit yet')

        if isinstance(contrast_def, (np.ndarray, str)):
            con_vals = [contrast_def]
        elif isinstance(contrast_def, (list, tuple)):
            con_vals = contrast_def
        else:
            raise ValueError('contrast_def must be an array or str or list of'
                             ' (array or str)')

        # Translate formulas to vectors with patsy
        design_info = DesignInfo(self.design_matrices_[0].columns.tolist())
        for cidx, con in enumerate(con_vals):
            if not isinstance(con, np.ndarray):
                con_vals[cidx] = design_info.linear_constraint(con).coefs

        n_runs = len(self.labels_)
        if len(con_vals) != n_runs:
            warn('One contrast given, assuming it for all %d runs' % n_runs)
            con_vals = con_vals * n_runs

        # 'all' is assumed to be the final entry; if adding more, place before 'all'
        valid_types = ['z_score', 'stat', 'p_value', 'effect_size',
                       'effect_variance', 'all']
        if output_type not in valid_types:
            raise ValueError('output_type must be one of {}'.format(valid_types))

        contrast = _fixed_effect_contrast(self.labels_, self.results_,
                                          con_vals, stat_type)

        output_types = valid_types[:-1] if output_type == 'all' else [output_type]

        outputs = {}
        for output_type_ in output_types:
            estimate_ = getattr(contrast, output_type_)()
            # Prepare the returned images
            output = self.masker_.inverse_transform(estimate_)
            contrast_name = str(con_vals)
            output.header['descrip'] = (
                '%s of contrast %s' % (output_type_, contrast_name))
            outputs[output_type_] = output

        return outputs if output_type == 'all' else output
Esempio n. 9
0
    def compute_contrast(self,
                         contrast_def,
                         stat_type=None,
                         output_type='z_score'):
        """Generate different outputs corresponding to
        the contrasts provided e.g. z_map, t_map, effects and variance.

        Parameters
        ----------
        contrast_def : str or array of shape (n_col)
            where ``n_col`` is the number of columns of the design matrix,
            The string can be a formula compatible with the linear constraint
            of the Patsy library. Basically one can use the name of the
            conditions as they appear in the design matrix of
            the fitted model combined with operators /*+- and numbers.
            Please checks the patsy documentation for formula examples:
            http://patsy.readthedocs.io/en/latest/API-reference.html#patsy.DesignInfo.linear_constraint

        stat_type : {'t', 'F'}, optional
            type of the contrast

        output_type : str, optional
            Type of the output map. Can be 'z_score', 'stat', 'p_value',
            'effect_size' or 'effect_variance'

        Returns
        -------
        output_image : Nifti1Image
            The desired output image

        """
        # check model was fit
        if self.labels_ is None or self.results_ is None:
            raise ValueError('The model has not been fit yet')

        # check contrast definition
        if isinstance(contrast_def, np.ndarray):
            con_val = contrast_def
            if np.all(con_val == 0):
                raise ValueError('Contrast is null')
        else:
            design_info = DesignInfo(self.design_matrix_.columns.tolist())
            con_val = design_info.linear_constraint(contrast_def).coefs

        # check output type
        if isinstance(output_type, _basestring):
            if output_type not in [
                    'z_score', 'stat', 'p_value', 'effect_size',
                    'effect_variance'
            ]:
                raise ValueError(
                    'output_type must be one of "z_score", "stat"'
                    ', "p_value", "effect_size" or "effect_variance"')
        else:
            raise ValueError('output_type must be one of "z_score", "stat",'
                             ' "p_value", "effect_size" or "effect_variance"')

        if self.memory is not None:
            arg_ignore = ['labels', 'results']
            mem_contrast = self.memory.cache(compute_contrast,
                                             ignore=arg_ignore)
        else:
            mem_contrast = compute_contrast
        contrast = mem_contrast(self.labels_, self.results_, con_val,
                                stat_type)

        estimate_ = getattr(contrast, output_type)()
        # Prepare the returned images
        output = self.masker_.inverse_transform(estimate_)
        contrast_name = str(con_val)
        output.get_header()['descrip'] = ('%s of contrast %s' %
                                          (output_type, contrast_name))
        return output
Esempio n. 10
0
    def compute_contrast(
            self, second_level_contrast=None, first_level_contrast=None,
            second_level_stat_type=None, output_type='z_score'):
        """Generate different outputs corresponding to
        the contrasts provided e.g. z_map, t_map, effects and variance.

        Parameters
        ----------
        second_level_contrast: str or array of shape (n_col), optional
            Where ``n_col`` is the number of columns of the design matrix,
            The string can be a formula compatible with the linear constraint
            of the Patsy library. Basically one can use the name of the
            conditions as they appear in the design matrix of
            the fitted model combined with operators /\*+- and numbers.
            Please check the patsy documentation for formula examples:
            http://patsy.readthedocs.io/en/latest/API-reference.html#patsy.DesignInfo.linear_constraint
            The default (None) is accepted if the design matrix has a single
            column, in which case the only possible contrast array([1]) is
            applied; when the design matrix has multiple columns, an error is
            raised.

        first_level_contrast: str or array of shape (n_col) with respect to
                              FirstLevelModel, optional
                              
            In case a list of FirstLevelModel was provided as
            second_level_input, we have to provide a contrast to apply to
            the first level models to get the corresponding list of images
            desired, that would be tested at the second level. In case a
            pandas DataFrame was provided as second_level_input this is the
            map name to extract from the pandas dataframe map_name column.
            It has to be a 't' contrast.

        second_level_stat_type: {'t', 'F'}, optional
            Type of the second level contrast

        output_type: str, optional
            Type of the output map. Can be 'z_score', 'stat', 'p_value',
            'effect_size' or 'effect_variance'

        Returns
        -------
        output_image: Nifti1Image
            The desired output image

        """
        if self.second_level_input_ is None:
            raise ValueError('The model has not been fit yet')

        # first_level_contrast check
        if isinstance(self.second_level_input_[0], FirstLevelModel):
            if first_level_contrast is None:
                raise ValueError('If second_level_input was a list of '
                                 'FirstLevelModel, then first_level_contrast '
                                 'is mandatory. It corresponds to the '
                                 'second_level_contrast argument of the '
                                 'compute_contrast method of FirstLevelModel')

        # check contrast definition
        if second_level_contrast is None:
            if self.design_matrix_.shape[1] == 1:
                second_level_contrast = np.ones([1])
            else:
                raise ValueError('No second-level contrast is specified.')
        if isinstance(second_level_contrast, np.ndarray):
            con_val = second_level_contrast
            if np.all(con_val == 0):
                raise ValueError('Contrast is null')
        else:
            design_info = DesignInfo(self.design_matrix_.columns.tolist())
            constraint = design_info.linear_constraint(second_level_contrast)
            con_val = constraint.coefs
        # check output type
        if isinstance(output_type, _basestring):
            if output_type not in ['z_score', 'stat', 'p_value', 'effect_size',
                                   'effect_variance']:
                raise ValueError(
                    'output_type must be one of "z_score", "stat"'
                    ', "p_value", "effect_size" or "effect_variance"')
        else:
            raise ValueError('output_type must be one of "z_score", "stat",'
                             ' "p_value", "effect_size" or "effect_variance"')

        # Get effect_maps appropriate for chosen contrast
        effect_maps = _infer_effect_maps(self.second_level_input_,
                                         first_level_contrast)
        # Check design matrix X and effect maps Y agree on number of rows
        if len(effect_maps) != self.design_matrix_.shape[0]:
            raise ValueError(
                'design_matrix does not match the number of maps considered. '
                '%i rows in design matrix do not match with %i maps' %
                (self.design_matrix_.shape[0], len(effect_maps)))

        # Fit an Ordinary Least Squares regression for parametric statistics
        Y = self.masker_.transform(effect_maps)
        if self.memory:
            mem_glm = self.memory.cache(run_glm, ignore=['n_jobs'])
        else:
            mem_glm = run_glm
        labels, results = mem_glm(Y, self.design_matrix_.values,
                                  n_jobs=self.n_jobs, noise_model='ols')
        # We save memory if inspecting model details is not necessary
        if self.minimize_memory:
            for key in results:
                results[key] = SimpleRegressionResults(results[key])
        self.labels_ = labels
        self.results_ = results

        # We compute contrast object
        if self.memory:
            mem_contrast = self.memory.cache(compute_contrast)
        else:
            mem_contrast = compute_contrast
        contrast = mem_contrast(self.labels_, self.results_, con_val,
                                second_level_stat_type)

        # We get desired output from contrast object
        estimate_ = getattr(contrast, output_type)()

        # Prepare the returned images
        output = self.masker_.inverse_transform(estimate_)
        contrast_name = str(con_val)
        output.header['descrip'] = (
            '%s of contrast %s' % (output_type, contrast_name))
        return output