Commit dea06f07 authored by William Clarke's avatar William Clarke
Browse files

Remove mrs_info and mrs_vis. Update documentation. Add documentation for mrs_tools.

parent f32c10dc
This document contains the FSL-MRS release history in reverse chronological order.
1.1.3 (TBC)
------------------------------
- Added mrs_tools script. Replaces mrs_vis and mrs_info. Adds split/merge/reorder functionality.
1.1.2 (Friday 16th April 2021)
------------------------------
- Added 2H information
......
......@@ -51,10 +51,8 @@ After installation see the [quick start guide](https://open.win.ox.ac.uk/pages/f
: Pre-packaged processing for non-edited SVS.
- **fsl\_mrs\_sim**
: simulate basis spectra
- **mrs_vis**
: quick visualisation of the spectra or basis spectra
- **mrs_info**
: quick information on a NIfTI-MRS file
- **mrs_tools**
: Collection of tools for NIfTI-MRS. Includes quick visualisation and information.
- **svs_segment & mrsi_segment**
: Run tissue segmentation for SVS/MRSI from T1 image.
......
Manipulating MRS Data
=====================
Handling NIfTI-MRS
------------------
MRS data stored in NIfTI-MRS format can contain multiple higher dimensions. For example it might contain dimensions encoding multiple receive coils, multiple temporal averages, or even a spectral editing dimension.
Data might need to be manipulated within the NIfTI-MRS storage framework before, after, or during preprocessing. For this, FLS-MRS provides the :code:`mrs_tools` command line script. :code:`mrs_tools` has the ability to merge and split NIfTI-MRS files along the higher encoding dimensions. It can also reorder the higher dimensions, or create a new singleton dimension for further manipulation.
:code:`mrs_tools` also contains the :code:`mrs_tools vis` and :code:`mrs_tools info` options to provide quick visualisation and information on the command line. See the :ref:`Visualisation <visualisation>` page for more information on :code:`mrs_tools vis/info`.
:code:`mrs_tools split` takes a single file and splits it along a specified dimension e.g. :code:`--dim DIM_DYN`, at a single point (:code:`--index 8`) or extracting multiple elements into a second file (:code:`--indices 8 9 10`).
:code:`mrs_tools merge` takes two or more files and merges them along a specified dimension e.g. :code:`--dim DIM_EDIT`.
:code:`mrs_tools reorder` permutes the dimensions of an existing NIfTI-MRS file. For example, the 5th through 7th dimensions can be changed from :code:`DIM_COIL, DIM_DYN, DIM_EDIT` to :code:`DIM_DYN, DIM_EDIT, DIM_COIL` using :code:`--dim_order DIM_DYN DIM_EDIT DIM_COIL`.
\ No newline at end of file
......@@ -19,6 +19,7 @@ If this is your first experience with FSL-MRS, get started with the :ref:`Quick
install
quick_start
data_conversion
data_handling
processing
fitting
quantitation
......
......@@ -34,9 +34,9 @@ But note that there are frequently multiple calibration scans for e.g. shimming
1.1 Take a look at your data
^^^^^^^^^^^^^^^^^^^^^^^^^^^^
You can use :code:`mrs_info` and :code:`mrs_vis` on the command line to view your data at any stage of the process. First mrs_info to see the dimensionality of the data::
You can use :code:`mrs_tools info` and :code:`mrs_tools vis` on the command line to view your data at any stage of the process. First :code:`mrs_tools info` to see the dimensionality of the data::
mrs_info my_metab_file.nii.gz
mrs_tools info my_metab_file.nii.gz
Read file my_metab_file.nii.gz (/path_to_file).
NIfTI-MRS version 0.2
......@@ -47,25 +47,25 @@ You can use :code:`mrs_info` and :code:`mrs_vis` on the command line to view you
Nucleus: 1H
Field Strength: 6.98 T
Then mrs_vis to visualise the data::
Then :code:`mrs_tools vis` to visualise the data::
mrs_vis my_metab_file.nii.gz
mrs_tools vis my_metab_file.nii.gz
:code:`mrs_vis` will automatically perform coil combination and averaging down to a single spectrum for display purposes only.
:code:`mrs_tools vis` will automatically perform coil combination and averaging down to a single spectrum for display purposes only.
.. image:: data/raw_conv.png
:width: 600
You can also quickly view data across one of the NIfTI-MRS higher dimensions (those containing uncombined coils, or averages etc.) In this case we plot all the transients stored in the dimension tagged *DIM_DYN* (i.e. averages)::
mrs_vis my_metab_file.nii.gz --display_dim DIM_DYN
mrs_tools vis my_metab_file.nii.gz --display_dim DIM_DYN
.. image:: data/mrs_vis_dir.png
:width: 600
If you see a significantly different picture (no data, just noise, etc.) stop and investigate. See :ref:`Troubleshooting <TS_4>`.
Have a look at the :ref:`Visualisation <visualisation>` page for more information on :code:`mrs_vis`.
Have a look at the :ref:`Visualisation <visualisation>` page for more information on :code:`mrs_tools vis`.
2. Process your raw data
~~~~~~~~~~~~~~~~~~~~~~~~
......@@ -101,9 +101,9 @@ The fitting in FSL-MRS requires the user to provide basis spectra. Basis spectra
`my_sequence_description.json` contains a description of the sequence broken down into blocks of RF pulses and gradients. This must be created for each sequence manually once. `metabs.txt` contains a list of metabolites to simulate. Much more information on constructing a suitable sequence description JSON file can be found on the :ref:`Basis Spectra Simulation <simulation>` page.
Have a quick check of your basis set using mrs_vis::
Have a quick check of your basis set using :code:`mrs_tools vis`::
mrs_vis my_basis_spectra/
mrs_tools vis my_basis_spectra/
4. Tissue Segmentation
~~~~~~~~~~~~~~~~~~~~~~
......
......@@ -31,7 +31,7 @@ Troubleshooting hints
.. _TS_4:
4. Data looks 'wrong' after conversion
If when using :code:`mrs_vis` you see no signal and just noise try conjugating the data using :code:`fsl_mrs_proc conj` or try expanding the ppm range plotted :code:`--ppmlim -10 10`. If you see a flat line, then conversion failed. The data might be corrupted - did the acquisition complete successfully?
If when using :code:`mrs_tools vis` you see no signal and just noise try conjugating the data using :code:`fsl_mrs_proc conj` or try expanding the ppm range plotted :code:`--ppmlim -10 10`. If you see a flat line, then conversion failed. The data might be corrupted - did the acquisition complete successfully?
.. image:: data/bad_data.png
:width: 600
\ No newline at end of file
......@@ -15,32 +15,32 @@ There are 4 ways of visualising/interacting with MRS data in FSL-MRS:
1. Quick glance
---------------
The first thing one might want to do when given a FID file or simulated spectra is to have a quick look at the spectra to see if they look like one would expect. To get a sense of the dimensionality and basic status of the data run :code:`mrs_info` for a quick text summary. FSL-MRS then provides a light-weight script (:code:`mrs_vis`) to quickly visualise the MRS or MRSI data. For example, running :code:`mrs_vis` on the provided example SVS data:
The first thing one might want to do when given a FID file or simulated spectra is to have a quick look at the spectra to see if they look like one would expect. To get a sense of the dimensionality and basic status of the data run :code:`mrs_tools info` for a quick text summary. FSL-MRS then provides a light-weight script (:code:`mrs_tools vis`) to quickly visualise the MRS or MRSI data. For example, running :code:`mrs_tools vis` on the provided example SVS data:
::
mrs_vis example_usage/example_data/metab.nii
mrs_tools vis example_usage/example_data/metab.nii
gives the following basic plot:
.. image:: data/mrs_vis_svs.png
:width: 400
Note that the reason :code:`mrs_vis` "knows" how to scale the x-axis is that the relevant information is stored in the NIfTI-MRS MRS header extension (namely the *dwell time* and the *central frequency*).
Note that the reason :code:`mrs_tools vis` "knows" how to scale the x-axis is that the relevant information is stored in the NIfTI-MRS MRS header extension (namely the *dwell time* and the *central frequency*).
:code:`mrs_vis` can also visualise a folder of mrs data::
:code:`mrs_tools vis` can also visualise a folder of mrs data::
mrs_vis ./converted_data_dir/
mrs_tools vis ./converted_data_dir/
.. image:: data/mrs_vis_dir.png
:width: 600
We can also run :code:`mrs_vis` to visualise the metabolite basis. Again below we do so for the simulated basis provided with the example data:
We can also run :code:`mrs_tools vis` to visualise the metabolite basis. Again below we do so for the simulated basis provided with the example data:
::
mrs_vis example_usage/example_data/steam_11ms/
mrs_tools vis example_usage/example_data/steam_11ms/
.. image:: data/mrs_vis_basis.png
......
%% Cell type:markdown id: tags:
# Example basis spectra creation
This notebook demos the process of creating basis spectra for fitting in FSL-MRS.
### Contents:
- [1. Sequence JSON file](#1.-Sequence-JSON-file)
- [1.1. Defining MM](#1.1-Defining-MM)
- [2. Simulation](#2.-Simulation)
- [3. Visualisation](#3.-Visualisation)
Will Clarke
June 2020
University of Oxford
%% Cell type:markdown id: tags:
## 1. Sequence JSON file
%% Cell type:markdown id: tags:
The sequence to simulate and the system parameters are descibed in a json file. The file breaks the sequence into a series of RF pulses (+ slice selcect gradients) and delays with optional rephasing gradients. A coherence filter is used to crush unwanted coherences.
%% Cell type:markdown id: tags:
## 1.1 Defining MM
An experimentally measured (or otherwise derived) macromollecues basis spectrum can be included in the basis spectrum by defining an additional JSON file.
%% Cell type:markdown id: tags:
## 2. Simulation
%% Cell type:code id: tags:
``` python
%sx fsl_mrs_sim -b example_data/metabs.txt \
-o steam_basis \
-p -2.66 \
--MM example_data/macSeed.json \
--overwrite \
-e 11.0 \
example_data/steam11.json
```
%%%% Output: execute_result
["Identified spinsystems: ['Ala', 'Asc', 'Asp', 'GPC', 'PCh', 'Cr', 'PCr', 'GABA', 'Glc', 'Gln', 'Glu', 'GSH', 'Ins', 'Lac', 'NAA', 'NAAG', 'PE', 'Scyllo', 'Tau']",
'Simulation running using mode 1d. Axis order = [0 1 2].',
'Auto-phase adjustment. Phasing peak position = 1.99 ppm',
'Rx_Phase: 2.3408',
'Additional phase: 0.059',
'Final Rx_Phase: 2.400',
'Running simulation on Asc.',
'Simulation running using mode 1d. Axis order = [0 1 2].',
'Running simulation on Glu.',
'Simulation running using mode 1d. Axis order = [0 1 2].',
'Running simulation on NAA.',
'Simulation running using mode 1d. Axis order = [0 1 2].',
'Simulation running using mode 1d. Axis order = [0 1 2].',
'Running simulation on PCr.',
'Simulation running using mode 1d. Axis order = [0 1 2].',
'Simulation running using mode 1d. Axis order = [0 1 2].',
'Running simulation on GSH.',
'Simulation running using mode 1d. Axis order = [0 1 2].',
'Simulation running using mode 1d. Axis order = [0 1 2].',
'Simulation running using mode 1d. Axis order = [0 1 2].',
'Running simulation on GABA.',
'Simulation running using mode 1d. Axis order = [0 1 2].',
'Running simulation on Lac.',
'Simulation running using mode 1d. Axis order = [0 1 2].',
'Running simulation on Scyllo.',
'Simulation running using mode 1d. Axis order = [0 1 2].',
'Running simulation on Tau.',
'Simulation running using mode 1d. Axis order = [0 1 2].',
'Running simulation on Cr.',
'Simulation running using mode 1d. Axis order = [0 1 2].',
'Running simulation on Ins.',
'Simulation running using mode 1d. Axis order = [0 1 2].',
'Running simulation on Ala.',
'Simulation running using mode 1d. Axis order = [0 1 2].',
'Running simulation on Gln.',
'Simulation running using mode 1d. Axis order = [0 1 2].',
'Simulation running using mode 1d. Axis order = [0 1 2].',
'Running simulation on NAAG.',
'Simulation running using mode 1d. Axis order = [0 1 2].',
'Simulation running using mode 1d. Axis order = [0 1 2].',
'Simulation running using mode 1d. Axis order = [0 1 2].',
'Running simulation on Asp.',
'Simulation running using mode 1d. Axis order = [0 1 2].',
'Running simulation on Glc.',
'Simulation running using mode 1d. Axis order = [0 1 2].',
'Simulation running using mode 1d. Axis order = [0 1 2].',
'Running simulation on PCh.',
'Simulation running using mode 1d. Axis order = [0 1 2].',
'Simulation running using mode 1d. Axis order = [0 1 2].',
'Running simulation on PE.',
'Simulation running using mode 1d. Axis order = [0 1 2].']
%% Cell type:markdown id: tags:
## 3. Visualisation
%% Cell type:code id: tags:
``` python
%%capture
%sx mrs_vis --save basis_fig.png steam_basis
%sx mrs_tools vis --save basis_fig.png steam_basis
```
%% Cell type:markdown id: tags:
![basis spectra](basis_fig.png)
......
#!/usr/bin/env python
# mrs_info - quick NIfTI MRS information
#
# Author: William Clarke <william.clarke@ndcn.ox.ac.uk>
#
# Copyright (C) 2021 University of Oxford
# SHBASECOPYRIGHT
import argparse
from pathlib import Path
def main():
p = argparse.ArgumentParser(description='FSL MRS Tools: NIfTI-MRS information')
p.add_argument('file', type=Path, metavar='FILE or list of FILEs',
help='NIfTI MRS file(s)', nargs='+')
args = p.parse_args()
from fsl_mrs.utils.mrs_io import read_FID
from fsl_mrs.utils.constants import GYRO_MAG_RATIO
for file in args.file:
data = read_FID(str(file))
print(f'\nRead file {file.name} ({file.parent.resolve()}).')
print(f'NIfTI-MRS version {data.mrs_nifti_version}')
print(f'Data shape {data.shape}')
print(f'Dimension tags: {data.dim_tags}')
print(f'Spectrometer Frequency: {data.spectrometer_frequency[0]} MHz')
print(f'Dwelltime (Bandwidth): {data.dwelltime:0.3E}s ({data.bandwidth:0.0f} Hz)')
print(f'Nucleus: {data.nucleus[0]}')
if data.nucleus[0] in GYRO_MAG_RATIO:
field_strength = data.spectrometer_frequency[0] / GYRO_MAG_RATIO[data.nucleus[0]]
print(f'Field Strength: {field_strength:0.2f} T')
print()
if __name__ == '__main__':
main()
......@@ -184,7 +184,7 @@ def vis(args):
# Identify directory of nifti files
elif p.is_dir() and len(nifti_files) > 0:
raise ValueError('mrs_vis should be called on a single'
raise ValueError('mrs_tools vis should be called on a single'
' NIFTI-MRS file, not a directory (unless'
' it contains basis files).')
......
#!/usr/bin/env python
# mrs_vis - quick MRS visualisation
#
# Author: Saad Jbabdi <saad@fmrib.ox.ac.uk>
# William Clarke <william.clarke@ndcn.ox.ac.uk>
#
# Copyright (C) 2019 University of Oxford
# SHBASECOPYRIGHT
import argparse
def main():
p = argparse.ArgumentParser(description='FSL Magnetic Resonance Spectroscopy Tools')
p.add_argument('file', type=str, metavar='FILE or DIR',
help='NIfTI file or directory of basis sets')
p.add_argument('--ppmlim', default=(.2, 4.2), type=float,
nargs=2, metavar=('LOW', 'HIGH'),
help='limit the fit to a freq range (default=(.2,4.2))')
p.add_argument('--mask', default=None, type=str, help='Mask for MRSI')
p.add_argument('--save', default=None, type=str, help='Save fig to path')
p.add_argument('--display_dim', default=None, type=str,
help='NIFTI-MRS tag. Do not average across this dimension.')
args = p.parse_args()
from fsl_mrs.utils.plotting import plot_spectrum, FID2Spec, plot_spectra
from fsl_mrs.utils.mrs_io import read_FID, read_basis
import matplotlib.pyplot as plt
from fsl_mrs.core import MRS
import numpy as np
from fsl_mrs.utils.preproc import nifti_mrs_proc
import nibabel as nib
from pathlib import Path
# Some logic to figure out what we are dealing with
p = Path(args.file)
nifti_files = list(p.glob('*.nii*'))
# Identify BASIS
if p.is_dir() and len(nifti_files) == 0 or \
p.suffix.upper() == '.BASIS':
basis, names, basishdr = read_basis(args.file)
fid = np.zeros(basis.shape[0])
mrs = MRS(FID=fid,
header=basishdr[0],
basis=basis,
names=names,
basis_hdr=basishdr[0])
mrs.check_Basis(repair=True)
first, last = mrs.ppmlim_to_range(ppmlim=args.ppmlim)
plt.figure(figsize=(8, 8))
for idx, n in enumerate(names):
plt.plot(mrs.getAxes(ppmlim=args.ppmlim),
np.real(FID2Spec(mrs.basis[:, idx]))[first:last],
label=n)
plt.gca().invert_xaxis()
plt.xlabel('Chemical shift (ppm)')
plt.legend()
if args.save is not None:
plt.savefig(args.save)
else:
plt.show()
# Identify directory of nifti files
elif p.is_dir() and len(nifti_files) > 0:
raise ValueError('mrs_vis should be called on a single'
' NIFTI-MRS file, not a directory (unless'
' it contains basis files).')
# Single nifti file
elif p.is_file():
data = read_FID(args.file)
if data.ndim > 4 and 'DIM_COIL' in data.dim_tags:
print('Performing coil combination')
data = nifti_mrs_proc.coilcombine(data)
if np.prod(data.shape[:3]) == 1:
# SVS
if args.display_dim:
for idx in range(data.ndim - 4):
if data.dim_tags[idx] != args.display_dim:
print(f'Averaging {data.dim_tags[idx]}')
data = nifti_mrs_proc.average(data, data.dim_tags[idx])
fig = plot_spectra(data.mrs(), ppmlim=args.ppmlim)
else:
while data.ndim > 4:
print(f'Averaging {data.dim_tags[0]}')
data = nifti_mrs_proc.average(data, data.dim_tags[0])
fig = plot_spectrum(data.mrs(), ppmlim=args.ppmlim)
if args.save is not None:
fig.savefig(args.save)
else:
plt.show()
else:
while data.ndim > 4:
print(f'Averaging {data.dim_tags[0]}')
data = nifti_mrs_proc.average(data, data.dim_tags[0])
mrsi = data.mrs()
if args.mask is not None:
mask_hdr = nib.load(args.mask)
mask = np.asanyarray(mask_hdr.dataobj)
if mask.ndim == 2:
mask = np.expand_dims(mask, 2)
mrsi.set_mask(mask)
mrsi.plot()
if __name__ == '__main__':
main()
'''FSL-MRS test script
Test the mrs_info script
Copyright Will Clarke, University of Oxford, 2021'''
# Imports
import subprocess
from pathlib import Path
# Files
testsPath = Path(__file__).parent
processed = testsPath / 'testdata/fsl_mrs/metab.nii.gz'
unprocessed = testsPath / 'testdata/fsl_mrs_preproc/metab_raw.nii.gz'
def test_single_info(tmp_path):
subprocess.check_call(['mrs_info', str(processed)])
def test_multi_info(tmp_path):
subprocess.check_call(['mrs_info', str(processed), str(unprocessed)])
'''FSL-MRS test script
Test the visualisation script
Copyright Will Clarke, University of Oxford, 2021'''
# Imports
import subprocess
from pathlib import Path
# Files
testsPath = Path(__file__).parent
svs = testsPath / 'testdata/fsl_mrs/metab.nii.gz'
basis = testsPath / 'testdata/fsl_mrs/steam_basis'
def test_vis_svs(tmp_path):
subprocess.check_call(['mrs_vis',
'--ppmlim', '0.2', '4.2',
'--save', str(tmp_path / 'svs.png'),
svs])
assert (tmp_path / 'svs.png').exists()
def test_vis_basis(tmp_path):
subprocess.check_call(['mrs_vis',
'--ppmlim', '0.2', '4.2',
'--save', str(tmp_path / 'basis.png'),
basis])
assert (tmp_path / 'basis.png').exists()
......@@ -41,8 +41,6 @@ setup(name='fsl_mrs',
'fsl_mrs/scripts/fsl_mrs_preproc',
'fsl_mrs/scripts/fsl_mrs_proc',
'fsl_mrs/scripts/fsl_mrs_sim',
'fsl_mrs/scripts/mrs_vis',
'fsl_mrs/scripts/mrs_info',
'fsl_mrs/scripts/mrs_tools',
'fsl_mrs/scripts/merge_mrs_reports',
'fsl_mrs/scripts/svs_segment',
......
Markdown is supported
0% or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment