Skip to content

Quick Start: Plotting NMR spectra

SpinPlots lets you load and plot processed NMR data in just a few lines of code. It currently supports Bruker processed data and DMFit exports (1D and 2D). For raw/unprocessed data or other instrument vendors, see NMRglue.

This tutorial covers Bruker data. For DMFit plotting, see the DMFit Plots tutorial. To learn how to access raw data arrays and build fully custom matplotlib figures, see Working with Spin Objects.

The examples below use 13C,15N-labelled Tyrosine and Glycine spectra.

from __future__ import annotations
import warnings
warnings.filterwarnings("ignore", category=UserWarning)

from spinplots.io import read_nmr

Plot 1D spectra

Here is how to load and plot a simple 1D spectrum of Tyrosine acquired at 9.4T using a MAS rate of 10kHz

tyr = read_nmr("../../data/1D/tyrosine/pdata/1")
tyr.plot(xlim=(200, -10))
No description has been provided for this image

SpinPlots uses Matplotlib's default style. To further customize a plot, pass return_fig=True to get the figure and axes objects back, then modify them with standard matplotlib calls. See the Read and Export tutorial for an example.

Customization of 1D spectra

The .plot() method accepts many keyword arguments to customize the output. Key options for 1D spectra include:

  • Overlay multiple spectra on the same axes
  • Labels and colors for each spectrum (supports matplotlib named colors and hex codes)
  • Normalization by maximum intensity (normalize="max") or number of scans (normalize="scans")
  • Stacking spectra vertically (stacked=True)
  • Grid layouts for side-by-side subplots (grid="1x2")
  • Frame control (frame=True to show y-axis and spines)
  • Font and tick customization (axisfont, axisfontsize, tickfont, tickfontsize, tickspacing)
  • Save directly to file (save=True, filename=..., format=...)
  • Return the matplotlib figure for further editing (return_fig=True)

The following example demonstrates the most common options:

tyr.plot(
    labels=["Tyrosine"],  # Set the labels for the spectra
    color=["black"],  # Set the colors for the spectra
    xlim=(200, 0),  # Set the x-axis limits
    alpha=1,  # Set the transparency of the lines (1 for no transparency, 0 for transparent)
    linewidth=2,  # Set the line width
    linestyle="-",  # Set the line style (styles, e.g. '--', ':', '-.', etc.)
    axisfont="Arial",  # Set the font style of the axis labels
    axisfontsize=12,  # Set the font size of the axis labels
    tickfont="Arial",  # Set the font style of the tick labels
    tickfontsize=10,  # Set the font size of the tick labels
    tickspacing=20,  # Set the spacing between the ticks on X-axis
    frame=True,  # Set True or False to add or remove frame
    save=False,  # Set True or False to save the figure
    filename="../../data/1D/tyrosine_13C",  # Set the path and filename for saving the figure
    format="svg",
)  # Set the format of the saved figure (e.g. 'png', 'pdf', 'svg', etc.)
No description has been provided for this image

plot sets the Y-axis and X-axis labels automatically based on the data loaded.

The Y-axis and X-axis labels can be edited with the yaxislabel and xaxislabel options, as follows :

tyr.plot(
    labels=["Tyrosine"],
    color=["black"],
    xlim=(200, 0),
    xaxislabel="my label 1",  # Set the label for the x-axis
    yaxislabel="my label 2",  # Set the label for the y-axis
    frame=True,
    save=False,
    filename="../../data/1D/tyrosine_13C",
    format="svg",
)
No description has been provided for this image

Normalization

For multiple spectra, the plot function supports normalization of data and plot stacking. For this example two 13C NMR datasets of Tyrosine and Glycine are used with different number of scans.

# Use a list of path to read multiple spectra
base_path = "../../data/1D/"
gly_tyr = read_nmr([base_path + "glycine/pdata/1", base_path + "tyrosine/pdata/1"])
gly_tyr.plot(
    labels=["Glycine", "Tyrosine"],
    color=["orange", "blue"],
    xlim=(200, 0),
    alpha=1,
    linewidth=1,
    linestyle="-",
    axisfont="Arial",
    axisfontsize=12,
    tickfont="Arial",
    tickfontsize=10,
    tickspacing=20,
    frame=True,
    save=True,
    filename="../../data/1D/overlapped",
    format="svg",
)
No description has been provided for this image

The spectrum can be normalized using the normalize using either max or scans to normalize by the maximum number of the number of scans.

gly_tyr.plot(
    labels=["Glycine", "Tyrosine"],
    color=["orange", "blue"],
    xlim=(200, 0),
    alpha=1,
    linewidth=1,
    linestyle="-",
    axisfont="Arial",
    axisfontsize=12,
    tickfont="Arial",
    tickfontsize=10,
    tickspacing=20,
    normalize="max",  # Normalized by maximum point
    frame=True,
    save=False,
    filename="../../data/1D/overlapped",
    format="svg",
)
No description has been provided for this image

Stacking

Multiple spectra can be plotted using the stacked option, as follows :

gly_tyr.plot(
    labels=["Glycine", "Tyrosine"],
    color=["orange", "blue"],
    xlim=(200, 0),
    alpha=1,
    linewidth=1,
    linestyle="-",
    axisfont="Arial",
    axisfontsize=12,
    tickfont="Arial",
    tickfontsize=10,
    tickspacing=20,
    normalize="max",
    stacked=True,  # Set to True to stack the spectra
    frame=True,
    save=False,
    filename="../../data/1D/stacked",
    format="svg",
)
No description has been provided for this image

or with more plots

base_path = "../../data/1D/"
gly_tyr_ala_arg = read_nmr(
    [
        base_path + "glycine/pdata/1",
        base_path + "tyrosine/pdata/1",
        base_path + "alanine/pdata/1",
        base_path + "arginine/pdata/1",
    ]
)
gly_tyr_ala_arg.plot(
    labels=["Glycine", "Tyrosine", "Alanine", "Arginine"],
    color=[
        "#03045e",
        "#023e8a",
        "#0077b6",
        "#0096c7",
    ],  # Hex color codes is also supported
    xlim=(200, 0),
    alpha=1,
    linewidth=1,
    linestyle="-",
    axisfont="Arial",
    axisfontsize=12,
    tickfont="Arial",
    tickfontsize=10,
    tickspacing=20,
    normalize="max",
    stacked=True,  # Set to True to stack the spectra
    frame=True,
    save=False,
    filename="../../data/1D/stacked",
    format="svg",
)
No description has been provided for this image

Grid

The plot allows the presentation of multiple spectra in a grid style (subplots), by using the option grid='rows x columns.

gly_tyr.plot(
    grid="1x2",  # Set the grid layout '1x2' for 1 row and 2 columns
    labels=["Glycine", "Tyrosine"],
    color=["orange", "blue"],
    xlim=(200, 0),
    frame=True,
    save=False,
    normalize="max",
    filename="../../data/1D/grid",
    format="svg",
)
No description has been provided for this image

More complex grid spaces can be created, as follows :

gly_tyr_ala_arg.plot(
    grid="2x2",  # Set the grid layout '2x2' for 2 rows and 2 columns
    labels=["Glycine", "Tyrosine", "Alanine", "Arginine"],
    color=[
        "#03045e",
        "#023e8a",
        "#0077b6",
        "#0096c7",
    ],  # Hex color codes is also supported
    xlim=(200, 0),
    normalize=True,
    frame=True,
    save=False,
    filename="../../data/1D/grid",
    format="svg",
)
No description has been provided for this image

Plot 2D spectra

The .plot() method also handles 2D spectra with contour lines and projections. Key options for 2D plots include:

  • contour_start: the minimum contour level (controls which peaks are visible)
  • contour_num: the number of contour levels
  • contour_factor: the multiplicative factor between successive contour levels
  • cmap: a matplotlib colormap for the contours (default is black lines)
  • color: solid color(s) for contour lines — use instead of cmap when overlaying spectra
  • proj_color: color(s) for the projection traces
  • xlim / ylim: axis limits for the direct (F2) and indirect (F1) dimensions
  • diagonal: slope of a diagonal reference line (e.g. diagonal=2 for DQ-SQ)
  • homonuclear: set to True when both axes correspond to the same nucleus
  • linewidth_contour / linewidth_proj: line widths for contours and projections
  • save, filename, format: save the plot directly to a file

Heteronuclear correlation

The following example includes all options currently available in the bruker2d function.

A simple heteronuclear 1H-13C 2D acquired at 9.4T using a MAS rate of 10kHz can be plotted, as follows :

data_het = read_nmr("../../data/2D/43/pdata/1")
data_het.plot(
    contour_start=4e10,  # Set the starting value for the contour lines
    contour_num=12,  # Set the number of contour lines
    contour_factor=1.5,  # Set the factor for the contour lines
    cmap="viridis",  # Set the colormap for the contour plot. Available colormaps: https://matplotlib.org/stable/users/explain/colors/colormaps.html
    xlim=(180, 30),  # Set the x-axis limits
    ylim=(14, -2),  # Set the y-axis limits
    linewidth_contour=1,  # Set the line width for the contour lines
    linewidth_proj=1.5,  # Set the line width for the projection lines
    axisfont="Arial",  # Set the font style of the axis labels
    axisfontsize=12,  # Set the font size of the axis labels
    tickfont="Arial",  # Set the font style of the tick labels
    tickfontsize=10,  # Set the font size of the tick labels
    tickspacing=20,  # Set the spacing between the ticks on X-axis
    save=False,  # Set True or False to save the figure
    filename="../../data/2D/2d_hetero",  # Set the path and filename for saving the figure
    format="png", # Set the format of the saved figure (e.g. 'png', 'pdf', 'svg', etc.)
)
No description has been provided for this image

Homonuclear correlation

Some NMR spectra, like double-quantum (DQ) experiments, are often visualized with a diagonal line representing y=2x. You can add this diagonal line for any line of the form y=nx using the keyword diagonal=n, where n sets the desired quantum order. The following example shows a 13C-13C DQ-SQ experiment. The option homonuclear=True is only needed if the y-axis label isn't displaying correctly, such as when the DQ-SQ is acquired through CPMAS.

Similarly, a simple homonuclear 13C-13C 2D can be plotted, as follows :

data_homo = read_nmr("../../data/2D/16/pdata/1")
data_homo.plot(
    contour_start=1e7,
    contour_num=25,
    contour_factor=1.5,
    cmap="viridis",
    xlim=(200, 30),
    ylim=(400, 60),
    linewidth_contour=1,
    linewidth_proj=1.5,
    axisfont="Arial",
    axisfontsize=12,
    tickfont="Arial",
    tickfontsize=10,
    tickspacing=20,
    homonuclear=True,  # Set to true if spectra is a homonuclear correlation
    diagonal=2,  # Set the diagonal slope: 2 for DQ (y=2x)
    save=False,
    filename="../../data/2D/2d_homo",
    format="png",
)
No description has been provided for this image

bruker2d function sets the Y-axis and X-axis labels automatically based on the data loaded, but you can edit them with the yaxislabel and xaxislabel options, as follows :

data_homo.plot(
    contour_start=1e7,
    contour_num=25,
    contour_factor=1.5,
    cmap="viridis",
    xlim=(200, 30),
    ylim=(400, 60),
    linewidth_contour=1,
    linewidth_proj=1.5,
    axisfont="Arial",
    axisfontsize=12,
    tickfont="Arial",
    tickfontsize=10,
    xtickspacing=20,    # Set space between ticks in x-axis
    ytickspacing=50,    # Set space between ticks in y-axis
    homonuclear=True,
    diagonal=2,
    xaxislabel="SQ $^{13}$C (ppm)",  # Set the label for the x-axis
    yaxislabel="DQ $^{13}$C (ppm)",  # Set the label for the y-axis
    save=False,
    filename="../../data/2D/2d_homo",
    format="png",
)
No description has been provided for this image