Exemple #1
0
def test_fit_FSLModel_on_invivo_sim():

    FIDs, hdr, trueconcs = syntheticFromBasisFile(basis_path,
                                                  noisecovariance=[[1E-3]],
                                                  broadening=(9.0, 9.0),
                                                  concentrations={'Mac': 2.0})

    basis, names, header = mrs_io.read_basis(basis_path)

    mrs = MRS(FID=FIDs,
              header=hdr,
              basis=basis,
              basis_hdr=header[0],
              names=names)
    mrs.processForFitting()

    metab_groups = [0] * mrs.numBasis
    Fitargs = {
        'ppmlim': [0.2, 4.2],
        'method': 'MH',
        'baseline_order': -1,
        'metab_groups': metab_groups,
        'MHSamples': 100
    }

    res = fit_FSLModel(mrs, **Fitargs)

    fittedRelconcs = res.getConc(scaling='internal', metab=mrs.names)

    answers = np.asarray(trueconcs)
    answers /= (answers[names.index('Cr')] + trueconcs[names.index('PCr')])

    assert np.allclose(fittedRelconcs, answers, atol=5E-2)
Exemple #2
0
def data():
    noiseCov = 0.01
    amplitude = np.asarray([0.5, 0.5, 1.0]) * 10
    chemshift = np.asarray([3.0, 3.05, 2.0]) - 4.65
    lw = [10, 10, 10]
    phases = [0, 0, 0]
    g = [0, 0, 0]
    basisNames = ['Cr', 'PCr', 'NAA']

    basisFIDs = []
    for idx, _ in enumerate(amplitude):
        tmp, basisHdr = syntheticFID(noisecovariance=[[0.0]],
                                     chemicalshift=[chemshift[idx]],
                                     amplitude=[1.0],
                                     linewidth=[lw[idx] / 5],
                                     phase=[phases[idx]],
                                     g=[g[idx]])
        basisFIDs.append(tmp[0])
    basisFIDs = np.asarray(basisFIDs)

    synFID, synHdr = syntheticFID(noisecovariance=[[noiseCov]],
                                  chemicalshift=chemshift,
                                  amplitude=amplitude,
                                  linewidth=lw,
                                  phase=phases,
                                  g=g)

    synMRS = MRS(FID=synFID[0],
                 header=synHdr,
                 basis=basisFIDs,
                 basis_hdr=basisHdr,
                 names=basisNames)

    return synMRS, amplitude
Exemple #3
0
def shiftToRef(FID, target, bw, cf, ppmlim=(2.8, 3.2), shift=True):
    #Find maximum of absolute spectrum in ppm limit
    padFID = pad(FID, FID.size * 3)
    MRSargs = {'FID': padFID, 'bw': bw, 'cf': cf}
    mrs = MRS(**MRSargs)
    spec = extract_spectrum(mrs, padFID, ppmlim=ppmlim, shift=shift)
    if shift:
        extractedAxis = mrs.getAxes(ppmlim=ppmlim)
    else:
        extractedAxis = mrs.getAxes(ppmlim=ppmlim, axis='ppm')

    maxIndex = np.argmax(np.abs(spec))
    shiftAmount = extractedAxis[maxIndex] - target
    shiftAmountHz = shiftAmount * mrs.centralFrequency / 1E6

    return freqshift(FID, 1 / bw, -shiftAmountHz), shiftAmount
Exemple #4
0
def phase_freq_align_diff(FIDlist0,
                          FIDlist1,
                          bandwidth,
                          centralFrequency,
                          diffType='add',
                          ppmlim=None,
                          shift=True,
                          target=None):
    """ Align subspectra from difference methods.

    Only spectra in FIDlist0 are shifted.   

    Parameters:
    -----------
    FIDlist0         : list - shifted
    FIDlist1         : list - fixed
    bandwidth        : float (unit=Hz)
    centralFrequency : float (unit=Hz)
    diffType         : string - add or subtract
    ppmlim           : tuple    
    shift            : apply H20 shift to ppm limit
    ref              : reference data to align to
    
    Returns:
    --------
    two lists of FID aligned to each other, phase and shift applied to first list.
    """
    # Process target
    if target is not None:
        tgt_FID = target
    else:
        diffFIDList = []
        for fid0, fid1 in zip(FIDlist0, FIDlist1):
            if diffType.lower() == 'add':
                diffFIDList.append(add(fid1, fid0))
            elif diffType.lower() == 'sub':
                diffFIDList.append(subtract(fid1, fid0))
            else:
                raise ValueError('diffType must be add or sub.')
        tgt_FID = get_target_FID(diffFIDList, target='nearest_to_mean')

    # Pass to phase_freq_align
    mrs = MRS(FID=FIDlist0[0], cf=centralFrequency, bw=bandwidth)
    phiOut, epsOut = [], []
    alignedFIDs0 = []
    for fid0, fid1 in zip(FIDlist0, FIDlist1):
        # breakpoint()
        out = align_FID_diff(mrs,
                             fid0,
                             fid1,
                             tgt_FID,
                             diffType=diffType,
                             ppmlim=ppmlim,
                             shift=shift)
        alignedFIDs0.append(out[0])
        phiOut.append(out[1])
        epsOut.append(out[2])

    return alignedFIDs0, FIDlist1, phiOut, epsOut
Exemple #5
0
 def mrs_by_index(self,index):
     mrs_out = MRS(FID=self.data[index[0],index[1],index[2],:],
                             header=self.header,
                             basis=self.basis,
                             names=self.names,
                             basis_hdr=self.basis_hdr,
                             H2O=self.H2O[index[0],index[1],index[2],:])
     self._process_mrs(mrs_out)
     return mrs_out
Exemple #6
0
def identifyUnlikeFIDs(FIDList,bandwidth,centralFrequency,sdlimit = 1.96,iterations=2,ppmlim=None,shift=True):
    """ Identify FIDs in a list that are unlike the others

    Args:
        FIDList (list of ndarray): Time domain data
        bandwidth (float)        : Bandwidth in Hz
        centralFrequency (float) : Central frequency in Hz
        sdlimit (float,optional) : Exclusion limit (number of stnadard deviations). Default = 3.
        iterations (int,optional): Number of iterations to use.
        ppmlim (tuple,optional)  : Limit to this ppm range
        shift (bool,optional)    : Apply H20 shft

    Returns:
        goodFIDS (list of ndarray): FIDs that passed the criteria
        badFIDS (list of ndarray): FIDs that failed the likeness critera
        rmIndicies (list of int): Indicies of those FIDs that have been removed
        metric (list of floats): Likeness metric of each FID
    """

    # Calculate the FID to compare to
    target = get_target_FID(FIDList,target='median')

    if ppmlim is not None:
        MRSargs = {'FID':target,'bw':bandwidth,'cf':centralFrequency}
        mrs = MRS(**MRSargs)
        target = extract_spectrum(mrs,target,ppmlim=ppmlim,shift=shift)
        compareList = [extract_spectrum(mrs,f,ppmlim=ppmlim,shift=shift) for f in FIDList]
    else:
        compareList = [FIDToSpec(f) for f in FIDList]
        target = FIDToSpec(target)
    
    # Do the comparison    
    for idx in range(iterations):
        metric = []
        for data in compareList:
            metric.append(np.linalg.norm(data-target))            
        metric = np.asarray(metric)
        metric_avg = np.mean(metric)
        metric_std = np.std(metric)

        goodFIDs,badFIDs,rmIndicies,keepIndicies = [],[],[],[]
        for iDx,(data,m) in enumerate(zip(FIDList,metric)):
            if m > ((sdlimit*metric_std)+metric_avg) or m < (-(sdlimit*metric_std)+metric_avg):
                badFIDs.append(data)
                rmIndicies.append(iDx)
            else:
                goodFIDs.append(data)
                keepIndicies.append(iDx)

        target = get_target_FID(goodFIDs,target='median')
        if ppmlim is not None:
            target = extract_spectrum(mrs,target,ppmlim=ppmlim,shift=shift)
        else:
            target = FIDToSpec(target)
    

    return goodFIDs,badFIDs,keepIndicies,rmIndicies,metric.tolist()
def test_shiftToRef():
    testFIDs, testHdrs = syn.syntheticFID(amplitude=[1, 0],
                                          chemicalshift=[-2.1, 0],
                                          phase=[0, 0],
                                          points=1024,
                                          noisecovariance=[[1E-3]])

    shiftFID, _ = preproc.shiftToRef(testFIDs[0],
                                     -2.0,
                                     testHdrs['bandwidth'],
                                     testHdrs['centralFrequency'],
                                     ppmlim=(-2.2, -2.0),
                                     shift=False)

    mrs = MRS(FID=shiftFID, header=testHdrs)

    maxindex = np.argmax(mrs.getSpectrum(shift=False))
    position = mrs.getAxes(axis='ppm')[maxindex]

    assert np.isclose(position, -2.0, atol=1E-1)
def test_align_diff():
    shift0 = np.random.randn(10) * 0.15
    phs = np.random.randn(10) * 0.1 * np.pi
    shiftedFIDs0 = []
    shiftedFIDs1 = []
    for s0, p in zip(shift0, phs):
        testFIDs, testHdrs = syn.syntheticFID(amplitude=[1, 1],
                                              chemicalshift=[-2 + s0, 3 + s0],
                                              phase=[p + np.pi, p],
                                              damping=[100, 100],
                                              points=2048,
                                              noisecovariance=[[1E-6]])
        shiftedFIDs0.append(testFIDs[0])

        testFIDs, testHdrs = syn.syntheticFID(amplitude=[1, 1],
                                              chemicalshift=[-2, 3],
                                              phase=[0, 0],
                                              damping=[100, 100],
                                              points=2048,
                                              noisecovariance=[[1E-6]])
        shiftedFIDs1.append(testFIDs[0])

    testFIDs0, _ = syn.syntheticFID(amplitude=[2, 1],
                                    chemicalshift=[-2, 3],
                                    phase=[np.pi, 0],
                                    damping=[100, 100],
                                    points=2048,
                                    noisecovariance=[[1E-6]])
    testFIDs1, _ = syn.syntheticFID(amplitude=[2, 1],
                                    chemicalshift=[-2, 3],
                                    phase=[0, 0],
                                    damping=[100, 100],
                                    points=2048,
                                    noisecovariance=[[1E-6]])

    tgt = testFIDs0[0] + testFIDs1[0]
    mrs = MRS(FID=tgt, header=testHdrs)

    sub0_aa, sub1_aa, phi, eps = preproc.phase_freq_align_diff(
        shiftedFIDs0,
        shiftedFIDs1,
        testHdrs['bandwidth'],
        testHdrs['centralFrequency'],
        target=tgt,
        shift=False,
        ppmlim=(-5, 5))
    # align.phase_freq_align_diff_report(shiftedFIDs0,shiftedFIDs1,sub0_aa,sub1_aa,testHdrs,eps,phi,shift=False,ppmlim=(-5,5))

    shiftInHz = shift0 * testHdrs['centralFrequency']
    assert np.allclose(eps, shiftInHz, atol=1E-0)
    assert np.allclose(phi, phs, atol=1E-0)
Exemple #9
0
 def mrs_from_average(self):
     FID = misc.volume_to_list(self.data,self.mask)
     H2O = misc.volume_to_list(self.H2O,self.mask)
     FID = sum(FID)/len(FID)
     H2O = sum(H2O)/len(H2O)
     
     mrs_out = MRS(FID=FID,
                   header=self.header,
                   basis=self.basis,
                   names=self.names,
                   basis_hdr=self.basis_hdr,
                   H2O=H2O)
     self._process_mrs(mrs_out)
     return mrs_out
Exemple #10
0
def data():
    noiseCov = 0.001
    amplitude = np.asarray([0.5, 0.5, 1.0]) * 10
    chemshift = np.asarray([3.0, 3.05, 2.0]) - 4.65
    lw = [10, 10, 10]
    phases = [0, 0, 0]
    g = [0, 0, 0]
    basisNames = ['Cr', 'PCr', 'NAA']
    begintime = 0.00005

    basisFIDs = []
    for idx, _ in enumerate(amplitude):
        tmp, basisHdr = syntheticFID(noisecovariance=[[0.0]],
                                     chemicalshift=[chemshift[idx] + 0.1],
                                     amplitude=[1.0],
                                     linewidth=[lw[idx] / 5],
                                     phase=[phases[idx]],
                                     g=[g[idx]],
                                     begintime=0)
        basisFIDs.append(tmp[0])
    basisFIDs = np.asarray(basisFIDs)

    synFID, synHdr = syntheticFID(noisecovariance=[[noiseCov]],
                                  chemicalshift=chemshift,
                                  amplitude=amplitude,
                                  linewidth=lw,
                                  phase=phases,
                                  g=g,
                                  begintime=begintime)

    synMRS = MRS(FID=synFID[0],
                 header=synHdr,
                 basis=basisFIDs,
                 basis_hdr=basisHdr,
                 names=basisNames)

    metab_groups = [0] * synMRS.numBasis
    Fitargs = {
        'ppmlim': [0.2, 4.2],
        'method': 'MH',
        'baseline_order': -1,
        'metab_groups': metab_groups,
        'MHSamples': 100,
        'disable_mh_priors': True
    }

    res = fit_FSLModel(synMRS, **Fitargs)

    return res, amplitude
Exemple #11
0
def generateBasisFromRes(mrs, res, resparams):
    """ Return mrs objects for each fitted basis spectrum"""
    mrsFits = []
    for metab in mrs.names:
        pred = models.getFittedModel(res.model,
                                     resparams,
                                     res.base_poly,
                                     res.metab_groups,
                                     mrs,
                                     basisSelect=metab,
                                     noBaseline=True)
        pred = SpecToFID(pred)  # predict FID not Spec
        mrsOut = MRS(pred, cf=mrs.centralFrequency, bw=mrs.bandwidth)
        mrsFits.append(mrsOut)
    return mrsFits
def test_quantifyWater():

    basis, names, headerb = mrsio.read_basis(basisfile)
    crIndex = names.index('Cr')
    data, header = mrsio.read_FID(metabfile)
    dataw, headerw = mrsio.read_FID(h2ofile)

    mrs = MRS(FID=data,
              header=header,
              basis=basis[:, crIndex],
              names=['Cr'],
              basis_hdr=headerb[crIndex],
              H2O=dataw)
    mrs.check_FID(repair=True)
    mrs.check_Basis(repair=True)

    Fitargs = {
        'ppmlim': [0.2, 5.2],
        'method': 'MH',
        'baseline_order': -1,
        'metab_groups': [0]
    }

    res = fit_FSLModel(mrs, **Fitargs)

    tissueFractions = {'GM': 0.6, 'WM': 0.4, 'CSF': 0.0}
    TE = 0.03
    T2dict = {
        'H2O_GM': 0.110,
        'H2O_WM': 0.080,
        'H2O_CSF': 2.55,
        'METAB': 0.160
    }

    res.calculateConcScaling(mrs,
                             referenceMetab=['Cr'],
                             waterRefFID=mrs.H2O,
                             tissueFractions=tissueFractions,
                             TE=TE,
                             T2=T2dict,
                             waterReferenceMetab='Cr',
                             wRefMetabProtons=5,
                             reflimits=(2, 5),
                             verbose=False)

    print(res.getConc(scaling='raw'))
    print(res.getConc(scaling='internal'))
    print(res.getConc(scaling='molality'))
    print(res.getConc(scaling='molarity'))

    assert np.allclose(res.getConc(scaling='internal'), 1.0)
    assert np.allclose(res.getConc(scaling='molarity'), 10.59, atol=1E-1)
Exemple #13
0
def phaseCorrect(FID, bw, cf, ppmlim=(2.8, 3.2), shift=True, hlsvd=False):
    """ Phase correction based on the phase of a maximum point.

    HLSVD is used to remove peaks outside the limits to flatten baseline first.

    Args:
        FID (ndarray): Time domain data
        bw (float): bandwidth
        cf (float): central frequency in Hz
        ppmlim (tuple,optional)  : Limit to this ppm range
        shift (bool,optional)    : Apply H20 shft
        hlsvd (bool,optional)    : Enable hlsvd step

    Returns:
        FID (ndarray): Phase corrected FID
    """

    if hlsvd:
        # Run HLSVD to remove peaks outside limits
        try:
            fid_hlsvd = hlsvd(FID,
                              1 / bw,
                              cf, (ppmlim[1] + 0.5, ppmlim[1] + 3.0),
                              limitUnits='ppm+shift')
            fid_hlsvd = hlsvd(fid_hlsvd,
                              1 / bw,
                              cf, (ppmlim[0] - 3.0, ppmlim[0] - 0.5),
                              limitUnits='ppm+shift')
        except:
            fid_hlsvd = FID
            print('HLSVD in phaseCorrect failed, proceeding to phasing.')
    else:
        fid_hlsvd = FID

    # Find maximum of absolute spectrum in ppm limit
    padFID = pad(fid_hlsvd, FID.size * 3)
    MRSargs = {'FID': padFID, 'bw': bw, 'cf': cf}
    mrs = MRS(**MRSargs)
    spec = extract_spectrum(mrs, padFID, ppmlim=ppmlim, shift=shift)

    maxIndex = np.argmax(np.abs(spec))
    phaseAngle = -np.angle(spec[maxIndex])

    return applyPhase(FID, phaseAngle), phaseAngle, int(np.round(maxIndex / 4))
Exemple #14
0
    def __iter__(self):
        shape = self.data.shape
        self._store_scalings = []
        for idx in np.ndindex(shape[:3]):
            if self.mask[idx]:
                mrs_out = MRS(FID=self.data[idx],
                                header=self.header,
                                basis=self.basis,
                                names=self.names,
                                basis_hdr=self.basis_hdr,
                                H2O=self.H2O[idx])
                
                self._process_mrs(mrs_out)
                self._store_scalings.append(mrs_out.scaling)

                if self.tissue_seg_loaded:
                    tissue_seg = {'CSF':self.csf[idx],'WM':self.wm[idx],'GM':self.gm[idx]}
                else:
                    tissue_seg = None

                yield mrs_out,idx,tissue_seg
Exemple #15
0
def apodize_report(inFID, outFID, hdr, plotlim=(0.2, 6), html=None):
    """
    Generate report
    """
    # from matplotlib import pyplot as plt
    from fsl_mrs.core import MRS
    import plotly.graph_objects as go
    from fsl_mrs.utils.preproc.reporting import plotStyles, plotAxesStyle

    # Turn input FIDs into mrs objects
    toMRSobj = lambda fid: MRS(FID=fid, header=hdr)
    plotIn = toMRSobj(inFID)
    plotOut = toMRSobj(outFID)

    # Fetch line styles
    lines, colors, _ = plotStyles()

    # Make a new figure
    fig = go.Figure()

    # Add lines to figure
    def addline(fig, mrs, lim, name, linestyle):
        trace = go.Scatter(x=mrs.getAxes(ppmlim=lim),
                           y=np.real(mrs.getSpectrum(ppmlim=lim)),
                           mode='lines',
                           name=name,
                           line=linestyle)
        return fig.add_trace(trace)

    fig = addline(fig, plotIn, plotlim, 'Uncorrected', lines['in'])
    fig = addline(fig, plotOut, plotlim, 'Corrected', lines['out'])

    # Axes layout
    plotAxesStyle(fig, plotlim, title='Apodization summary')

    # Generate report
    if html is not None:
        from plotly.offline import plot
        from fsl_mrs.utils.preproc.reporting import figgroup, singleReport
        from datetime import datetime
        import os.path as op

        if op.isdir(html):
            filename = 'report_' + datetime.now().strftime(
                "%Y%m%d_%H%M%S%f")[:-3] + '.html'
            htmlfile = op.join(html, filename)
        elif op.isdir(op.dirname(html)) and op.splitext(html)[1] == '.html':
            htmlfile = html
        else:
            raise ValueError('Report html path must be file or directory. ')

        opName = 'Apodization'
        timestr = datetime.now().strftime("%H:%M:%S")
        datestr = datetime.now().strftime("%d/%m/%Y")
        headerinfo = 'Report for fsl_mrs.utils.preproc.filtering.apodize.\n'\
                    + f'Generated at {timestr} on {datestr}.'
        # Figures
        div = plot(fig, output_type='div', include_plotlyjs='cdn')
        figurelist = [
            figgroup(fig=div,
                     name='',
                     foretext=f'Apodization of spectra.',
                     afttext=f'')
        ]

        singleReport(htmlfile, opName, headerinfo, figurelist)
        return fig
    else:
        return fig
Exemple #16
0
def combine_FIDs_report(inFIDs,
                        outFID,
                        hdr,
                        ncha=2,
                        ppmlim=(0.0, 6.0),
                        method='not specified',
                        html=None):
    """ Take list of FIDs that are passed to combine and output

    If uncombined data it will display ncha channels (default 2).
    """
    from fsl_mrs.core import MRS
    import plotly.graph_objects as go
    from fsl_mrs.utils.preproc.reporting import plotStyles, plotAxesStyle
    from matplotlib.pyplot import cm
    toMRSobj = lambda fid: MRS(FID=fid, header=hdr)

    # Assemble data to plot
    toPlotIn = []
    colourVecIn = []
    legendIn = []
    if isinstance(inFIDs, list):
        for idx, fid in enumerate(inFIDs):
            if inFIDs[0].ndim > 1:
                toPlotIn.extend([toMRSobj(f) for f in fid[:, :ncha].T])
                colourVecIn.extend([idx / len(inFIDs)] * ncha)
                legendIn.extend(
                    [f'FID #{idx}: CHA #{jdx}' for jdx in range(ncha)])
            else:
                toPlotIn.append(toMRSobj(fid))
                colourVecIn.append(idx / len(inFIDs))
                legendIn.append(f'FID #{idx}')

    elif inFIDs.ndim > 1:
        toPlotIn.extend([toMRSobj(f) for f in inFIDs[:, :ncha].T])
        colourVecIn.extend([float(jdx) / ncha for jdx in range(ncha)])
        legendIn.extend([f'FID #0: CHA #{jdx}' for jdx in range(ncha)])

    toPlotOut = []
    legendOut = []
    if outFID.ndim > 1:
        toPlotOut.extend([toMRSobj(f) for f in outFID[:, :ncha].T])
        legendOut.extend([f'Combined: CHA #{jdx}' for jdx in range(ncha)])
    else:
        toPlotOut.append(toMRSobj(outFID))
        legendOut.append('Combined')

    def addline(fig, mrs, lim, name, linestyle):
        trace = go.Scatter(x=mrs.getAxes(ppmlim=lim),
                           y=np.real(mrs.getSpectrum(ppmlim=lim)),
                           mode='lines',
                           name=name,
                           line=linestyle)
        return fig.add_trace(trace)

    lines, colors, _ = plotStyles()
    colors = cm.Spectral(np.array(colourVecIn).ravel())

    fig = go.Figure()
    for idx, fid in enumerate(toPlotIn):
        cval = np.round(255 * colors[idx, :])
        linetmp = {'color': f'rgb({cval[0]},{cval[1]},{cval[2]})', 'width': 1}
        fig = addline(fig, fid, ppmlim, legendIn[idx], linetmp)

    for idx, fid in enumerate(toPlotOut):
        fig = addline(fig, fid, ppmlim, legendOut[idx], lines['blk'])
    plotAxesStyle(fig, ppmlim, 'Combined')

    # Generate report
    if html is not None:
        from plotly.offline import plot
        from fsl_mrs.utils.preproc.reporting import figgroup, singleReport
        from datetime import datetime
        import os.path as op

        if op.isdir(html):
            filename = 'report_' + datetime.now().strftime(
                "%Y%m%d_%H%M%S%f")[:-3] + '.html'
            htmlfile = op.join(html, filename)
        elif op.isdir(op.dirname(html)) and op.splitext(html)[1] == '.html':
            htmlfile = html
        else:
            raise ValueError('Report html path must be file or directory. ')

        opName = 'Combination'
        timestr = datetime.now().strftime("%H:%M:%S")
        datestr = datetime.now().strftime("%d/%m/%Y")
        headerinfo = 'Report for fsl_mrs.utils.preproc.combine.combine_FIDs.\n'\
                    + f'Generated at {timestr} on {datestr}.'
        # Figures
        div = plot(fig, output_type='div', include_plotlyjs='cdn')
        figurelist = [
            figgroup(fig=div,
                     name='',
                     foretext=f'Combination of spectra. Method = {method}',
                     afttext=f'')
        ]

        singleReport(htmlfile, opName, headerinfo, figurelist)
        return fig
    else:
        return fig
Exemple #17
0
def shift_report(inFID,
                 outFID,
                 inHdr,
                 outHdr,
                 ppmlim=(0.2, 4.2),
                 html=None,
                 function='shift'):
    """
    Generate report
    """
    import plotly.graph_objects as go
    from plotly.subplots import make_subplots
    from fsl_mrs.utils.preproc.reporting import plotStyles, plotAxesStyle

    plotIn = MRS(FID=inFID, header=inHdr)
    plotOut = MRS(FID=outFID, header=outHdr)

    # Fetch line styles
    lines, colors, _ = plotStyles()

    # Make a new figure
    fig = make_subplots(rows=1, cols=2, subplot_titles=['Spectra', 'FID'])

    # Add lines to figure
    trace1 = go.Scatter(x=plotIn.getAxes(ppmlim=ppmlim),
                        y=np.real(plotIn.getSpectrum(ppmlim=ppmlim)),
                        mode='lines',
                        name='Original',
                        line=lines['in'])
    trace2 = go.Scatter(x=plotOut.getAxes(ppmlim=ppmlim),
                        y=np.real(plotOut.getSpectrum(ppmlim=ppmlim)),
                        mode='lines',
                        name='Shifted',
                        line=lines['out'])
    fig.add_trace(trace1, row=1, col=1)
    fig.add_trace(trace2, row=1, col=1)

    # Add lines to figure
    trace3 = go.Scatter(x=plotIn.getAxes(axis='time'),
                        y=np.real(plotIn.FID),
                        mode='lines',
                        name='Original',
                        line=lines['emph'])
    trace4 = go.Scatter(x=plotOut.getAxes(axis='time'),
                        y=np.real(plotOut.FID),
                        mode='lines',
                        name='Shifted',
                        line=lines['diff'])
    fig.add_trace(trace3, row=1, col=2)
    fig.add_trace(trace4, row=1, col=2)

    # Axes layout
    plotAxesStyle(fig, ppmlim, title='Shift summary')
    fig.layout.xaxis2.update(title_text='Time (s)')
    fig.layout.yaxis2.update(zeroline=True,
                             zerolinewidth=1,
                             zerolinecolor='Gray',
                             showgrid=False,
                             showticklabels=False)

    if html is not None:
        from plotly.offline import plot
        from fsl_mrs.utils.preproc.reporting import figgroup, singleReport
        from datetime import datetime
        import os.path as op

        if op.isdir(html):
            filename = 'report_' + datetime.now().strftime(
                "%Y%m%d_%H%M%S%f")[:-3] + '.html'
            htmlfile = op.join(html, filename)
        elif op.isdir(op.dirname(html)) and op.splitext(html)[1] == '.html':
            htmlfile = html
        else:
            raise ValueError('Report html path must be file or directory. ')

        operation, function, description = reportStrings(function)

        opName = operation
        timestr = datetime.now().strftime("%H:%M:%S")
        datestr = datetime.now().strftime("%d/%m/%Y")
        headerinfo = f'Report for fsl_mrs.utils.preproc.shifting.{function}.\n'\
                    + f'Generated at {timestr} on {datestr}.'
        # Figures
        div = plot(fig, output_type='div', include_plotlyjs='cdn')
        figurelist = [
            figgroup(fig=div, name='', foretext=f'{description}', afttext=f'')
        ]

        singleReport(htmlfile, opName, headerinfo, figurelist)
        return fig
    else:
        return fig
Exemple #18
0
def phaseCorrect_report(inFID,
                        outFID,
                        hdr,
                        position,
                        ppmlim=(2.8, 3.2),
                        html=None):
    """
    Generate report for phaseCorrect
    """
    # from matplotlib import pyplot as plt
    from fsl_mrs.core import MRS
    import plotly.graph_objects as go
    from fsl_mrs.utils.preproc.reporting import plotStyles, plotAxesStyle

    # Turn input FIDs into mrs objects
    toMRSobj = lambda fid: MRS(FID=fid, header=hdr)
    plotIn = toMRSobj(inFID)
    plotOut = toMRSobj(outFID)

    widelimit = (0, 6)

    # Fetch line styles
    lines, colors, _ = plotStyles()

    # Make a new figure
    fig = go.Figure()

    # Add lines to figure
    def addline(fig, mrs, lim, name, linestyle):
        trace = go.Scatter(x=mrs.getAxes(ppmlim=lim),
                           y=np.real(mrs.getSpectrum(ppmlim=lim)),
                           mode='lines',
                           name=name,
                           line=linestyle)
        return fig.add_trace(trace)

    fig = addline(fig, plotIn, widelimit, 'Unphased', lines['in'])
    fig = addline(fig, plotIn, ppmlim, 'Search region', lines['emph'])

    if position is None:
        # re-estimate here.
        position = np.argmax(np.abs(plotIn.getSpectrum(ppmlim=ppmlim)))

    axis = [plotIn.getAxes(ppmlim=ppmlim)[position]]
    y_data = [np.real(plotIn.getSpectrum(ppmlim=ppmlim))[position]]
    trace = go.Scatter(x=axis,
                       y=y_data,
                       mode='markers',
                       name='max point',
                       marker=dict(color=colors['emph'], symbol='x', size=8))
    fig.add_trace(trace)

    fig = addline(fig, plotOut, widelimit, 'Phased', lines['out'])

    # Axes layout
    plotAxesStyle(fig, widelimit, title='Phase correction summary')

    # Axes
    if html is not None:
        from plotly.offline import plot
        from fsl_mrs.utils.preproc.reporting import figgroup, singleReport
        from datetime import datetime
        import os.path as op

        if op.isdir(html):
            filename = 'report_' + datetime.now().strftime(
                "%Y%m%d_%H%M%S%f")[:-3] + '.html'
            htmlfile = op.join(html, filename)
        elif op.isdir(op.dirname(html)) and op.splitext(html)[1] == '.html':
            htmlfile = html
        else:
            raise ValueError('Report html path must be file or directory. ')

        opName = 'Phase correction'
        timestr = datetime.now().strftime("%H:%M:%S")
        datestr = datetime.now().strftime("%d/%m/%Y")
        headerinfo = 'Report for fsl_mrs.utils.preproc.phasing.phaseCorrect.\n'\
                    + f'Generated at {timestr} on {datestr}.'
        # Figures
        div = plot(fig, output_type='div', include_plotlyjs='cdn')
        figurelist = [
            figgroup(
                fig=div,
                name='',
                foretext=
                f'Phase correction of spectra based on maximum in the range {ppmlim[0]} to {ppmlim[1]} ppm.',
                afttext=f'')
        ]

        singleReport(htmlfile, opName, headerinfo, figurelist)
        return fig
    else:
        return fig
Exemple #19
0
 def toMRSobj(fid):
     return MRS(FID=fid, header=hdr)
Exemple #20
0
def identifyUnlikeFIDs_report(goodFIDs,badFIDs,hdr,keepIndicies,rmIndicies,metric,ppmlim=(0.2,4.2),sdlimit = 1.96,html=None):
    from fsl_mrs.utils.preproc.combine import combine_FIDs
    import plotly.graph_objects as go    
    from fsl_mrs.utils.preproc.reporting import plotStyles,plotAxesStyle

    metricGd = np.array(metric)[keepIndicies]
    metricBd = np.array(metric)[rmIndicies]    
    metric_avg = np.mean(metric)
    metric_std = np.std(metric)

    metricGd_SD = np.abs(metricGd-metric_avg)/metric_std
    metricBd_SD = np.abs(metricBd-metric_avg)/metric_std

    gdIndex = np.argsort(metricGd_SD)
    bdIndex = np.argsort(metricBd_SD)



    plotGood,plotBad = [],[]
    gdLegend,bdLegend = [],[]
    toMRSobj = lambda fid : MRS(FID=fid,header=hdr)    

    for idx in gdIndex:
        fid = goodFIDs[idx]
        plotGood.append(toMRSobj(fid))
        gdLegend.append(f'Kept (SD={metricGd_SD[idx]:0.2f})')
    for idx in bdIndex:
        fid = badFIDs[idx]
        plotBad.append(toMRSobj(fid))
        bdLegend.append(f'Removed (SD={metricBd_SD[idx]:0.2f})')
        
    target = get_target_FID(goodFIDs,target='median')
    tgtmrs = toMRSobj(target)

    # Fetch line styles
    lines,colors,_ = plotStyles()
    # Make a new figure
    fig = go.Figure()

    # Add lines to figure
    def addline(fig,mrs,lim,name,linestyle):
        trace = go.Scatter(x=mrs.getAxes(ppmlim=lim),
                        y=np.real(mrs.getSpectrum(ppmlim=lim)),
                        mode='lines',
                        name=name,
                        line=linestyle)
        return fig.add_trace(trace)    
    for fid,leg in zip(plotGood,gdLegend):        
        fig = addline(fig,fid,ppmlim,leg,lines['out'])
    for fid,leg in zip(plotBad,bdLegend):        
        fig = addline(fig,fid,ppmlim,leg,lines['emph'])    
    fig = addline(fig,tgtmrs,ppmlim,'Target',lines['blk']) 
    
    plotAxesStyle(fig,ppmlim,title = 'Bad average removal summary')

    # Generate report 
    if html is not None:
        from plotly.offline import plot
        from fsl_mrs.utils.preproc.reporting import figgroup, singleReport
        from datetime import datetime
        import os.path as op

        if op.isdir(html):
            filename = 'report_' + datetime.now().strftime("%Y%m%d_%H%M%S%f")[:-3]+'.html'
            htmlfile=op.join(html,filename)
        elif op.isdir(op.dirname(html)) and op.splitext(html)[1]=='.html':
            htmlfile = html
        else:
            raise ValueError('Report html path must be file or directory. ')
        
        opName = 'BadAverageRemoval'
        timestr = datetime.now().strftime("%H:%M:%S")
        datestr = datetime.now().strftime("%d/%m/%Y")
        headerinfo = 'Report for fsl_mrs.utils.preproc.unlike.identifyUnlikeFIDs.\n'\
                    + f'Generated at {timestr} on {datestr}.'        
        # Figures
        div = plot(fig, output_type='div',include_plotlyjs='cdn')
        figurelist = [figgroup(fig = div,
                            name= '',
                            foretext= f'Identification of FIDs unlike others. SD limit = {sdlimit:0.2f}',
                            afttext= f'')]

        singleReport(htmlfile,opName,headerinfo,figurelist)
        return fig
    else:
        return fig
Exemple #21
0
def phase_freq_align(FIDlist,
                     bandwidth,
                     centralFrequency,
                     ppmlim=None,
                     niter=2,
                     apodize=10,
                     verbose=False,
                     shift=True,
                     target=None):
    """
    Algorithm:
       Average spectra
       Loop over all spectra and find best phase/frequency shifts
       Iterate

    TODO: 
       test the code
       add dedrifting?

    Parameters:
    -----------
    FIDlist          : list
    bandwidth        : float (unit=Hz)
    centralFrequency : float (unit=Hz)
    ppmlim           : tuple
    niter            : int
    apodize          : float (unit=Hz)
    verbose          : bool
    shift            : apply H20 shift to ppm limit
    ref              : reference data to align to
    
    Returns:
    --------
    list of FID aligned to each other
    """
    all_FIDs = FIDlist.copy()

    phiOut, epsOut = np.zeros(len(FIDlist)), np.zeros(len(FIDlist))
    for iter in range(niter):
        if verbose:
            print(' ---- iteration {} ----\n'.format(iter))

        if target is None:
            target = get_target_FID(all_FIDs, target='nearest_to_mean')

        MRSargs = {'FID': target, 'bw': bandwidth, 'cf': centralFrequency}
        mrs = MRS(**MRSargs)

        if apodize > 0:
            target = apod(target, mrs.dwellTime, [apodize])

        for idx, FID in enumerate(all_FIDs):
            if verbose:
                print(f'... aligning FID number {idx}\r')

            if apodize > 0:
                FID_apod = apod(FID.copy(), mrs.dwellTime, [apodize])
            else:
                FID_apod = FID

            phi, eps = align_FID(mrs,
                                 FID_apod,
                                 target,
                                 ppmlim=ppmlim,
                                 shift=shift)

            all_FIDs[idx] = np.exp(-1j * phi) * shift_FID(mrs, FID, eps)
            phiOut[idx] += phi
            epsOut[idx] += eps
        if verbose:
            print('\n')
    return all_FIDs, phiOut, epsOut
Exemple #22
0
def phase_freq_align_diff_report(inFIDs0,
                                 inFIDs1,
                                 outFIDs0,
                                 outFIDs1,
                                 hdr,
                                 eps,
                                 phi,
                                 ppmlim=None,
                                 diffType='add',
                                 shift=True,
                                 html=None):
    from fsl_mrs.utils.preproc.combine import combine_FIDs
    import plotly.graph_objects as go
    from fsl_mrs.utils.preproc.reporting import plotStyles, plotAxesStyle
    from plotly.subplots import make_subplots

    # Fetch line styles
    lines, _, _ = plotStyles()

    # Make a new figure
    fig = make_subplots(rows=1, cols=2, subplot_titles=['Phase', 'Shift'])

    trace1 = go.Scatter(x=np.arange(1,
                                    len(phi) + 1),
                        y=np.array(phi) * (180.0 / np.pi),
                        mode='lines',
                        name='Phase',
                        line=lines['out'])
    fig.add_trace(trace1, row=1, col=1)
    fig.layout.xaxis.update(title_text='Transient #')
    fig.layout.yaxis.update(title_text=r'$\phi$ (degrees)')

    trace2 = go.Scatter(x=np.arange(1,
                                    len(eps) + 1),
                        y=eps,
                        mode='lines',
                        name='Shift',
                        line=lines['diff'])
    fig.add_trace(trace2, row=1, col=2)
    fig.layout.yaxis2.update(title_text='Shift (Hz)')
    fig.layout.xaxis2.update(title_text='Transient #')

    diffFIDListIn = []
    diffFIDListOut = []
    for fid0i, fid1i, fid0o, fid1o in zip(inFIDs0, inFIDs1, outFIDs0,
                                          outFIDs1):
        if diffType.lower() == 'add':
            diffFIDListIn.append(add(fid1i, fid0i))
            diffFIDListOut.append(add(fid1o, fid0o))
        elif diffType.lower() == 'sub':
            diffFIDListIn.append(subtract(fid1i, fid0i))
            diffFIDListOut.append(subtract(fid1o, fid0o))
        else:
            raise ValueError('diffType must be add or sub.')

    meanIn = combine_FIDs(diffFIDListIn, 'mean')
    meanOut = combine_FIDs(diffFIDListOut, 'mean')
    toMRSobj = lambda fid: MRS(FID=fid, header=hdr)
    meanIn = toMRSobj(meanIn)
    meanOut = toMRSobj(meanOut)

    if shift:
        axis = 'ppmshift'
    else:
        axis = 'ppm'

    toPlotIn, toPlotOut = [], []
    for fid in diffFIDListIn:
        toPlotIn.append(toMRSobj(fid))
    for fid in diffFIDListOut:
        toPlotOut.append(toMRSobj(fid))

    def addline(fig, mrs, lim, name, linestyle):
        trace = go.Scatter(x=mrs.getAxes(ppmlim=lim, axis=axis),
                           y=np.real(mrs.getSpectrum(ppmlim=lim, shift=shift)),
                           mode='lines',
                           name=name,
                           line=linestyle)
        return fig.add_trace(trace)

    fig2 = go.Figure()
    for idx, fid in enumerate(toPlotIn):
        cval = np.round(255 * idx / len(toPlotIn))
        linetmp = {'color': f'rgb(0,{cval},{cval})', 'width': 1}
        fig2 = addline(fig2, fid, ppmlim, f'#{idx}', linetmp)
    fig2 = addline(fig2, meanIn, ppmlim, f'Mean - Unligned', lines['blk'])
    plotAxesStyle(fig2, ppmlim, 'Unaligned')

    fig3 = go.Figure()
    for idx, fid in enumerate(toPlotOut):
        cval = np.round(255 * idx / len(toPlotIn))
        linetmp = {'color': f'rgb(0,{cval},{cval})', 'width': 1}
        fig3 = addline(fig3, fid, ppmlim, f'#{idx}', linetmp)
    fig3 = addline(fig3, meanIn, ppmlim, f'Mean - Unligned', lines['out'])
    fig3 = addline(fig3, meanOut, ppmlim, f'Mean - Aligned', lines['blk'])
    plotAxesStyle(fig3, ppmlim, 'Aligned')

    if html is not None:
        from plotly.offline import plot
        from fsl_mrs.utils.preproc.reporting import figgroup, singleReport
        from datetime import datetime
        import os.path as op

        if op.isdir(html):
            filename = 'report_' + datetime.now().strftime(
                "%Y%m%d_%H%M%S%f")[:-3] + '.html'
            htmlfile = op.join(html, filename)
        elif op.isdir(op.dirname(html)) and op.splitext(html)[1] == '.html':
            htmlfile = html
        else:
            raise ValueError('Report html path must be file or directory. ')

        opName = 'AlignDiff'
        timestr = datetime.now().strftime("%H:%M:%S")
        datestr = datetime.now().strftime("%d/%m/%Y")
        headerinfo = 'Report for fsl_mrs.utils.align.phase_freq_align_diff.\n'\
                    + f'Generated at {timestr} on {datestr}.'
        # Figures
        div = plot(fig, output_type='div', include_plotlyjs='cdn')
        figurelist = [
            figgroup(fig=div,
                     name='',
                     foretext=f'Alignment parameters.',
                     afttext=f'')
        ]
        div2 = plot(fig2, output_type='div', include_plotlyjs='cdn')
        figurelist.append(
            figgroup(fig=div2,
                     name='',
                     foretext=f'Transients before alignment.',
                     afttext=f''))
        div3 = plot(fig3, output_type='div', include_plotlyjs='cdn')
        figurelist.append(
            figgroup(fig=div3,
                     name='',
                     foretext=f'Transients after alignment.',
                     afttext=f''))

        singleReport(htmlfile, opName, headerinfo, figurelist)
        return fig, fig2, fig3
    else:
        return fig, fig2, fig3
Exemple #23
0
def test_calcQC():
    # Syntetic data
    synFID, synHdr = syntheticFID(noisecovariance=[[0.1]],
                                  points=2 * 2048,
                                  chemicalshift=[0],
                                  amplitude=[6.0],
                                  linewidth=[10])
    synFIDNoise, synHdrNoise = syntheticFID(noisecovariance=[[0.1]],
                                            points=2 * 2048,
                                            chemicalshift=[0],
                                            amplitude=[0],
                                            linewidth=[10])
    basisFID, basisHdr = syntheticFID(noisecovariance=[[0.0]],
                                      points=2 * 2048,
                                      chemicalshift=[0],
                                      amplitude=[0.1],
                                      linewidth=[2])

    synMRS = MRS(FID=synFID[0], header=synHdr)
    synMRSNoise = MRS(FID=synFIDNoise[0], header=synHdrNoise)
    synMRSNoNoise = MRS(FID=synHdr['noiseless'], header=synHdr)
    synMRS_basis = MRS(FID=synFID[0],
                       header=synHdr,
                       basis=basisFID[0],
                       basis_hdr=basisHdr,
                       names=['Peak1'])

    truenoiseSD = np.sqrt(synHdrNoise['cov'][0, 0])
    pureNoiseMeasured = np.std(synMRSNoise.getSpectrum())
    realnoise = np.std(np.real(synMRSNoise.getSpectrum()))
    imagNoise = np.std(np.imag(synMRSNoise.getSpectrum()))
    print(
        f'True cmplx noise = {truenoiseSD:0.3f}, pure noise measured = {pureNoiseMeasured:0.3f} (real/imag = {realnoise:0.3f}/{imagNoise:0.3f})'
    )

    # Calc SNR without apodisation from the no noise and pure noise spectra
    truePeakHeight = np.max(np.real(synMRSNoNoise.getSpectrum()))
    SNR_noApod = truePeakHeight / pureNoiseMeasured
    print(
        f'SNR no apod: {SNR_noApod:0.1f} ({truePeakHeight:0.2e}/{pureNoiseMeasured:0.2e})'
    )

    # Calc SNR with apodisation from the no noise and pure noise spectra
    trueLW = synHdr['inputopts']['linewidth'][0]
    trueApodSpec_Noise = specApodise(synMRSNoise, trueLW)
    apodNoise = np.std(trueApodSpec_Noise)
    trueApodSpec_noNoise = specApodise(synMRSNoNoise, trueLW)
    peakHeigtApod = np.max(np.real(trueApodSpec_noNoise))
    SNR = peakHeigtApod / apodNoise
    print(f'SNR w. apod: {SNR:0.1f} ({peakHeigtApod:0.2e}/{apodNoise:0.2e})')

    metab_groups = [0]
    Fitargs = {
        'ppmlim': [2.65, 6.65],
        'method': 'Newton',
        'baseline_order': -1,
        'metab_groups': [0]
    }

    res = fit_FSLModel(synMRS_basis, **Fitargs)
    fwhm_test, SNRObj = calcQC(synMRS_basis, res, ppmlim=[2.65, 6.65])
    print(f'Measured FWHM: {fwhm_test.mean().to_numpy()[0]:0.1f}')
    print(f'Measured spec SNR: {SNRObj.spectrum:0.1f}')
    print(f'Measured peak SNR: {SNRObj.peaks.mean().to_numpy()[0]:0.1f}')
    assert np.isclose(fwhm_test.mean().to_numpy(), trueLW, atol=1E0)
    assert np.isclose(SNRObj.spectrum, SNR_noApod, atol=1E1)
    assert np.isclose(SNRObj.peaks.mean().to_numpy(), SNR, atol=2E1)