Skip to content

Conversation

conradhaupt
Copy link
Contributor

Summary

The recent addition of the visualization module for Qiskit Experiments introduced plotters to the code-base (#902). This PR adds a new plotter subclass for plotting IQ data, typically acquired from experiments with level-1 results or during state-discrimination training (#936).

Details and comments

This PR adds a new IQPlotter class to plot IQ data for multiple prepared states and a discriminator which classifies the IQ points into state labels. The plotter takes in points and centroid data for different prepared states and creates a scatter plot with their values. Modifications were made to BaseDrawer and MplDrawer to add functionality to draw an image on a canvas, (i.e., equivalent to plt.imshow).

Usage of IQPlotter.

Below you can see a figure generated using IQPlotter for mock qutrit readout. The code used to generate this figure is given at the end of the PR description. The plotting class supports plotting individual points and centroids for multiple states, where states are different series. It also supports plotting the predictions of a trained discriminator over a region of the IQ space. This is done by sampling the discriminators predict() method for different IQ positions. The discriminator is passed as supplementary data to the plotter.

image

New BaseDrawer.image() method.

To allow plotters to draw images onto a canvas, BaseDrawer and MplDrawer had to be updated with new functionality. BaseDrawer.image() takes in a two-dimensional NumPy array of numerical values or strings, or a three-dimensional NumPy array of RGB/RGBA data. If two-dimensional numerical data is provided, the drawer will assign colours to the values based on the cmap parameter. image() also supports plotting images of classification labels, where the values in data are series names (str). Setting cmap_use_series_colors=True will tell the drawer to use the series colours (from other graphics already drawn on the canvas) as the colours for the image. This is used by IQPlotter to plot a discriminators predictions and match the colours to IQ points and centroids.

image() also has an extent parameter which defines the region for the image in the units of the X and Y axes. IQPlotter uses a helper class DataExtentCalculator to assist with precomputing the extent of the plotting data, so that the discriminator can be sampled to generate the prediction image.

Example code to generate the example figure.

import numpy as np
from qiskit_experiments.data_processing import SkLDA
from qiskit_experiments.visualization import IQPlotter, MplDrawer, PlotStyle
from sklearn.discriminant_analysis import LinearDiscriminantAnalysis

# Generate dummy qutrit data.
centers = [(-1, 1), (1, 1), (0.8, 2.5)]
widths = [0.3] * 3
states = [0, 1, 2]
n_shots = 8096

points, series_names = [], []
for cent, width, label in zip(centers, widths, states):
    p = np.zeros((n_shots, 2))
    for i in range(2):
        p[:, i] = np.random.normal(cent[i], width, (n_shots,))
    points.append(p)
    series_names.append(label)
centroids = [np.mean(x, axis=0) for x in points]

# Create and train linear discriminator
lda = LinearDiscriminantAnalysis()
sklda = SkLDA(lda)
sklda.fit(
    np.concatenate(points),
    np.asarray([[f"{l}"] * n_shots for l in series_names]).flatten().transpose(),
)

# Create IQPlotter and generate figure.
plotter = IQPlotter(MplDrawer())
plotter.set_options(
    discriminator_max_resolution=64,
    style=PlotStyle(figsize=(6, 4), legend_loc=None),
)
plotter.set_figure_options(
    series_params={
        "0": {"label": "$|0\\rangle$"},
        "1": {"label": "$|1\\rangle$"},
        "2": {"label": "$|2\\rangle$"},
    },
)
for p, c, n in zip(points, centroids, series_names):
    _name = f"{n}"
    plotter.set_series_data(_name, points=p, centroid=c)
plotter.set_supplementary_data(discriminator=sklda)
fig = plotter.figure()

@coruscating
Copy link
Collaborator

This looks nice! A feature that was useful in Ignis was being able to style the misclassified points with red crosses using a simple flag. Is there an easy way to do that with your plotter class without adding another series to the legend?

image

Also, plotting the distribution of shots projected to both I and Q axes can be useful for visualizing overlap, maybe that can be an optional visualization flag:
image

Copy link
Contributor

@eggerdj eggerdj left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This looks good. A few small comments.

@eggerdj
Copy link
Contributor

eggerdj commented Oct 18, 2022

I like the suggestions in #948 (comment) I think we could also do this in a follow-up PR (this would allow #936 to move forward in parallel to adding the suggested plotting functionality) since this plotting functionality requires a bit more code. From the user's perspective it should be easy to control through options. E.g.

flag_missclassified: bool
plot_marginals: bool

Copy link
Contributor

@eggerdj eggerdj left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

LGTM! Thanks.

@eggerdj eggerdj merged commit 0d4e1e9 into qiskit-community:main Oct 19, 2022
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

3 participants