Skip to content

Plotting

Sequence logos and plots of analysis results, drawn with matplotlib, which is installed with pip install universalmotif[plot]. Each function returns the matplotlib figure or axes, so that plots can be adjusted before they are saved.

view_motifs

view_motifs(
    motifs: Motif | Iterable[Motif],
    use_type: str = "ICM",
    rc: bool = True,
    min_overlap: int = 6,
    relative_entropy: bool = False,
    sort_by: str = "none",
    show_names: bool = True,
    names_pos: str = "top",
    show_positions: bool = True,
    show_positions_once: bool = True,
    colour_scheme: Mapping[str, str] | None = None,
    min_height: float = 0.01,
    x_spacer: float = 0.04,
    y_spacer: float = 0.01,
    sort_positions: bool | None = None,
    sort_positions_decreasing: bool = True,
    fit_to_height: Any = _DEFAULT,
    rc_text: str = " [RC]",
    flip_neg: bool = True,
    text_size: float = 12,
    figsize: tuple[float, float] | None = None,
    return_raw: bool = False,
    nthreads: int = 1,
    ax: Axes | None = None,
)

Draw motifs as sequence logos.

Motifs of any alphabet can be drawn. Several motifs are aligned to the one with the highest information content in the same way as compare_motifs() aligns them, trying reverse complements of DNA and RNA motifs with rc. Motifs that align better as reverse complements are flipped and get rc_text added to their names, and all of them are padded into a common frame and drawn one above the other.

Parameters:

Name Type Description Default
use_type str

Matrix type to draw, one of "ICM", "PPM", "PWM", "PCM", or "CWM" for motifs that are CWMs. ICMs are drawn in bits, and motifs without nsites count as 100 sites.

'ICM'
sort_by str

Display order, which is the input order with "none", decreasing information content with "ic", or clusters by correlation with "similarity".

'none'
show_names bool

Name each logo, either above it with "top" or beside it with "right". A single logo is named above it.

True
names_pos bool

Name each logo, either above it with "top" or beside it with "right". A single logo is named above it.

True
show_positions bool

Number the positions, either once under the last logo or under every logo with each motif counting its own positions.

True
show_positions_once bool

Number the positions, either once under the last logo or under every logo with each motif counting its own positions.

True
colour_scheme Mapping[str, str] | None

Letter colours. DNA and RNA default to green A, blue C, yellow G and red T or U, amino acids to colours grouped by side-chain chemistry, and other alphabets to a categorical palette.

None
min_height float

Letter layout, as in view_logo(). Letters are sorted by height except for PCMs and PPMs, and PPM positions are scaled to a height of 1, unless told otherwise.

0.01
x_spacer float

Letter layout, as in view_logo(). Letters are sorted by height except for PCMs and PPMs, and PPM positions are scaled to a height of 1, unless told otherwise.

0.01
y_spacer float

Letter layout, as in view_logo(). Letters are sorted by height except for PCMs and PPMs, and PPM positions are scaled to a height of 1, unless told otherwise.

0.01
sort_positions float

Letter layout, as in view_logo(). Letters are sorted by height except for PCMs and PPMs, and PPM positions are scaled to a height of 1, unless told otherwise.

0.01
sort_positions_decreasing float

Letter layout, as in view_logo(). Letters are sorted by height except for PCMs and PPMs, and PPM positions are scaled to a height of 1, unless told otherwise.

0.01
fit_to_height float

Letter layout, as in view_logo(). Letters are sorted by height except for PCMs and PPMs, and PPM positions are scaled to a height of 1, unless told otherwise.

0.01
flip_neg float

Letter layout, as in view_logo(). Letters are sorted by height except for PCMs and PPMs, and PPM positions are scaled to a height of 1, unless told otherwise.

0.01
return_raw bool

Return the aligned matrices as a dict from names to (letters, positions) arrays instead of drawing them.

False
ax Axes | None

Draw a single motif on these axes, such as a panel of a larger figure, instead of in a new figure. figsize is then ignored.

None

Returns:

Type Description
Figure | Axes | dict[str, ndarray]

A matplotlib figure, the axes drawn on when ax is given, or with return_raw a dict of matrices.

Examples:

>>> import matplotlib.pyplot as plt
>>> import universalmotif as um
>>> motifs = um.example_motifs()[:3]
>>> fig = um.view_motifs(motifs)
>>> type(fig).__name__, len(fig.axes)
('Figure', 3)
>>> plt.close(fig)

With return_raw, the aligned matrices share one width:

>>> raw = um.view_motifs(motifs, use_type="PPM", return_raw=True)
>>> {name: m.shape for name, m in raw.items()}
{'TATA-box [RC]': (4, 11), 'AP-1': (4, 11), 'CRE': (4, 11)}

A single motif can go into a panel of another figure:

>>> fig, (left, right) = plt.subplots(1, 2, figsize=(8, 2.5))
>>> ax = um.view_motifs(motifs[1], ax=left)
>>> ax is left
True
>>> plt.close(fig)
view_logo(
    x,
    letters: Sequence[str] | None = None,
    colour_scheme: Mapping[str, str] | None = None,
    fill: str = "black",
    min_height: float = 0.01,
    x_spacer: float = 0.04,
    y_spacer: float = 0.01,
    sort_positions: bool = False,
    sort_positions_decreasing: bool = True,
    fit_to_height: float | None = None,
    flip_neg: bool = True,
    ax: Axes | None = None,
) -> Axes

Draw a logo from any numeric matrix.

x is a (rows, positions) array with letters naming the rows, a mapping from row names to values, or a motif, which is drawn as its matrix is. Row names may be several characters long, columns can have any height, and negative values are stacked below zero, upside down so that they read outward from zero unless flip_neg is False. Letters are coloured by colour_scheme, a mapping from single characters to colours, or all filled with fill.

Letters shorter than min_height are left out, x_spacer and y_spacer set the gaps between letters, sort_positions stacks each position's letters by height, and fit_to_height scales every position to that height. The axes are left bare.

Examples:

>>> import matplotlib.pyplot as plt
>>> import numpy as np
>>> import universalmotif as um
>>> x = np.array([[1.0, 0.2, -0.5], [0.1, 1.5, 0.3]])
>>> ax = um.view_logo(x, letters=["A", "Bc"])
>>> type(ax).__name__
'Axes'
>>> plt.close("all")

view_attributions

view_attributions(
    scores: Any,
    sequence: str | None = None,
    kind: str = "observed",
    alphabet: str = "ACGT",
    start: int = 0,
    region: tuple[int, int] | None = None,
    hits: DataFrame | None = None,
    colour_scheme: Mapping[str, str] | None = None,
    flip_neg: bool = True,
    ylabel: str | None = None,
    figsize: tuple[float, float] | None = None,
    ax: Axes | None = None,
) -> Axes

Draw attribution or contribution scores along a sequence, such as those a deep-learning model gives each position of an input.

scores is either one value per position, or one value per letter and position as an array of shape (letters, length), with the letters in the order of alphabet. Arrays of shape (length, letters) and PyTorch tensors are accepted too. kind chooses what is drawn:

"observed" A logo of the letters of sequence, each as tall as its score, above the axis when positive and below it when negative. Scores per letter are reduced to those of the letters in the sequence, so this draws contribution scores times the input. Without sequence, per-letter scores are drawn as they are, which suits scores that are already zero for the letters not in the sequence. "all" A logo of every letter's score at every position, such as hypothetical contributions or the effects of in silico mutagenesis, with positive scores stacked above the axis and negative ones below. "heatmap" The same per-letter scores as a heatmap with a colour scale centred on zero, with the letters of sequence marked by dots.

Positions are labelled from start, such as the genomic position of the first letter, and region, a (start, end) pair in the same positions with the end left out, draws only part of the sequence. hits, such as from scan_sequences() run on sequence, shades each hit, labelled with its motif if the table has one, with positions counted along the sequence from 0. Letters are coloured by colour_scheme, by default the package's colours for DNA, RNA and amino acids, and letters below the axis are drawn upside down, so that they read outward from zero, unless flip_neg is False.

Needs the plot extra.

Examples:

>>> import matplotlib.pyplot as plt
>>> import numpy as np
>>> import universalmotif as um
>>> seq = "ACGTTTGACCAAGT"
>>> scores = np.zeros(len(seq))
>>> scores[4:10] = [0.3, 0.6, 0.9, 0.8, 0.7, 0.4]
>>> ax = um.view_attributions(scores, seq)
>>> ax.get_ylabel()
'Attribution'
>>> ism = np.random.default_rng(1).normal(0, 0.2, (4, len(seq)))
>>> ax = um.view_attributions(ism, seq, kind="heatmap", ylabel="Effect")
>>> plt.close("all")

view_variant

view_variant(
    ref_scores: Any,
    alt_scores: Any,
    sequence: str,
    position: int,
    alt: str,
    kind: str = "observed",
    alphabet: str = "ACGT",
    start: int = 0,
    region: tuple[int, int] | None = None,
    colour_scheme: Mapping[str, str] | None = None,
    flip_neg: bool = True,
    figsize: tuple[float, float] | None = None,
) -> Figure

Draw the attribution scores of a sequence and of the same sequence with one letter changed, one above the other, with their difference below.

ref_scores are the scores of sequence and alt_scores those of the sequence with alt at position, in any of the forms view_attributions() takes, drawn with its kind of "observed" or "all". position and region are given in the same positions as the axis, which start at start. The two logos share a y-axis so that they can be compared, the changed position is shaded, and the bottom panel shows how the total score at each position changes, alternative minus reference.

Needs the plot extra.

Examples:

>>> import matplotlib.pyplot as plt
>>> import numpy as np
>>> import universalmotif as um
>>> seq = "ACGTTGACTCAGT"
>>> ref = np.zeros(len(seq))
>>> ref[5:11] = [0.3, 0.6, 0.5, 0.6, 0.6, 0.4]
>>> alt = ref * 0.2
>>> fig = um.view_variant(ref, alt, seq, position=7, alt="A")
>>> len(fig.axes)
3
>>> plt.close(fig)

plot_motif_peaks

plot_motif_peaks(
    peaks: DataFrame,
    motifs: Sequence[str] | None = None,
    ncol: int = 2,
    bins: int = 50,
    fill_window: str = "#ffe4a3",
    figsize: tuple[float, float] | None = None,
) -> Figure

Draw the positions of motif hits found by motif_peaks().

One panel per motif, or per motif named in motifs, shows a histogram of the hit centres, with the most enriched window shaded and the P-value and enrichment in the title.

Examples:

>>> import matplotlib.pyplot as plt
>>> import universalmotif as um
>>> wbox = um.example_motifs()[5]
>>> hits = um.scan_sequences(wbox, um.example_sequences("targets"), nthreads=1)
>>> fig = um.plot_motif_peaks(um.motif_peaks(hits, seq_length=1000, nthreads=1))
>>> type(fig).__name__
'Figure'
>>> plt.close(fig)

plot_match_bkg

plot_match_bkg(
    sequences: Sequence[str]
    | Mapping[str, str]
    | None = None,
    bkg: Sequence[str] | Mapping[str, str] | None = None,
    by: Sequence[str] | None = None,
    indices: DataFrame | None = None,
    figsize: tuple[float, float] | None = None,
) -> Figure

Compare the composition of targets and their matched background from match_bkg(), as overlaid densities.

Give the targets and the background to draw their GC fraction and length, or the indices table from match_bkg(..., return_indices=True) to also see any covariates. by picks the axes to draw.

Examples:

>>> import matplotlib.pyplot as plt
>>> import universalmotif as um
>>> targets = um.example_sequences("targets")
>>> bkg = um.match_bkg(targets, um.example_sequences("controls"), seed=1)
>>> fig = um.plot_match_bkg(targets, bkg, by=["gc"])
>>> type(fig).__name__
'Figure'
>>> plt.close(fig)

plot_motif_proximity

plot_motif_proximity(
    proximity: DataFrame,
    motifs: Sequence[str] | None = None,
    ncol: int = 2,
    bins: int = 50,
    fill_zone: str = "#ffe4a3",
    log_x: bool = False,
    figsize: tuple[float, float] | None = None,
) -> Figure

Draw each motif's distances to the nearest anchor, from motif_proximity(), with the most enriched zone shaded.

Distances are signed and negative upstream of stranded anchors. With log_x the absolute distances plus one are drawn on a log scale.

Examples:

>>> import matplotlib.pyplot as plt
>>> import universalmotif as um
>>> motifs = [um.example_motifs()[i] for i in (3, 5)]
>>> targets = um.example_sequences("targets")
>>> anchors = [(name, 500, 500) for name in targets]
>>> res = um.motif_proximity(anchors=anchors, motifs=motifs, sequences=targets, nthreads=1)
>>> fig = um.plot_motif_proximity(res)
>>> type(fig).__name__
'Figure'
>>> plt.close(fig)

Logos without matplotlib

In a Jupyter notebook, a motif on its own at the end of a cell is shown as its logo next to its metadata. The same logo is available as an SVG image, and the letter heights as a DataFrame for logomaker.

logo_svg

logo_svg(
    motif: Motif,
    use_type: str | None = None,
    height: float = 60,
    position_width: float = 16,
    colours: Mapping[str, str] | None = None,
    relative_entropy: bool = False,
) -> str

A sequence logo of a motif as an SVG image, without matplotlib.

The letters are those view_motifs() draws, with heights from use_type: information content by default, or contribution weights for a CWM. The logo is height pixels high and position_width pixels wide per position, with no axes, which suits reports and web pages. colours maps letters to colours, by default those of view_motifs(). The gaps of a gapped motif are drawn as dotted spaces labelled with their sizes.

Examples:

>>> import universalmotif as um
>>> svg = um.logo_svg(um.example_motifs()[3])
>>> svg.startswith("<svg") and svg.count("<path") >= 8
True

to_logomaker

to_logomaker(
    motif: Motif,
    use_type: str | None = None,
    relative_entropy: bool = False,
)

A motif as a pandas DataFrame for logomaker.

logomaker draws logos from a DataFrame with one row per position, indexed from 0, and one column per letter. The values are the letter heights of use_type, information content by default or contribution weights for a CWM, as view_motifs() draws them. Pass use_type="PPM" for probabilities. Needs the pandas extra.

Examples:

>>> import universalmotif as um
>>> df = um.to_logomaker(um.example_motifs()[3])
>>> list(df.columns), df.shape
(['A', 'C', 'G', 'T'], (8, 4))