Skip to content

Visualization ​

Visualize quantum circuits, quantum states, and simulation results using pyqpanda3's built-in drawing and plotting tools.

Prerequisites: Circuit Construction -- you should be comfortable building QProg and QCircuit objects before working through this tutorial.


Table of Contents ​


Overview ​

pyqpanda3 provides two layers of visualization tools:

  1. Core module (pyqpanda3.core) -- Circuit drawing functions (draw_qprog, PIC_TYPE, set_print_options) that produce text or LaTeX representations directly, no extra dependencies required.

  2. Visualization module (pyqpanda3.visualization) -- Rich plotting functions (Bloch sphere, state city plots, density matrices, probability bar charts) that depend on matplotlib for rendering graphical output.

The following diagram shows how these two layers relate to the quantum objects you create:

mermaid
graph TD
    subgraph "Quantum Objects"
        QProg["QProg"]
        QCircuit["QCircuit"]
        SimResult["Simulator Result"]
        StateVec["State Vector"]
    end

    subgraph "Core Drawing"
        DrawQprog["core.draw_qprog()"]
        PrintStr["print() / __str__"]
        SetPrint["core.set_print_options()"]
        PIC_TEXT["PIC_TYPE.TEXT"]
        PIC_LATEX["PIC_TYPE.LATEX"]
    end

    subgraph "visualization Module"
        PlotBloch["plot_bloch()"]
        PlotState["plot_state()"]
        PlotProb["plot_probabilities()"]
        CircuitSum["circuit_summary()"]
        DrawMember[".draw() method"]
    end

    QProg --> DrawQprog
    QProg --> PrintStr
    QProg --> DrawMember
    QCircuit --> DrawQprog
    QCircuit --> PrintStr
    QCircuit --> DrawMember
    StateVec --> PlotBloch
    StateVec --> PlotState
    SimResult --> PlotProb
    QProg --> CircuitSum
    QCircuit --> CircuitSum

    DrawQprog --> PIC_TEXT
    DrawQprog --> PIC_LATEX
    SetPrint -.-> PrintStr

    style QProg fill:#4a90d9,color:#fff
    style QCircuit fill:#50b86c,color:#fff
    style SimResult fill:#e8913a,color:#fff
    style StateVec fill:#7b68ee,color:#fff

1. Circuit Drawing ​

Circuit drawing is the most common visualization task. It renders a quantum circuit as a human-readable diagram showing qubit wires, gates, measurements, and their connectivity. pyqpanda3 supports three output formats: text (ASCII art), image (matplotlib), and LaTeX source code.

1.1 Quick Text Output with print() ​

The fastest way to visualize a circuit is the built-in print() function. Both QProg and QCircuit implement __repr__ so that print() renders a text circuit diagram automatically.

python
from pyqpanda3 import core

# Build a Bell state circuit
prog = core.QProg()
prog << core.H(0) << core.CNOT(0, 1) << core.measure([0, 1], [0, 1])

# Quick text rendering
print(prog)

运行结果:

          ┌─┐         ┌─┐     
q_0:  |0>─┤H├ ───*── ─┤M├──── 
          └─┘ ┌──┴─┐  └╥┘ ┌─┐ 
q_1:  |0>──── ┤CNOT├ ──╫──┤M├ 
              └────┘   ║  └╥┘ 
 c :   / ══════════════╩═══╩═
                        0   1

This produces a text circuit diagram showing the gate sequence on qubit wires:

          ┌─┐         ┌─┐
q_0:  |0>─┤H├ ───*── ─┤M├────
          └─┘ ┌──┴─┐  └╥┘ ┌─┐
q_1:  |0>──── ┤CNOT├ ──╫──┤M├
              └────┘   ║  └╥┘
 c :   / ══════════════╩═══╩═
                        0   1

You can also print a QCircuit object the same way:

python
circuit = core.QCircuit()
circuit << core.H(0) << core.RY(1, 1.57) << core.CNOT(0, 1)

print(circuit)

运行结果:

          ┌─┐                     
q_0:  |0>─┤H├───────────── ───*── 
          ├─┴────────────┐ ┌──┴─┐ 
q_1:  |0>─┤RY(1.57000000)├ ┤CNOT├ 
          └──────────────┘ └────┘ 
 c :   / ════════════════════════

The output displays each gate on the appropriate qubit wire, with control and target markers for two-qubit gates.

1.2 Drawing with core.draw_qprog() ​

The core.draw_qprog() function gives you more control over the output format and parameters. It accepts either a QProg or QCircuit as its first argument and a PIC_TYPE enum to select the output format.

The two available picture types are:

ConstantDescription
core.PIC_TYPE.TEXTASCII text diagram (default for most uses)
core.PIC_TYPE.LATEXLaTeX source code for publication-quality rendering

Text Output ​

python
from pyqpanda3 import core

prog = core.QProg()
prog << core.H(0) << core.CNOT(0, 1) << core.measure([0, 1], [0, 1])

# Draw as text with gate parameters shown
result = core.draw_qprog(
    prog,
    p=core.PIC_TYPE.TEXT,
    param_show=True,
    line_length=100
)
print(result)

运行结果:

          ┌─┐         ┌─┐     
q_0:  |0>─┤H├ ───*── ─┤M├──── 
          └─┘ ┌──┴─┐  └╥┘ ┌─┐ 
q_1:  |0>──── ┤CNOT├ ──╫──┤M├ 
              └────┘   ║  └╥┘ 
 c :   / ══════════════╩═══╩═
                        0   1

The param_show=True flag reveals numerical parameters on rotation gates (for example, showing the angle on an RX gate).

LaTeX Output ​

python
# Draw as LaTeX source code
latex_result = core.draw_qprog(
    prog,
    p=core.PIC_TYPE.LATEX,
    with_logo=False
)
print(latex_result)

运行结果:

Latex format is temporarily not supported

Note: The core.draw_qprog() function with PIC_TYPE.LATEX currently returns a placeholder message indicating that LaTeX generation via this API path is temporarily not supported. For working LaTeX output, use the .draw('latex') method described in Section 1.5.

Saving to File ​

Both text and LaTeX output can be saved directly to a file:

python
# Save text diagram to file
core.draw_qprog(
    prog,
    p=core.PIC_TYPE.TEXT,
    output_file="bell_circuit.txt"
)

# Save LaTeX source to file (via .draw() method)
prog.draw('latex', filename="bell_circuit.tex")

The output_file parameter writes the result to the specified path. When the output_file is empty (the default), the function returns the result as a string instead.

1.3 The draw() Member Method ​

Both QProg and QCircuit have a draw() method injected by the visualization module. This provides a convenient, object-oriented interface for circuit drawing. The method is available as soon as pyqpanda3 is imported.

python
from pyqpanda3 import core

prog = core.QProg()
prog << core.H(0) << core.CNOT(0, 1)

# Text output (default)
text = prog.draw()
print(text)

# Explicit text output
text = prog.draw('text')
print(text)

运行结果:

          ┌─┐        
q_0:  |0>─┤H├ ───*── 
          └─┘ ┌──┴─┐ 
q_1:  |0>──── ┤CNOT├ 
              └────┘ 
 c :   / ═══════════
                    



          ┌─┐        
q_0:  |0>─┤H├ ───*── 
          └─┘ ┌──┴─┐ 
q_1:  |0>──── ┤CNOT├ 
              └────┘ 
 c :   / ═══════════

The draw() method accepts the following keyword arguments:

ParameterTypeDefaultDescription
outputstr'text'Output format: 'text', 'pic', or 'latex'
filenamestrNoneSave output to this file path
scalefloat0.7Image scale factor ('pic' only)
foldint30Maximum image width in gates ('pic' only)
with_logoboolFalseInclude logo in LaTeX output
with_gate_paramsboolFalseShow gate parameters
line_lengthint100Maximum line length for text output
console_encode_typestr'utf8'Character encoding: 'utf8' or 'gbk'

1.4 Drawing as an Image (PIC) ​

The 'pic' output format uses matplotlib to render a colorful circuit diagram and save it as an image file (JPEG or PNG). This is useful for reports, presentations, and Jupyter notebooks.

python
from pyqpanda3 import core

prog = core.QProg()
prog << core.H(0) << core.CNOT(0, 1) << core.measure([0, 1], [0, 1])

# Save as JPEG with default filename
prog.draw('pic')

# Save to a custom path with custom scale
prog.draw('pic', filename='my_circuit.png', scale=0.5)

# Show gate parameters in the image
prog.draw('pic', filename='circuit_with_params.jpg', with_gate_params=True)

When using 'pic' output without specifying a filename, the image is saved to QCircuit_pic.jpg in the current working directory.

mermaid
flowchart LR
    A["QProg / QCircuit"] --> B[".draw('pic')"]
    B --> C["MatplotlibDrawer"]
    C --> D["JPEG / PNG file"]
    C --> E["Jupyter inline display"]

    style A fill:#4a90d9,color:#fff
    style D fill:#50b86c,color:#fff
    style E fill:#e8913a,color:#fff

1.5 LaTeX Output ​

LaTeX output produces source code that you can embed in academic papers, theses, or any LaTeX document. The output uses the qcircuit TikZ library for typesetting circuit diagrams.

python
from pyqpanda3 import core

prog = core.QProg()
prog << core.H(0) << core.T(1) << core.CNOT(0, 1)
prog << core.measure([0, 1], [0, 1])

# Get LaTeX source code
latex = prog.draw('latex')
print(latex)

# Save to .tex file with logo
prog.draw('latex', filename='paper_circuit.tex', with_logo=True)

# Also accessible via core.draw_qprog (returns placeholder text)
# Use prog.draw('latex') for working LaTeX output

运行结果:

\documentclass[border=2px]{standalone}
\usepackage[braket, qm]{qcircuit}
\usepackage{graphicx}
\begin{document}

\scalebox{1.0}{
\Qcircuit @C = 1.0em @R = 0.5em @!R { \\
\nghost{} & \lstick{\ket{q_0}} & \gate{\mathrm{H}} & \qw & \ctrl{1} & \meter & \qw & \rstick{}\qw & \nghost{} \\
\nghost{} & \lstick{\ket{q_1}} & \qw & \gate{\mathrm{T}} & \targ\qw & \qw & \meter & \rstick{}\qw & \nghost{} \\
\nghost{c0} & \lstick{\mathrm{c:c0}} & \cw & \cw & \cw & \dstick{__{0}}\cw \ar @{<=} [-2,0] & \cw & \rstick{}\cw & \nghost{} \\
\nghost{c1} & \lstick{\mathrm{c:c1}} & \cw & \cw & \cw & \cw & \dstick{__{1}}\cw \ar @{<=} [-2,0] & \rstick{}\cw & \nghost{} \\
}}
\end{document}

To compile the LaTeX output into a PDF, you need a LaTeX distribution with the qcircuit package installed. A minimal compilation command is:

bash
pdflatex circuit.tex

1.6 Drawing Parameters in Detail ​

param_show / with_gate_params ​

By default, parameterized gates (such as RX, RY, RZ, U3) are drawn without their numerical parameters. Set param_show=True (for core.draw_qprog) or with_gate_params=True (for .draw()) to display them:

python
from pyqpanda3 import core

prog = core.QProg()
prog << core.RX(0, 1.5708) << core.RY(1, 0.7854) << core.CNOT(0, 1)

# Without parameters (default)
print(prog.draw())

# With parameters
print(prog.draw(with_gate_params=True))

运行结果:

          ┌──┐        
q_0:  |0>─┤RX├ ───*── 
          ├──┤ ┌──┴─┐ 
q_1:  |0>─┤RY├ ┤CNOT├ 
          └──┘ └────┘ 
 c :   / ════════════
                     



          ┌──────────────┐        
q_0:  |0>─┤RX(1.57080000)├ ───*── 
          ├──────────────┤ ┌──┴─┐ 
q_1:  |0>─┤RY(0.78540000)├ ┤CNOT├ 
          └──────────────┘ └────┘ 
 c :   / ════════════════════════

When using LaTeX output, setting with_logo=True includes the pyqpanda3 logo in the circuit diagram header. This is mainly useful for presentations and demonstrations.

line_length ​

Controls the maximum number of characters per line in text output. Circuits that exceed this length wrap to multiple lines:

python
# Short lines for narrow terminals
result = prog.draw('text', line_length=60)

expend_map ​

The expend_map parameter controls expansion of nested circuits. Passing {"all": 1} expands all nested sub-circuits into individual gates:

python
# Expand all nested circuits
result = core.draw_qprog(
    prog,
    p=core.PIC_TYPE.TEXT,
    expend_map={"all": 1}
)

encode ​

Controls the character encoding for text output. The default is "utf-8". Use "gbk" for compatibility with terminals that use GBK encoding (common in some Chinese locales).


2. Print Options ​

The core.set_print_options() function configures global defaults for how circuit information is displayed when using print() or core.draw_qprog(). This affects all subsequent print operations in your session.

python
from pyqpanda3 import core

# Configure print options
core.set_print_options(
    precision=8,       # Decimal places for gate parameters
    param_show=True,   # Show gate parameters by default
    linewidth=100      # Maximum line width
)

Parameters ​

ParameterTypeDefaultDescription
precisionint8Number of decimal places for floating-point parameters
param_showboolTrueWhether to display gate parameters
linewidthint100Maximum line width for text output

Usage Example ​

python
from pyqpanda3 import core

# Build a circuit with parameterized gates
prog = core.QProg()
prog << core.RX(0, 3.14159265) << core.RY(1, 1.57079633) << core.CNOT(0, 1)

# Default print options
print("Default:")
print(prog)

# Set high precision with parameters visible
core.set_print_options(precision=4, param_show=True, linewidth=80)
print("\nWith options (precision=4, param_show=True):")
print(prog)

# Reset to defaults
core.set_print_options(precision=8, param_show=False, linewidth=100)

运行结果:

Default:

          ┌──────────────┐        
q_0:  |0>─┤RX(3.14159265)├ ───*── 
          ├──────────────┤ ┌──┴─┐ 
q_1:  |0>─┤RY(1.57079633)├ ┤CNOT├ 
          └──────────────┘ └────┘ 
 c :   / ════════════════════════
                                 



With options (precision=4, param_show=True):

          ┌──────────┐        
q_0:  |0>─┤RX(3.1416)├ ───*── 
          ├──────────┤ ┌──┴─┐ 
q_1:  |0>─┤RY(1.5708)├ ┤CNOT├ 
          └──────────┘ └────┘ 
 c :   / ════════════════════

The precision setting is particularly useful when working with variational circuits where you need to inspect parameter values during optimization.


3. The visualization Module ​

The pyqpanda3.visualization module provides rich graphical visualization tools that go beyond text-based circuit drawing. It depends on matplotlib for rendering and offers functions for Bloch sphere plots, state city visualizations, density matrix heatmaps, and probability bar charts.

3.1 Importing the Module ​

python
# Import specific functions
from pyqpanda3.visualization import (
    plot_bloch,
    plot_state,
    plot_probabilities,
    circuit_summary
)

# Or import the module as a whole
import pyqpanda3.visualization as viz

The module also exposes lower-level functions for specialized use cases:

python
from pyqpanda3.visualization import (
    plot_bloch_vector,
    plot_bloch_multivector,
    plot_bloch_circuit,
    plot_state_city,
    plot_density_matrix,
    draw_probability,
    draw_probability_dict
)

3.2 Bloch Sphere Visualization ​

The Bloch sphere is a geometric representation of a single-qubit quantum state. Any pure single-qubit state can be written as:

|ψ⟩=cos⁡θ2|0⟩+eiϕsin⁡θ2|1⟩

and represented as a point on the unit sphere with coordinates (x,y,z) where:

x=sin⁡θcos⁡ϕ,y=sin⁡θsin⁡ϕ,z=cos⁡θ

The visualization module provides three functions for Bloch sphere rendering:

plot_bloch_vector(bloch, title, axis_obj, fig_size) ​

Plot a single Bloch vector on a 3D sphere. The input is a list of three floats [x, y, z] representing the Cartesian coordinates of the Bloch vector.

python
from pyqpanda3.visualization import plot_bloch_vector

# Plot the |0> state (north pole, z-axis)
plot_bloch_vector([0, 0, 1], title="|0> state")

# Plot the |1> state (south pole)
plot_bloch_vector([0, 0, -1], title="|1> state")

# Plot the |+> state (x-axis)
plot_bloch_vector([1, 0, 0], title="|+> state")

# Plot the |-i> state (-y-axis)
plot_bloch_vector([0, -1, 0], title="|-i> state")

Common single-qubit states and their Bloch vectors:

StateBloch VectorDescription
|0⟩[0, 0, 1]North pole
|1⟩[0, 0, -1]South pole
|+⟩=12(|0⟩+|1⟩)[1, 0, 0]+X direction
|−⟩=12(|0⟩−|1⟩)[-1, 0, 0]-X direction
|+i⟩=12(|0⟩+i|1⟩)[0, 1, 0]+Y direction
|−i⟩=12(|0⟩−i|1⟩)[0, -1, 0]-Y direction

plot_bloch_multivector(state, title, fig_size) ​

Plot each qubit of a multi-qubit state on its own Bloch sphere. This function takes a state vector (list or numpy array) and computes the reduced density matrix for each qubit to determine its Bloch vector.

python
import numpy as np
from pyqpanda3.visualization import plot_bloch_multivector

# Bell state: (|00> + |11>) / sqrt(2)
# Each qubit is maximally mixed -> Bloch vector at origin
bell_state = np.array([1, 0, 0, 1]) / np.sqrt(2)
plot_bloch_multivector(bell_state, title="Bell State Qubits")

# Product state: |+>|0>
# Qubit 0 at +X, qubit 1 at +Z
product_state = np.array([1, 1, 0, 0]) / np.sqrt(2)
plot_bloch_multivector(product_state, title="|+>|0> State")

For entangled states like the Bell state, the reduced state of each individual qubit is a maximally mixed state, so the Bloch vector sits at the origin. This is a visual indication of entanglement.

plot_bloch_circuit(circuit, trace, saveas, fps, secs_per_gate) ​

Animate the evolution of a single-qubit circuit on the Bloch sphere. This function traverses the circuit gate by gate, showing how each gate rotates the state vector on the sphere. It supports common single-qubit gates: H, X, Y, Z, RX, RY, RZ, S, T, and their dagger variants.

python
from pyqpanda3 import core
from pyqpanda3.visualization import plot_bloch_circuit

# Build a single-qubit circuit
circuit = core.QCircuit()
circuit << core.H(0)
circuit << core.RY(0, 1.5708)  # pi/2 rotation
circuit << core.Z(0)

# Animate the circuit on the Bloch sphere
plot_bloch_circuit(
    circuit,
    trace=True,          # Show the path of the state vector
    saveas='bloch_animation.gif',  # Save as animated GIF
    fps=20,              # Frames per second
    secs_per_gate=1      # Duration per gate in seconds
)

When trace=True, the animation draws a colored trail showing the path of the state vector as each gate is applied. Each gate has a distinct color to help you follow the evolution.

mermaid
sequenceDiagram
    participant C as Circuit
    participant B as Bloch Sphere

    Note over B: Initial state: |0> (north pole)
    C->>B: H(0)
    Note over B: State rotates to |+> (equator, +X)
    C->>B: RY(0, pi/2)
    Note over B: State rotates around Y axis
    C->>B: Z(0)
    Note over B: Phase flip around Z axis

Unified plot_bloch() Interface ​

The plot_bloch() function provides a unified interface that automatically detects the input type and calls the appropriate function:

python
from pyqpanda3 import core
from pyqpanda3.visualization import plot_bloch

# Single Bloch vector (list/tuple of 3 numbers)
plot_bloch([1, 0, 0], title="X State")

# State vector (array-like)
import numpy as np
state = np.array([1, 0, 0, 1]) / np.sqrt(2)
plot_bloch(state, title="Bell State")

# Circuit (single-qubit only)
circuit = core.QCircuit()
circuit << core.H(0) << core.T(0)
plot_bloch(circuit)

3.3 State City Plots ​

State city plots provide a 3D visualization of a quantum state's density matrix. They show both the real and imaginary parts of the density matrix as side-by-side bar charts, giving you an intuitive picture of the state's structure.

The density matrix for a pure state |ψ⟩ is:

ρ=|ψ⟩⟨ψ|

plot_state_city(state, title, figsize, color) ​

python
import numpy as np
from pyqpanda3.visualization import plot_state_city

# Bell state density matrix
bell_state = np.array([1, 0, 0, 1]) / np.sqrt(2)
plot_state_city(bell_state, title="Bell State Density Matrix")

# Custom colors and figure size
plot_state_city(
    bell_state,
    title="Bell State",
    figsize=(12, 4),
    color=["#1f77b4", "#ff7f0e"]  # [real color, imaginary color]
)

The function accepts either a state vector (1D array) or a density matrix (2D array). When given a state vector, it computes the density matrix automatically.

The left subplot shows Re[ρ] and the right shows Im[ρ]. For a Bell state |Φ+⟩=12(|00⟩+|11⟩), the density matrix is:

ρBell=12(1001000000001001)

All entries are real, so the imaginary part is zero and the right subplot shows a flat surface.

Unified plot_state() Interface ​

python
from pyqpanda3.visualization import plot_state
import numpy as np

state = np.array([1, 0, 0, 1]) / np.sqrt(2)

# City plot (default)
plot_state(state, kind='city', title="Bell State")

# Density matrix heatmap
rho = np.outer(state, np.conj(state))
plot_state(rho, kind='density', title="Bell State")

The kind parameter selects the visualization type: 'city' for a 3D bar plot, 'density' for a heatmap with phase coloring.

3.4 Density Matrix Visualization ​

The plot_density_matrix() function renders the density matrix as a 3D bar chart where the height of each bar represents the absolute value |ρij| and the color encodes the complex phase arg⁡(ρij).

python
import numpy as np
from pyqpanda3.visualization import plot_density_matrix

# Create a mixed state density matrix
rho = np.array([
    [0.5, 0.0, 0.0, 0.5],
    [0.0, 0.0, 0.0, 0.0],
    [0.0, 0.0, 0.0, 0.0],
    [0.5, 0.0, 0.0, 0.5]
])

fig, ax = plot_density_matrix(
    rho,
    title="Bell State Density Matrix",
    xlabels=['00', '01', '10', '11'],
    ylabels=['00', '01', '10', '11']
)

The color bar maps the phase angle from −π to π, making it easy to identify phase relationships between matrix elements.

3.5 Probability Bar Charts ​

Probability bar charts visualize measurement outcome distributions. They are useful for inspecting simulator results and understanding the output distribution of quantum circuits.

plot_probabilities(data, title, figsize, top_k, save) ​

The unified plot_probabilities() function accepts either a dictionary mapping state labels to probabilities, or a list/array of probabilities:

python
from pyqpanda3.visualization import plot_probabilities

# From a dictionary
plot_probabilities(
    {'00': 0.5, '11': 0.5},
    title="Bell State Probabilities"
)

# From a raw array (auto-generates labels)
probs = [0.5, 0, 0, 0.5]
plot_probabilities(probs, title="Bell State")

# Show only top-K most probable outcomes
noisy_results = {
    '000': 0.485, '111': 0.492,
    '001': 0.008, '010': 0.006,
    '100': 0.005, '011': 0.004
}
plot_probabilities(noisy_results, top_k=3, title="Noisy GHZ (top 3)")

When top_k is specified, only the k most probable outcomes are displayed. This is useful for circuits with many qubits where most basis states have near-zero probability.

draw_probability() and draw_probability_dict() ​

Lower-level functions for backward compatibility:

python
from pyqpanda3.visualization import draw_probability, draw_probability_dict

# From a dictionary of counts or probabilities
data = {'00': 497, '11': 503}
draw_probability(data)

# From a probability dictionary (filters zero entries)
draw_probability_dict({'|00>': 0.5, '|11>': 0.5})

Computing Probabilities from Simulation Results ​

A typical workflow combines simulation with probability visualization:

python
from pyqpanda3 import core
from pyqpanda3.visualization import plot_probabilities

# Build and run a circuit
prog = core.QProg()
prog << core.H(0) << core.CNOT(0, 1) << core.measure([0, 1], [0, 1])

machine = core.CPUQVM()
machine.run(prog, shots=10000)
counts = machine.result().get_counts()

# Convert counts to probabilities
total = sum(counts.values())
probs = {state: count / total for state, count in counts.items()}

# Visualize
plot_probabilities(probs, title="Bell State Measurement (10000 shots)")

3.6 Circuit Summary ​

The circuit_summary() function provides a statistical overview of a circuit's composition: how many single-qubit gates, two-qubit gates, and multi-control gates it contains, along with layer information.

python
from pyqpanda3 import core
from pyqpanda3.visualization import circuit_summary

prog = core.QProg()
prog << core.H(0) << core.H(1)
prog << core.CNOT(0, 1) << core.SWAP(1, 2)
prog << core.measure([0, 1, 2], [0, 1, 2])

# Get summary (optionally display pie chart)
summary = circuit_summary(prog, show=False)

# Print textual summary
print(summary)

# Access statistics programmatically
info = summary.info
print(f"Total nodes:    {info.node_num}")
print(f"Single gates:   {info.single_gate_num}")
print(f"Two-qubit gates: {info.double_gate_num}")
print(f"Total layers:   {info.layer_num}")
print(f"Single layers:  {info.single_gate_layer_num}")
print(f"Double layers:  {info.double_gate_layer_num}")

运行结果:

ProgInfo(single_gate_num=2, double_gate_num=2, multi_control_gate_num=0, node_num=4, single_gate_layer_num=1, double_gate_layer_num=2, layer_num=3)
Total nodes:    4
Single gates:   2
Two-qubit gates: 2
Total layers:   3
Single layers:  1
Double layers:  2

When show=True (the default), circuit_summary() displays a pair of pie charts showing the distribution of gate types and layer types. This is useful for quickly assessing circuit complexity and estimating execution cost on hardware.

3.7 Time Scheduling Diagrams ​

Starting in pyqpanda3 0.4.0, the visualization module can render time scheduling diagrams — timeline views showing when each gate executes on each physical qubit. This is essential for understanding how a transpiled circuit will behave on real superconducting hardware, where gate durations and parallelism matter.

The workflow has three stages:

  1. Transpile and export — Decompose to native gates, transpile for the target hardware, then call QProg.to_instruction(backend, is_scheduling=True) to produce an instruction JSON stream with timing data.
  2. Parse — Use parse_instruction_schedule() to convert the JSON into normalized InstructionScheduleItem objects.
  3. Draw — Use draw_time_scheduling() to render a Matplotlib or Plotly timeline figure.
mermaid
flowchart LR
    A["QProg"] --> B["decompose + transpile"]
    B --> C["to_instruction()"]
    C --> D["parse_instruction_schedule()"]
    D --> E["draw_time_scheduling()"]
    E --> F["Matplotlib / Plotly figure"]

    style A fill:#4a90d9,color:#fff
    style F fill:#50b86c,color:#fff

Building and Exporting a Schedule ​

First, create a circuit and prepare it for instruction export:

python
from pyqpanda3 import core
from pyqpanda3.transpilation import ChipBackend, decompose

# Build a circuit
qc = core.QCircuit()
qc.append(core.X(core.Qubit(0)))
qc.append(core.H(core.Qubit(1)))
qc.append(core.CNOT(core.Qubit(0), core.Qubit(1)))
q = core.QProg()
q.append(qc)

# Decompose to native gates and transpile
decomposed = decompose(q, ["X1", "RZ", "CZ", "RPhi"])
cb = ChipBackend()
cb.chip_topology_edges = [[0, 1]]
cb.single_gate_timing = 40
cb.double_gate_timing = 80

# Export instruction JSON with timing
instruction = decomposed.to_instruction(cb, offset=1, is_scheduling=True)
print(instruction)

运行结果:

text
[{"RPhi":[1,0.0,90.0,0]},{"RPhi":[2,270.0,90.0,0]},{"RPhi":[1,0.0,90.0,0]},{"RPhi":[2,90.0,90.0,0]},{"CZ":[1,2,0]},{"RPhi":[2,270.0,90.0,0]}]

Each instruction is a single-key object: RPhi carries [qubit, angle, phi, start_time], CZ carries [q0, q1, start_time], and Measure carries [[q0, q1, ...], start_time].

Parsing and Inspecting the Schedule ​

python
from pyqpanda3.visualization import parse_instruction_schedule

items = parse_instruction_schedule(
    instruction,
    durations={"RPhi": 40, "CZ": 80},
)

for item in items:
    print(f"{item.name:8s} q{item.qubits}  t={item.start_time:3d}  dur={item.duration}")

运行结果:

text
RPhi     q(1,)  t=  0  dur=40.0
RPhi     q(2,)  t=  0  dur=40.0
RPhi     q(1,)  t=  0  dur=40.0
RPhi     q(2,)  t=  0  dur=40.0
CZ       q(1, 2) t=  0  dur=80.0
RPhi     q(2,)  t=  0  dur=40.0

Each InstructionScheduleItem has fields: name, qubits (tuple), start_time, duration, params (tuple), order, and is_marker. The end_time property returns start_time + duration.

Drawing the Timeline ​

python
from pyqpanda3.visualization import draw_time_scheduling

fig = draw_time_scheduling(
    instruction,
    durations={"RPhi": 40, "CZ": 80},
    title="Two-Qubit Schedule",
    qubit_offset=-1,
)
fig.savefig("schedule.png", dpi=150)

The output parameter controls the rendering backend:

  • output="mpl" (default) — Returns a Matplotlib Figure.
  • output="plotly" — Returns a Plotly Figure.

Key drawing parameters:

ParameterTypeDefaultDescription
outputstr"mpl"Rendering backend: "mpl" for Matplotlib, "plotly" for Plotly.
durationsdictNoneGate-name to duration overrides.
backendChipBackendNoneTiming source (single_gate_timing, double_gate_timing).
qubit_offsetint-1Display offset: -1 maps physical q[1] to displayed q[0].
titlestr"QProg Instruction Schedule"Figure title.
merge_common_instructionsboolFalseMerge temporally adjacent same-type instructions.
gate_filterlist[str]NoneOnly draw specified gate names.
filter_measureboolFalseRemove Measure markers from the plot.
time_range(float, float)NoneRestrict drawing to a cycle range.
max_qubits_per_panelintNoneSplit vertically into panels of at most N qubits each.

When using output="plotly", use fig.write_html("schedule.html") to save the interactive figure instead of fig.savefig().

Complete End-to-End Example ​

python
from pyqpanda3 import core
from pyqpanda3.transpilation import ChipBackend, Transpiler, decompose
from pyqpanda3.visualization import draw_time_scheduling, parse_instruction_schedule

# Build and transpile
qc = core.QCircuit()
qc.append(core.X(core.Qubit(0)))
qc.append(core.H(core.Qubit(1)))
qc.append(core.CNOT(core.Qubit(0), core.Qubit(1)))
q = core.QProg()
q.append(qc)

backend = ChipBackend()
backend.chip_topology_edges = [[0, 1]]
backend.basic_gates = ["RPhi", "CZ"]
backend.single_gate_timing = 40
backend.double_gate_timing = 80

transpiler = Transpiler()
transpiled = transpiler.transpile(q, backend, {}, 2)
# Decompose to X1/RZ/CZ — to_instruction calls virtual_z internally
decomposed = decompose(transpiled, ["X1", "RZ", "CZ"])
instruction = decomposed.to_instruction(backend, offset=1, is_scheduling=True)

# Parse and draw
schedule = parse_instruction_schedule(instruction, backend=backend)
print(f"Total instructions: {len(schedule)}")
print(f"Qubits used: {sorted(set(q for item in schedule for q in item.qubits))}")

fig = draw_time_scheduling(
    instruction,
    backend=backend,
    title="Transpiled Circuit Schedule",
    merge_common_instructions=True,
)
fig.savefig("transpiled_schedule.png", dpi=150)

运行结果:

text
Total instructions: 5
Qubits used: [1, 2]

Durations are resolved in priority order: (1) explicit durations dict, (2) backend timing attributes, (3) gate payload duration (for IDLE), and (4) missing durations become zero-duration markers.


4. Practical Examples ​

4.1 Drawing a Bell State Circuit ​

This complete example builds a Bell state circuit and demonstrates all three output formats:

python
from pyqpanda3 import core

# Build the Bell state circuit
prog = core.QProg()
prog << core.H(0)
prog << core.CNOT(0, 1)
prog << core.measure([0, 1], [0, 1])

# 1. Quick text print
print("=== Text via print() ===")
print(prog)

# 2. Text with parameters via core.draw_qprog
print("\n=== Text via draw_qprog ===")
text = core.draw_qprog(prog, p=core.PIC_TYPE.TEXT, param_show=True)
print(text)

# 3. LaTeX output
print("\n=== LaTeX ===")
latex = core.draw_qprog(prog, p=core.PIC_TYPE.LATEX)
print(latex)

# 4. Save as image
prog.draw('pic', filename='bell_state.jpg')
print("\nImage saved to bell_state.jpg")

运行结果:

=== Text via print() ===

          ┌─┐         ┌─┐     
q_0:  |0>─┤H├ ───*── ─┤M├──── 
          └─┘ ┌──┴─┐  └╥┘ ┌─┐ 
q_1:  |0>──── ┤CNOT├ ──╫──┤M├ 
              └────┘   ║  └╥┘ 
 c :   / ══════════════╩═══╩═
                        0   1



=== Text via draw_qprog ===

          ┌─┐         ┌─┐     
q_0:  |0>─┤H├ ───*── ─┤M├──── 
          └─┘ ┌──┴─┐  └╥┘ ┌─┐ 
q_1:  |0>──── ┤CNOT├ ──╫──┤M├ 
              └────┘   ║  └╥┘ 
 c :   / ══════════════╩═══╩═
                        0   1



=== LaTeX ===
Latex format is temporarily not supported

Image saved to bell_state.jpg

4.2 Drawing Parameterized Circuits ​

Parameterized circuits are common in variational algorithms. Use param_show=True or with_gate_params=True to inspect parameter values in the circuit diagram:

python
import math
from pyqpanda3 import core

# Build a parameterized circuit
prog = core.QProg()
prog << core.H(0)
prog << core.RY(0, math.pi / 4)
prog << core.RX(1, math.pi / 3)
prog << core.CNOT(0, 1)
prog << core.RZ(0, 0.7854)
prog << core.U3(1, 0.1, 0.2, 0.3)
prog << core.measure([0, 1], [0, 1])

# Draw without parameters
print("Without parameters:")
print(prog.draw())

# Draw with parameters
print("\nWith parameters:")
print(prog.draw(with_gate_params=True))

# Save image with parameters visible
prog.draw('pic', filename='param_circuit.jpg', with_gate_params=True)

# Set global print options so parameters always show
core.set_print_options(precision=4, param_show=True)
print("\nAfter set_print_options:")
print(prog)

运行结果:

Without parameters:

          ┌─┐  ┌──┐        ┌──┐  ┌─┐     
q_0:  |0>─┤H├─ ┤RY├ ───*── ┤RZ├ ─┤M├──── 
          ├─┴┐ └──┘ ┌──┴─┐ ├──┤  └╥┘ ┌─┐ 
q_1:  |0>─┤RX├ ──── ┤CNOT├ ┤U3├ ──╫──┤M├ 
          └──┘      └────┘ └──┘   ║  └╥┘ 
 c :   / ═════════════════════════╩═══╩═
                                   0   1



With parameters:

          ┌─┐              ┌──────────────┐        ┌──────────────┐                          ┌─┐     
q_0:  |0>─┤H├───────────── ┤RY(0.78539816)├ ───*── ┤RZ(0.78540000)├──────────────────────── ─┤M├──── 
          ├─┴────────────┐ └──────────────┘ ┌──┴─┐ ├──────────────┴───────────────────────┐  └╥┘ ┌─┐ 
q_1:  |0>─┤RX(1.04719755)├ ──────────────── ┤CNOT├ ┤U3(0.10000000, 0.20000000, 0.30000000)├ ──╫──┤M├ 
          └──────────────┘                  └────┘ └──────────────────────────────────────┘   ║  └╥┘ 
 c :   / ═════════════════════════════════════════════════════════════════════════════════════╩═══╩═
                                                                                               0   1



After set_print_options:

          ┌─┐          ┌──────────┐        ┌──────────┐                  ┌─┐     
q_0:  |0>─┤H├───────── ┤RY(0.7854)├ ───*── ┤RZ(0.7854)├──────────────── ─┤M├──── 
          ├─┴────────┐ └──────────┘ ┌──┴─┐ ├──────────┴───────────────┐  └╥┘ ┌─┐ 
q_1:  |0>─┤RX(1.0472)├ ──────────── ┤CNOT├ ┤U3(0.1000, 0.2000, 0.3000)├ ──╫──┤M├ 
          └──────────┘              └────┘ └──────────────────────────┘   ║  └╥┘ 
 c :   / ═════════════════════════════════════════════════════════════════╩═══╩═
                                                                           0   1

4.3 Drawing Large Circuits ​

Large circuits require careful management of line length and image dimensions. Here are techniques for handling circuits with many qubits or many gates:

python
from pyqpanda3 import core

# Build a 6-qubit GHZ-like circuit
prog = core.QProg()
prog << core.H(0)
for i in range(1, 6):
    prog << core.CNOT(i - 1, i)
prog << core.measure(list(range(6)), list(range(6)))

# Use longer line length for wide circuits
text = core.draw_qprog(prog, p=core.PIC_TYPE.TEXT, line_length=150)
print(text)

# For image output, use a larger fold value to fit more gates per row
prog.draw('pic', filename='large_circuit.jpg', fold=50, scale=0.5)

运行结果:

          ┌─┐               ┌─┐                                           
q_0:  |0>─┤H├ ───*── ───────┤M├ ────────── ────────── ────────── ──────── 
          └─┘ ┌──┴─┐        └╥┘        ┌─┐                                
q_1:  |0>──── ┤CNOT├ ───*────╫─ ───────┤M├ ────────── ────────── ──────── 
              └────┘ ┌──┴─┐  ║         └╥┘        ┌─┐                     
q_2:  |0>──── ────── ┤CNOT├──╫─ ───*────╫─ ───────┤M├ ────────── ──────── 
                     └────┘  ║  ┌──┴─┐  ║         └╥┘        ┌─┐          
q_3:  |0>──── ────── ────────╫─ ┤CNOT├──╫─ ───*────╫─ ───────┤M├ ──────── 
                             ║  └────┘  ║  ┌──┴─┐  ║         └╥┘  ┌─┐     
q_4:  |0>──── ────── ────────╫─ ────────╫─ ┤CNOT├──╫─ ───*────╫─ ─┤M├──── 
                             ║          ║  └────┘  ║  ┌──┴─┐  ║   └╥┘ ┌─┐ 
q_5:  |0>──── ────── ────────╫─ ────────╫─ ────────╫─ ┤CNOT├──╫─ ──╫──┤M├ 
                             ║          ║          ║  └────┘  ║    ║  └╥┘ 
 c :   / ════════════════════╩══════════╩══════════╩══════════╩════╩═══╩═
                              0          1          2          3    4   5

For very large circuits (20+ qubits), text output may become unwieldy. In these cases, use the LaTeX output and compile it to PDF, or use circuit_summary() to inspect statistics rather than the full diagram:

python
from pyqpanda3.visualization import circuit_summary

# Get statistics instead of full diagram
summary = circuit_summary(prog, show=True)
print(f"\nCircuit has {summary.info.node_num} gates across {summary.info.layer_num} layers")

运行结果:

Circuit has 6 gates across 6 layers

4.4 Exporting to File ​

pyqpanda3 supports exporting circuit diagrams in multiple file formats for different use cases:

python
from pyqpanda3 import core

prog = core.QProg()
prog << core.H(0) << core.CNOT(0, 1) << core.measure([0, 1], [0, 1])

# Text file (useful for version control and diffs)
core.draw_qprog(prog, p=core.PIC_TYPE.TEXT, output_file="circuit.txt")

# LaTeX file (for papers and presentations)
prog.draw('latex', filename="circuit.tex", with_logo=True)

# Image file (for reports and quick sharing)
prog.draw('pic', filename='circuit_diagram.png', scale=0.7)

# Alternative: use the draw() method with filename
prog.draw('text', filename='circuit_text.txt')
prog.draw('latex', filename='circuit_latex.tex')

The following table summarizes the output formats and their typical use cases:

FormatFile ExtensionBest For
Text.txtDebugging, terminal output, version control
LaTeX.texAcademic papers, presentations, documentation
Image.jpg, .pngReports, slides, quick sharing, Jupyter
mermaid
flowchart TD
    A["QProg / QCircuit"] --> B{Choose Format}
    B -->|Terminal / Debug| C["Text (.txt)"]
    B -->|Paper / Presentation| D["LaTeX (.tex)"]
    B -->|Report / Quick View| E["Image (.jpg/.png)"]

    C --> F["print() or .draw('text')"]
    D --> G[".draw('latex')"]
    E --> H[".draw('pic')"]

    F --> I["Console output or text file"]
    G --> J["pdflatex -> PDF"]
    H --> K["JPEG/PNG image file"]

    style A fill:#4a90d9,color:#fff
    style I fill:#50b86c,color:#fff
    style J fill:#7b68ee,color:#fff
    style K fill:#e8913a,color:#fff

4.5 Visualizing a GHZ State End-to-End ​

This example demonstrates a complete workflow: build a circuit, simulate it, draw the circuit diagram, and visualize the results.

python
from pyqpanda3 import core
from pyqpanda3.visualization import plot_probabilities, plot_bloch_multivector, circuit_summary

# Build a 3-qubit GHZ state circuit
prog = core.QProg()
prog << core.H(0)
prog << core.CNOT(0, 1)
prog << core.CNOT(1, 2)
prog << core.measure([0, 1, 2], [0, 1, 2])

# Step 1: Draw the circuit
print("=== Circuit Diagram ===")
print(prog.draw())

# Step 2: Get circuit statistics
print("\n=== Circuit Summary ===")
summary = circuit_summary(prog, show=False)
print(f"Gates: {summary.info.node_num}, Layers: {summary.info.layer_num}")
print(f"Single-qubit gates: {summary.info.single_gate_num}")
print(f"Two-qubit gates: {summary.info.double_gate_num}")

# Step 3: Simulate
machine = core.CPUQVM()
machine.run(prog, shots=10000)

# Step 4: Visualize probabilities
counts = machine.result().get_counts()
total = sum(counts.values())
probs = {state: count / total for state, count in counts.items()}
plot_probabilities(probs, title="GHZ State Probabilities (10000 shots)")

# Step 5: Visualize the GHZ state on Bloch spheres
# (requires the state vector before measurement)
ghz_circuit = core.QCircuit()
ghz_circuit << core.H(0) << core.CNOT(0, 1) << core.CNOT(1, 2)
state = ghz_circuit.matrix()[:, 0]  # first column = |000> input
plot_bloch_multivector(state, title="GHZ State (Per-Qubit Bloch)")

For the GHZ state |GHZ3⟩=12(|000⟩+|111⟩), each individual qubit is maximally mixed, so all three Bloch sphere vectors point to the origin. This is expected because tracing out any two qubits leaves the remaining one in the maximally mixed state I2.

4.6 Bloch Sphere Animation of a Single-Qubit Circuit ​

This example creates an animated Bloch sphere visualization showing how a sequence of gates transforms a single qubit:

python
import math
from pyqpanda3 import core
from pyqpanda3.visualization import plot_bloch_circuit, plot_bloch_vector

# Build a single-qubit circuit with several gates
circuit = core.QCircuit()
circuit << core.H(0)              # Move to equator (+X)
circuit << core.T(0)              # Rotate pi/4 around Z
circuit << core.RY(0, math.pi/4)  # Tilt toward +Z
circuit << core.Z(0)              # Flip phase

# Animate the circuit on the Bloch sphere
plot_bloch_circuit(
    circuit,
    trace=True,
    saveas='single_qubit_evolution.gif',
    fps=20,
    secs_per_gate=1
)

# Static visualization of specific states
from pyqpanda3.visualization import plot_bloch

# Show the |0> starting state
plot_bloch([0, 0, 1], title="Initial |0> state")

# Show the state after Hadamard (|+>)
plot_bloch([1, 0, 0], title="After H: |+> state")

# Show the state after H then T
plot_bloch([1/math.sqrt(2), 1/math.sqrt(2), 0], title="After H+T")

The animation proceeds through each gate in order, showing the state vector rotating on the sphere. The trace=True parameter leaves a colored trail so you can see the full path of the state.


5. Visualization Workflow ​

The following diagram illustrates the complete visualization workflow in pyqpanda3, from circuit construction to visual output:

mermaid
flowchart TD
    A["Build Circuit<br/>(QProg / QCircuit)"] --> B{What to visualize?}

    B -->|"Circuit diagram"| C{Output format?}
    C -->|"Quick view"| D["print(prog)"]
    C -->|"Text file"| E["core.draw_qprog(..., TEXT)"]
    C -->|"LaTeX / PDF"| F["prog.draw('latex')"]
    C -->|"Image"| G["prog.draw('pic')"]

    B -->|"Quantum state"| H{How many qubits?}
    H -->|"1 qubit"| I["plot_bloch_vector()"]
    H -->|"Multi-qubit"| J["plot_bloch_multivector()"]
    H -->|"Density matrix"| K["plot_state_city() or plot_density_matrix()"]

    B -->|"Measurement results"| L["plot_probabilities()"]
    B -->|"Circuit statistics"| M["circuit_summary()"]
    B -->|"State evolution"| N["plot_bloch_circuit()"]
    B -->|"Instruction timing"| O["draw_time_scheduling()"]

    style A fill:#4a90d9,color:#fff
    style D fill:#50b86c,color:#fff
    style E fill:#50b86c,color:#fff
    style F fill:#7b68ee,color:#fff
    style G fill:#e8913a,color:#fff
    style I fill:#c0392b,color:#fff
    style J fill:#c0392b,color:#fff
    style K fill:#c0392b,color:#fff
    style L fill:#2ecc71,color:#fff
    style M fill:#2ecc71,color:#fff
    style N fill:#c0392b,color:#fff
    style O fill:#c0392b,color:#fff

Decision Guide ​

Your GoalRecommended Function
Quick circuit inspectionprint(prog)
Save circuit to text filecore.draw_qprog(prog, p=core.PIC_TYPE.TEXT, output_file='out.txt')
Circuit image for a reportprog.draw('pic', filename='circuit.jpg')
Circuit for a paper (LaTeX)prog.draw('latex', filename='circuit.tex')
See gate parametersprog.draw(with_gate_params=True) or core.set_print_options(param_show=True)
Inspect a single-qubit stateplot_bloch_vector([x, y, z])
Inspect a multi-qubit stateplot_bloch_multivector(state_vector)
View density matrix structureplot_state_city(state) or plot_state(state, kind='density')
View measurement distributionplot_probabilities(counts_dict)
Animate single-qubit evolutionplot_bloch_circuit(circuit)
Get circuit gate statisticscircuit_summary(prog)
Visualize instruction timingdraw_time_scheduling(instruction, backend=...)

6. API Quick Reference ​

Core Module (pyqpanda3.core) ​

Function / ConstantDescription
core.draw_qprog(prog, p, ...)Draw circuit as text or LaTeX
core.PIC_TYPE.TEXTText output format
core.PIC_TYPE.LATEXLaTeX output format
core.set_print_options(precision, param_show, linewidth)Configure global print settings

core.draw_qprog() Parameters ​

ParameterTypeDefaultDescription
progQProg or QCircuit(required)Circuit to draw
pPIC_TYPEPIC_TYPE.TEXTOutput format
expend_mapdictNoneControl expansion, e.g., {"all": 1}
param_showboolFalseShow gate parameters
with_logoboolFalseInclude logo (LaTeX only)
line_lengthint100Max line length (text only)
output_filestr""Save to file (empty = return string)
encodestr"utf-8"Character encoding

Member Method (.draw()) ​

ParameterTypeDefaultDescription
outputstr'text''text', 'pic', or 'latex'
filenamestrNoneOutput file path
scalefloat0.7Image scale (pic only)
foldint30Max image width in gates (pic only)
with_logoboolFalseInclude logo (LaTeX only)
with_gate_paramsboolFalseShow gate parameters
line_lengthint100Max line length (text only)
console_encode_typestr'utf8''utf8' or 'gbk'

Visualization Module (pyqpanda3.visualization) ​

FunctionDescription
plot_bloch(state, title, figsize, save)Unified Bloch sphere interface
plot_bloch_vector(bloch, title, axis_obj, fig_size)Single Bloch vector
plot_bloch_multivector(state, title, fig_size)Per-qubit Bloch spheres
plot_bloch_circuit(circuit, trace, saveas, fps, secs_per_gate)Animate circuit on Bloch sphere
plot_state(state, kind, title, figsize)Unified state visualization
plot_state_city(state, title, figsize, color)3D density matrix bars
plot_density_matrix(M, title, ...)Density matrix heatmap
plot_probabilities(data, title, figsize, top_k, save)Probability bar chart
circuit_summary(prog, show)Circuit statistics and pie charts
InstructionScheduleItemFrozen dataclass for one normalized instruction
parse_instruction_schedule(instruction, durations, backend)Parse instruction JSON into schedule items
draw_time_scheduling(instruction, durations, backend, output, ...)Draw instruction timing diagram

Summary ​

In this tutorial you learned:

  1. Circuit drawing -- Use print(prog) for quick inspection, core.draw_qprog() for controlled output, and .draw() for an object-oriented interface. Three output formats are available: text (ASCII), image (matplotlib), and LaTeX.

  2. Print options -- core.set_print_options() configures the precision, parameter visibility, and line width for all text-based circuit output.

  3. Bloch sphere -- Visualize single-qubit states with plot_bloch_vector(), multi-qubit states per-qubit with plot_bloch_multivector(), and animate single-qubit circuit evolution with plot_bloch_circuit().

  4. State visualization -- Use plot_state_city() for 3D bar plots of the density matrix, plot_density_matrix() for phase-colored heatmaps, and plot_state() as a unified interface.

  5. Probability charts -- plot_probabilities() renders measurement outcome distributions, with optional top_k filtering for large state spaces.

  6. Exporting -- Save diagrams as text files, LaTeX source, or JPEG/PNG images using output_file or filename parameters.

  7. Time scheduling -- Parse instruction JSON from QProg.to_instruction() into normalized schedule items, and render per-qubit timing diagrams using draw_time_scheduling().

The next tutorial in the series covers Transpilation, where you will learn how to optimize circuits for specific hardware topologies and gate sets.

Released under the MIT License.