Phasor plot#

An introduction to plotting phasor coordinates.

The phasorpy.plot.PhasorPlot class is used to plot phasor coordinates as scattered points, lines, two-dimensional histograms, and contours. The plots are supplemented with universal semicircles, polar grids, polar cursors, component mixture indicators, and manual annotations.

Import required modules, functions, and classes:

import math

import numpy

from phasorpy.plot import PhasorPlot

numpy.random.seed(42)

Empty phasor plot#

Create an empty phasor plot, showing the first quadrant and the universal semicircle:

plot = PhasorPlot()
plot.show()
Phasor plot

Custom axes#

Create a phasor plot with custom axis limits, automatic ticks, and custom axis labels:

plot = PhasorPlot(
    title='Custom axes',
    xlabel='G',
    ylabel='S',
    xlim=(-0.1, 1.1),
    ylim=(-0.1, 0.61),
    xticks=None,
    yticks=None,
)
plot.show()
Custom axes

Universal semicircle#

Create a phasor plot at a frequency of 80 MHz with custom lifetime ticks. Add a second, transformed universal semicircle for FRET acceptor coordinates:

plot = PhasorPlot(xlim=(-0.2, 1.1), title='Universal semicircle')
plot.semicircle(
    frequency=80.0,
    lifetime=[0, 0.5, 1, 2, 4, 8, 16],
    color='tab:green',
    label='donor',
)
plot.semicircle(
    polar_reference=(0.9852, 0.5526), color='tab:red', label='acceptor'
)
plot.show()
Universal semicircle

Scatter and line plots#

Plot phasor coordinates as scatter or lines:

plot = PhasorPlot(frequency=80.0, title='Scatter and line plots')
plot.plot(0.6, 0.4, label='1')
plot.plot([0.2, 0.9], [0.4, 0.3], '.-', label='2')
plot.plot([0.39, 0.4, 0.41], [0.21, 0.19, 0.2], 'x', label='3')
plot.show()
Scatter and line plots

Crosshair cursors#

Highlight specific phasor coordinates using Cartesian or polar lines, optionally limited by a radius:

plot = PhasorPlot(frequency=80.0, title='Crosshair cursors')
plot.cursor(0.7, 0.25, color='tab:blue', label='cartesian')
plot.cursor(
    0.7, 0.25, color='tab:orange', polar=True, linestyle='--', label='polar'
)
plot.cursor(
    0.2, 0.4, radius=0.1, crosshair=True, color='tab:red', label='radius'
)
plot.cursor(
    0.45,
    0.4,
    radius=0.1,
    crosshair=True,
    polar=True,
    linestyle='--',
    color='tab:green',
    label='radius|polar',
)
plot.show()
Crosshair cursors

Cursors#

Highlight specific ranges of Cartesian or polar coordinates:

plot = PhasorPlot(frequency=80.0, title='Cursors')
plot.cursor(0.35, 0.3, 0.65, 0.1, color='tab:blue', label='rectangle')
plot.cursor(
    0.35,
    0.3,
    0.65,
    0.1,
    polar=True,
    color='tab:orange',
    label='rectangle|polar',
)
plot.cursor(0.5, 0.5, radius=0.05, color='tab:red', label='circle')
plot.cursor(
    0.1, 0.3, radius=0.05, radius_minor=0.1, color='tab:green', label='ellipse'
)
plot.cursor(
    0.9,
    0.3,
    radius=0.05,
    radius_minor=0.1,
    angle='semicircle',
    color='tab:purple',
    label='semicircle aligned',
)
plot.show()
Cursors

Multiple cursors sharing the same style may be plotted at once:

plot = PhasorPlot(frequency=80.0, title='Multiple cursors')
plot.cursor(
    [0.2, 0.5, 0.8],
    0.4,
    radius=[0.05, 0.1, 0.05],
    radius_minor=0.1,
    angle='semicircle',
    color=['tab:blue', '0.5', 'tab:orange'],
    label=['blue ellipse', 'gray circle', 'orange ellipse'],
)
plot.show()
Multiple cursors

Alternatively, use polar coordinates and various options:

plot = PhasorPlot(frequency=80.0, title='Polar cursors')
plot.polar_cursor(0.6435, 0.5, color='tab:blue', label='crosshair')
plot.polar_cursor(0.5236, 0.6, 0.1963, 0.8, linewidth=2, label='rectangle')
plot.polar_cursor(
    0.6435,
    0.5,
    radius=0.05,
    radius_minor=0.1,
    alpha=0.5,
    fill=True,
    color='tab:blue',
    label='ellipse',
)
plot.show()
Polar cursors

Component mixtures#

Show linear combinations of phasor coordinates or ranges thereof:

real, imag, weights = numpy.array(
    [[0.1, 0.2, 0.5, 0.9], [0.3, 0.4, 0.5, 0.3], [2, 1, 2, 1]]
)

plot = PhasorPlot(frequency=80.0, title='Component mixtures')
plot.components(
    real,
    imag,
    linestyle='',
    marker='o',
    labels=['A', 'B', 'C', 'D'],
    fill=True,
    color='tab:blue',
    facecolor='lightyellow',
    label='components',
)
plot.components(real, imag, weights, marker='o', label='mixture')
plot.show()
Component mixtures

Two-dimensional histogram#

Plot large number of phasor coordinates as a two-dimensional histogram:

real, imag = numpy.random.multivariate_normal(
    [0.6, 0.4], [[3e-3, -1e-3], [-1e-3, 1e-3]], (256, 256)
).T
plot = PhasorPlot(frequency=80.0, title='Two-dimensional histogram')
plot.hist2d(real, imag)
plot.show()
Two-dimensional histogram

Contours#

Plot the contours of the density of phasor coordinates:

plot = PhasorPlot(frequency=80.0, title='Contours')
plot.contour(real, imag)
plot.show()
Contours

Image#

Plot a custom-colored image of a two-dimensional histogram (not implemented):

plot = PhasorPlot(frequency=80.0, title='Image (not implemented yet)')
# plot.imshow(image)
plot.show()
Image (not implemented yet)

Combined plots#

Multiple plots can be combined:

real2, imag2 = numpy.random.multivariate_normal(
    [0.9, 0.2], [[2e-4, -1e-4], [-1e-4, 2e-4]], 4096
).T

plot = PhasorPlot(
    xlim=(0.35, 1.03), ylim=(0.1, 0.59), grid=False, title='Combined plots'
)
plot.semicircle(frequency=80.0, color='tab:purple')
plot.hist2d(real, imag, bins=64, cmap='Blues')
plot.contour(real, imag, bins=48, levels=3, cmap='summer_r', norm='log')
plot.hist2d(real2, imag2, bins=64, cmap='Oranges')
plot.plot(0.6, 0.4, 'o', color='tab:blue', label='Blues')
plot.plot(0.9, 0.2, 'o', color='tab:orange', label='Oranges')
plot.cursor(0.9, 0.2, color='tab:orange', polar=True)
plot.polar_cursor(math.atan2(0.4, 0.6), math.hypot(0.6, 0.4), color='tab:blue')
plot.show()
Combined plots

All quadrants#

Create an empty phasor plot showing all four quadrants:

plot = PhasorPlot(allquadrants=True, title='All quadrants')
plot.show()
All quadrants

Custom grid#

Customize the polar grid of an all-quadrants plot:

plot = PhasorPlot(
    allquadrants=True,
    grid={
        'labels': ['', '450', '500 nm', '550', '600', '650', '700', ''],
        'ticks': [430, 450, 500, 550, 600, 650, 700, 730],
        'tick_space': numpy.linspace(430, 730, 16),
        'angles': 8,
        'radii': 2,
    },
    pad=0.2,  # make space for labels
    title='Custom grid',
)
plot.show()
Custom grid

Matplotlib axes#

The PhasorPlot class can use an existing matlotlib axes. The PhasorPlot.ax attribute provides access to the underlying matplotlib axes, for example, to add annotations:

from matplotlib import pyplot

ax = pyplot.subplot(1, 1, 1)
plot = PhasorPlot(ax=ax, allquadrants=True, title='Matplotlib axes')
plot.hist2d(real, imag, cmap='Blues')
plot.ax.annotate(
    '0.6, 0.4',
    xy=(0.6, 0.4),
    xytext=(0.2, 0.2),
    arrowprops={'arrowstyle': '->'},
)
pyplot.show()
Matplotlib axes

plot_phasor function#

The phasorpy.plot.plot_phasor() function provides a simpler alternative to plot phasor coordinates in a single statement:

from phasorpy.plot import plot_phasor

plot_phasor(
    real[0, :32],
    imag[0, :32],
    frequency=80.0,
    marker='.',
    title='plot_phasor function',
)
plot_phasor function

sphinx_gallery_thumbnail_number = -5 mypy: allow-untyped-defs, allow-untyped-calls mypy: disable-error-code=”arg-type”

Total running time of the script: (0 minutes 1.038 seconds)

Gallery generated by Sphinx-Gallery