Exemplo n.º 1
0
def test_MelodicImage_create():

    # non existent
    with pytest.raises(Exception):
        meli.MelodicImage('badfile')

    # bad file
    paths = [
        'analysis.ica/melodic_IC.nii.gz', 'analysis.ica/melodic_mix',
        'analysis.ica/melodic_FTmix'
    ]
    with tests.testdir(paths) as testdir:
        path = op.join(testdir, 'analysis.ica/melodic_IC.nii.gz')
        with pytest.raises(Exception):
            meli.MelodicImage(path)

    with tests.testdir() as testdir:
        meldir = _create_dummy_melodic_analysis(testdir)
        icfile = op.join(meldir, 'melodic_IC.nii.gz')
        icfilenosuf = op.join(meldir, 'melodic_IC')

        # Should be able to specify the
        # melodic dir, or the IC image
        meli.MelodicImage(meldir)
        meli.MelodicImage(icfile)
        meli.MelodicImage(icfilenosuf)
Exemplo n.º 2
0
def test_MelodicImage_tr():

    # If data file not present, tr should default to 1.0
    with tests.testdir() as testdir:
        meldir = _create_dummy_melodic_analysis(testdir, with_data=False)
        img = meli.MelodicImage(meldir)

        assert img.tr == 1

    # Otherwise, it should be set to the datafile tr
    with tests.testdir() as testdir:
        meldir = _create_dummy_melodic_analysis(testdir, tr=5)
        img = meli.MelodicImage(meldir)
        assert img.tr == 5

    # The TR can be updated
    with tests.testdir() as testdir:

        cbCalled = [False]

        def trChanged(*a):
            cbCalled[0] = True

        meldir = _create_dummy_melodic_analysis(testdir, with_data=False)
        img = meli.MelodicImage(meldir)

        img.register('cbname', trChanged, topic='tr')

        img.tr = 8

        assert cbCalled[0]
        assert img.tr == 8
Exemplo n.º 3
0
def test_MelodicImage_create():

    # non existent
    with pytest.raises(Exception):
        meli.MelodicImage('badfile')

    # bad file
    paths = [
        'analysis.ica/melodic_IC.nii.gz', 'analysis.ica/melodic_mix',
        'analysis.ica/melodic_FTmix'
    ]
    paths = [op.join(*p.split('/')) for p in paths]
    with tests.testdir(paths) as testdir:
        path = op.join(testdir, 'analysis.ica', 'melodic_IC.nii.gz')
        with pytest.raises(Exception):
            meli.MelodicImage(path)

    for ic_prefix in ['melodic_IC', 'melodic_oIC']:

        with tests.testdir() as testdir:
            meldir = _create_dummy_melodic_analysis(testdir,
                                                    ic_prefix=ic_prefix)
            icfile = op.join(meldir, '{}.nii.gz'.format(ic_prefix))
            icfilenosuf = op.join(meldir, ic_prefix)

            # Should be able to specify the
            # melodic dir, or the IC image
            i = meli.MelodicImage(meldir)
            i = meli.MelodicImage(icfile)
            i = meli.MelodicImage(icfilenosuf)
            i = None
Exemplo n.º 4
0
def test_MelodicImage_componentData():
    with tests.testdir() as testdir:
        meldir = _create_dummy_melodic_analysis(testdir)
        img = meli.MelodicImage(meldir)
        nics = img.numComponents()

        expectTS = mela.getComponentTimeSeries(meldir)
        expectPS = mela.getComponentPowerSpectra(meldir)

        for ic in range(nics):
            assert np.all(img.getComponentTimeSeries(ic) == expectTS[:, ic])
            assert np.all(img.getComponentPowerSpectrum(ic) == expectPS[:, ic])
Exemplo n.º 5
0
def test_MelodicImage_atts():

    with tests.testdir() as testdir:
        meldir = _create_dummy_melodic_analysis(testdir)
        img = meli.MelodicImage(meldir)

        assert img.shape == (10, 10, 10, 10)
        assert img.pixdim == (1, 1, 1, 1)
        assert np.all(img.voxToWorldMat == np.eye(4))
        assert img.numComponents() == 10
        assert img.getMelodicDir() == meldir

        assert img.getReportFile() == mela.getReportFile(meldir)
        assert img.getTopLevelAnalysisDir() == mela.getTopLevelAnalysisDir(
            meldir)
        assert img.getDataFile() == mela.getDataFile(meldir)
        assert img.getMeanFile() == mela.getMeanFile(meldir)
Exemplo n.º 6
0
    def __onLoadButton(self, ev):
        """Called when the *Load labels* button is pushed.  Prompts the user
        to select a label file to load, then does the following:

        1. If the selected label file refers to the currently selected
           melodic_IC overlay, the labels are applied to the overlay.

        2. If the selected label file refers to a different melodic_IC
           overlay, the user is asked whether they want to load the
           different melodic_IC file (the default), or whether they
           want the labels applied to the existing overlay.

        3. If the selected label file does not refer to any overlay
           (it only contains the bad component list), the user is asked
           whether they want the labels applied to the current melodic_IC
           overlay.

        If the number of labels in the file is less than the number of
        melodic_IC components, the remaining components are labelled
        as unknown. If the number of labels in the file is greater than
        the number of melodic_IC components, an error is shown, and
        nothing is done.
        """

        # The aim of the code beneath the
        # applyLabels function is to load
        # a set of component labels, and
        # to figure out which overlay
        # they should be added to.

        # When it has done this, it calls
        # applyLabels, which applies the
        # loaded labels to the overlay.
        def applyLabels(labelFile, overlay, allLabels, newOverlay):
            # labelFile:  Path to the loaded label file
            # overlay:    Overlay to apply them to
            # allLabels:  Loaded labels (list of (component, [label]) tuples)
            # newOverlay: True if the selected overlay has changed, False
            #             otherwise

            lut       = self.__lut
            volLabels = self.overlayList.getData(overlay, 'VolumeLabels')

            ncomps  = volLabels.numComponents()
            nlabels = len(allLabels)

            # Error: number of labels in the
            # file is greater than the number
            # of components in the overlay.
            if ncomps < nlabels:
                msg   = strings.messages[self, 'wrongNComps'].format(
                    labelFile, overlay.dataSource)
                title = strings.titles[  self, 'loadError']
                wx.MessageBox(msg, title, wx.ICON_ERROR | wx.OK)
                return

            # Number of labels in the file is
            # less than number of components
            # in the overlay - we pad the
            # labels with 'Unknown'
            elif ncomps > nlabels:
                for i in range(nlabels, ncomps):
                    allLabels.append(['Unknown'])

            # Disable notification while applying
            # labels so the component/label grids
            # don't confuse themselves.
            with volLabels.skip(self.__componentGrid.name), \
                 volLabels.skip(self.__labelGrid    .name):

                volLabels.clear()

                for comp, lbls in enumerate(allLabels):
                    for lbl in lbls:
                        volLabels.addLabel(comp, lbl)

                # Make sure a colour in the melodic
                # lookup table exists for all labels
                for label in volLabels.getAllLabels():

                    label    = volLabels.getDisplayLabel(label)
                    lutLabel = lut.getByName(label)

                    if lutLabel is None:
                        log.debug('New melodic classification '
                                  'label: {}'.format(label))
                        lut.new(label, colour=fslcm.randomBrightColour())

            # New overlay was loaded
            if newOverlay:

                # Make sure the new image is selected.
                with props.skip(self.displayCtx,
                                'selectedOverlay',
                                self.name):
                    self.displayCtx.selectOverlay(overlay)

                self.__componentGrid.setOverlay(overlay)
                self.__labelGrid    .setOverlay(overlay)

            # Labels were applied to
            # already selected overlay.
            else:
                self.__componentGrid.refreshTags()
                self.__labelGrid    .refreshTags()

        # If the current overlay is a compatible
        # Image, the open file dialog starting
        # point will be its directory.
        overlay = self.__overlay

        if overlay is not None and overlay.dataSource is not None:
            loadDir = op.dirname(overlay.dataSource)

        # Otherwise it will be the most
        # recent overlay load directory.
        else:
            loadDir = fslsettings.read('loadSaveOverlayDir', os.getcwd())

        # Ask the user to select a label file
        dlg = wx.FileDialog(
            self,
            message=strings.titles[self, 'loadDialog'],
            defaultDir=loadDir,
            style=wx.FD_OPEN)

        # User cancelled the dialog
        if dlg.ShowModal() != wx.ID_OK:
            return

        # Load the specified label file
        filename = dlg.GetPath()
        emsg     = strings.messages[self, 'loadError'].format(filename)
        etitle   = strings.titles[  self, 'loadError']
        try:
            with status.reportIfError(msg=emsg, title=etitle):
                melDir, allLabels = fixlabels.loadLabelFile(filename)
        except Exception:
            return

        # Ok we've got the labels, now
        # we need to figure out which
        # overlay to add them to.

        # If the label file does not refer
        # to a Melodic directory, and the
        # current overlay is a compatible
        # image, apply the labels to the
        # image.
        if overlay is not None and melDir is None:
            applyLabels(filename, overlay, allLabels, False)
            return

        # If the label file refers to a
        # Melodic directory, and the
        # current overlay is a compatible
        # image.
        if overlay is not None and melDir is not None:

            if isinstance(overlay, fslmelimage.MelodicImage):
                overlayDir = overlay.getMelodicDir()
            elif overlay.dataSource is not None:
                overlayDir = op.dirname(overlay.dataSource)
            else:
                overlayDir = 'none'

            # And both the current overlay and
            # the label file refer to the same
            # directory, then we apply the
            # labels to the curent overlay.
            if op.abspath(melDir) == op.abspath(overlayDir):

                applyLabels(filename, overlay, allLabels, False)
                return

            # Otherwise, if the overlay and the
            # label file refer to different
            # directories...

            # Ask the user whether they want to load
            # the image specified in the label file,
            # or apply the labels to the currently
            # selected image.
            dlg = wx.MessageDialog(
                self,
                strings.messages[self, 'diffMelDir'].format(
                    melDir, overlayDir),
                style=wx.ICON_QUESTION | wx.YES_NO | wx.CANCEL)
            dlg.SetYesNoLabels(
                strings.messages[self, 'diffMelDir.labels'],
                strings.messages[self, 'diffMelDir.overlay'])

            response = dlg.ShowModal()

            # User cancelled the dialog
            if response == wx.ID_CANCEL:
                return

            # User chose to load the melodic
            # image specified in the label
            # file. We'll carry on with this
            # processing below.
            elif response == wx.ID_YES:
                pass

            # Apply the labels to the current
            # overlay, even though they are
            # from different analyses.
            else:
                applyLabels(filename, overlay, allLabels, False)
                return

        # If we've reached this far, we are
        # going to attempt to identify the
        # image associated with the label
        # file, load that image, and then
        # apply the labels.

        # The label file does not
        # specify a melodic directory
        if melDir is None:

            msg   = strings.messages[self, 'noMelDir'].format(filename)
            title = strings.titles[  self, 'loadError']
            wx.MessageBox(msg, title, wx.ICON_ERROR | wx.OK)
            return

        # Try loading the melodic_IC image
        # specified in the label file.
        try:
            overlay = fslmelimage.MelodicImage(melDir)

            log.debug('Adding {} to overlay list'.format(overlay))

            with props.skip(self.overlayList, 'overlays',        self.name),\
                 props.skip(self.displayCtx,  'selectedOverlay', self.name):

                self.overlayList.append(overlay)

            if self.displayCtx.autoDisplay:
                autodisplay.autoDisplay(overlay,
                                        self.overlayList,
                                        self.displayCtx)

            fslsettings.write('loadSaveOverlayDir', op.abspath(melDir))

        except Exception as e:

            e     = str(e)
            msg   = strings.messages[self, 'loadError'].format(filename, e)
            title = strings.titles[  self, 'loadError']
            log.debug('Error loading classification file '
                      '({}), ({})'.format(filename, e), exc_info=True)
            wx.MessageBox(msg, title, wx.ICON_ERROR | wx.OK)

        # Apply the loaded labels
        # to the loaded overlay.
        applyLabels(filename, overlay, allLabels, True)