Code reference
nmrplot.core
The core module of nmrplot. Contains the Spectrum class, which is the main class of nmrplot, and a number of extras.
Spectrum
An object containing a spectrum and its parameters
calc_baseline(self)
Determine the spectral baseline using the mode
Source code in nmrplot/core.py
def calc_baseline(self):
"""Determine the spectral baseline using the mode"""
counts, bins = self.calc_histogram()
self.baseline = bins[np.argmax(counts)]
return self.baseline
calc_clevs(self, nlevs=42, factor=1.1)
Calculate the contour levels for the spectrum given a series of parameters.
Parameters:
Name | Type | Description | Default |
---|---|---|---|
threshold |
float |
How many times the noise level is the lower contour above the baseline. |
required |
nlevs |
int |
How many contour levels to use. |
42 |
factor |
float |
Increment factor between the contour levels. |
1.1 |
sign |
string |
Sign of the signals to use. Can be 'positive', 'negative' or 'both'. |
required |
Exceptions:
Type | Description |
---|---|
ValueError |
If no correct sign is given, an error message is raised. |
Source code in nmrplot/core.py
def calc_clevs(self, nlevs=42, factor=1.1):
"""Calculate the contour levels for the spectrum given a series of parameters.
Args:
threshold (float): How many times the noise level is the lower contour above the baseline.
nlevs (int): How many contour levels to use.
factor (float): Increment factor between the contour levels.
sign (string): Sign of the signals to use. Can be 'positive', 'negative' or 'both'.
Raises:
ValueError: If no correct sign is given, an error message is raised.
"""
# calculate starting contour level from threshold
start_clev = self.baseline + self.threshold * self.noise
if self.sign == "both":
positive_clevs = start_clev * factor ** np.arange(nlevs)
negative_clevs = -np.flip(positive_clevs)
self.clevs = np.concatenate((negative_clevs, positive_clevs))
print(
f"Highest negative/lowest positive contour levels are at {self.threshold:.1f}*noise below/above the baseline"
)
elif self.sign == "positive":
self.clevs = start_clev * factor ** np.arange(nlevs)
print(
f"Lowest positive contour level is at {self.threshold:.1f}*noise above the baseline"
)
elif self.sign == "negative":
self.clevs = -np.flip(start_clev * factor ** np.arange(nlevs))
print(
f"Highest negative contour level is at {self.threshold:.1f}*noise below the baseline"
)
else:
raise ValueError(
f"Unknown sign: {self.sign}\nPlease choose a valid sign: negative, positive or both"
)
calc_histogram(self)
Return the histogram of the spectrum
Source code in nmrplot/core.py
def calc_histogram(self):
"""Return the histogram of the spectrum"""
counts, bins = histogram(self.data.flatten())
return counts, bins
calc_signal_to_noise(self)
Return the signal to noise ratio of the spectrum Based on SNR definition by Hyberts et al. (2013) https://www.ncbi.nlm.nih.gov/pmc/articles/PMC3570699/
Source code in nmrplot/core.py
def calc_signal_to_noise(self):
"""Return the signal to noise ratio of the spectrum
Based on SNR definition by Hyberts et al. (2013)
https://www.ncbi.nlm.nih.gov/pmc/articles/PMC3570699/
"""
# define signal as the maximum intensity in the spectrum (positive or negative)
self.signal = abs(self.data).max()
# define an empty region as the lowest decile of the spectrum
# FIXME: Review this definition for spectra with negative peaks
# E.g. NOESY
empty = self.data[self.data < np.quantile(self.data, 0.1)]
# define the noise as the standard deviation of the empty region
self.noise = empty.std()
# calculate the signal to noise ratio
self.snr = self.signal / self.noise
return self.snr, self.signal, self.noise
calc_threshold(self, signal_fraction=0.01)
Return the threshold for the spectrum contour level based on a given signal fraction
Parameters:
Name | Type | Description | Default |
---|---|---|---|
sign |
str |
Sign of the intensities to draw. |
required |
signal_fraction |
float |
Fraction of the maximum intensity as lower contour. Defaults to 0.01. |
0.01 |
Exceptions:
Type | Description |
---|---|
ValueError |
Error message if no correct sign is given. |
Returns:
Type | Description |
---|---|
self.threshold |
How many times the noise level is the lower contour above the baseline. |
Source code in nmrplot/core.py
def calc_threshold(self, signal_fraction=0.01):
"""Return the threshold for the spectrum contour level based on a given
signal fraction
Args:
sign (str, optional): Sign of the intensities to draw.
signal_fraction (float, optional): Fraction of the maximum intensity as lower contour. Defaults to 0.01.
Raises:
ValueError: Error message if no correct sign is given.
Returns:
self.threshold: How many times the noise level is the lower contour above the baseline.
"""
if self.sign == "both":
# A good guess is the lowest contour should be 1/100 of the signal
# Calculate the corresponding threshold
self.threshold = (self.signal * signal_fraction) / self.noise
elif self.sign == "positive":
# Same but on the positive side
self.threshold = (self.data.max() * signal_fraction) / self.noise
elif self.sign == "negative":
# Same but on the negative side
self.threshold = abs(self.data.min() * signal_fraction) / self.noise
else:
raise ValueError(
f"Unknown sign: {self.sign}\nPlease choose a valid sign: negative, positive or both"
)
return self.threshold
get_ppm_ranges(self)
Return the ppm ranges of the spectrum
Source code in nmrplot/core.py
def get_ppm_ranges(self):
"""Return the ppm ranges of the spectrum"""
self.ppm_ranges = []
# go through each dimension inversely to keep the right order.
for i in reversed(range(self.ndim)):
converter = ng.fileiobase.uc_from_udic(self.udic, dim=i)
self.ppm_ranges.append(converter.ppm_limits())
# flatten the range list
self.ppm_ranges = [item for sublist in self.ppm_ranges for item in sublist]
return self.ppm_ranges
normalize_data(self)
Normalize the data to the baseline and make it zero
Source code in nmrplot/core.py
def normalize_data(self):
"""Normalize the data to the baseline and make it zero"""
self.data = (self.data - self.baseline) / abs(self.baseline)
self.calc_baseline()
self.normalized = True
plot_histogram(self)
Plot the histogram of the spectrum
Source code in nmrplot/core.py
def plot_histogram(self):
"""Plot the histogram of the spectrum"""
bins, counts = self.calc_histogram()
plt.hist(bins, counts)
plt.show()
plot_spectrum(self, xlims='', ylims='', nlevs=42, factor=1.1, linewidth=1.0, cmap='viridis')
Plot the spectrum.
Parameters:
Name | Type | Description | Default |
---|---|---|---|
threshold |
float |
Lowest contour drawn as a multiple of the spectral noise. |
required |
xlims(tuple, |
optional |
x axis ppm limit. Keep in mind that ppm decrease left to right. |
required |
ylims(tuple, |
optional |
y axis ppm limit. Keep in mind that ppm decrease left to right. |
required |
nlevs |
int |
Number of contour levels. |
42 |
factor |
float |
Exponential increment between contours. |
1.1 |
cmap |
str |
Colormap to be used. Options are: "viridis, "red", "blue", "green", "purple", "orange", "grey", "light_red", "light_blue". Only with sign="both":"coolwarm". |
'viridis' |
sign |
str |
Sign of the intensities to draw. Defaults to 'positive'. |
required |
Source code in nmrplot/core.py
def plot_spectrum(self, xlims="", ylims="", nlevs=42, factor=1.1, linewidth=1.0, cmap="viridis"):
"""Plot the spectrum.
Args:
threshold (float, optional): Lowest contour drawn as a multiple of the spectral noise.
xlims(tuple, optional): x axis ppm limit. Keep in mind that ppm decrease left to right.
ylims(tuple, optional): y axis ppm limit. Keep in mind that ppm decrease left to right.
nlevs (int, optional): Number of contour levels.
factor (float, optional): Exponential increment between contours.
linewidth (float, optional). Contour level linewidth
cmap (str, optional): Colormap to be used. Options are: "viridis, "red", "blue", "green", "purple", "orange", "grey", "light_red", "light_blue". Only with sign="both":"coolwarm".
sign (str, optional): Sign of the intensities to draw. Defaults to 'positive'.
"""
if self.ndim == 1:
fig, ax = plt.subplots()
ppm_scale = np.linspace(
self.ppm_ranges[0], self.ppm_ranges[1], self.data.size
)
ax.plot(ppm_scale, self.data, linewidth=linewidth)
if xlims is False:
ax.set_xlim(xlims)
else:
ax.set_xlim(*self.ppm_ranges)
ax.set_xlabel(f"{self.label[0]} ppm")
ax.set_ylabel("Intensity (A.U.)")
plt.show()
elif self.ndim == 2:
self.calc_clevs(nlevs, factor)
fig, ax = plt.subplots()
# Set the limits of the color map to the calculated contour levels
vmin = self.clevs.min()
vmax = self.clevs.max()
# Colormaps need to be lognormalized to fit the contour levels
if self.sign == "both":
cmap = cmapdict["coolwarm"]
# We have positive and negative contours
norm = SymLogNorm(
linthresh=self.threshold * self.noise, vmin=vmin, vmax=vmax, base=10
)
data = norm(self.data)
clevs = norm(self.clevs)
print(f"Plotting {nlevs} negative and {nlevs} positive contour levels")
elif self.sign == "positive":
norm = LogNorm(vmin=vmin, vmax=vmax)
cmap = cmapdict[cmap]
data = norm(self.data)
clevs = norm(self.clevs)
print(f"Plotting {nlevs} positive contour levels")
elif self.sign == "negative":
# Because contours are negative we need to make it positive to calculate
# the norm, and apply it flipped to the data and clevs
# FIXME: It raises a RuntimeWarning, but it works.
# Also, it is not very efficient to make copies of the data and clevs
norm = LogNorm(vmin=abs(vmax), vmax=abs(vmin))
cmap = cmapdict[cmap]
data = norm.inverse(self.data)
clevs = norm.inverse(self.clevs)
print(f"Plotting {nlevs} negative contour levels")
else:
pass
ax.contour(
data, clevs, extent=self.ppm_ranges, linewidths=linewidth, cmap=cmap,
)
if xlims == "":
ax.set_xlim(*self.ppm_ranges[:2])
else:
ax.set_xlim(xlims)
if ylims == "":
ax.set_ylim(*self.ppm_ranges[2:])
else:
ax.set_ylim(ylims)
ax.set_xlabel(f"{self.label[0]} ppm")
ax.set_ylabel(f"{self.label[1]} ppm")
plt.show()
else:
print("The spectrum is not 1D or 2D")
return fig, ax
load_bruker(expno_path, pdata=1)
Load a processed spectrum in Bruker format and return data and spectral parameters.
Parameters:
Name | Type | Description | Default |
---|---|---|---|
expno_path |
str |
Path to experiment folder (i.e. to experiment_name/expno) |
required |
pdata |
int |
Number of proccessing. Defaults to 1. |
1 |
Returns:
Type | Description |
---|---|
dic (dic) |
Dictionary of Bruker NMR parameters. data (np.ndarray): Processed NMR spectum as an array of intensities. |
Source code in nmrplot/core.py
def load_bruker(expno_path, pdata=1):
"""Load a processed spectrum in Bruker format and return data and spectral parameters.
Args:
expno_path (str): Path to experiment folder (i.e. to experiment_name/expno)
pdata (int, optional): Number of proccessing. Defaults to 1.
Returns:
dic (dic): Dictionary of Bruker NMR parameters.
data (np.ndarray): Processed NMR spectum as an array of intensities.
"""
pdata_path = path.join(expno_path, f"pdata/{pdata}")
dic, data = ng.bruker.read_pdata(pdata_path)
return dic, data