# Bloch Spheres In classical computing a bit can be only 0 or 1. In quantum computing a quantum bit (qubit) is a vector with 2 complex numbers, which can be visualized in 3D. Like in classical computing, gates are used to change the qubit state, but in quantum computing gates act as rotations. This visualization lets you explore quantum gates and learn how to control qubits. This is an essential skill for programming quantum computers.

Source Code

             import numpy as np
from fasthtml.common import *
import plotly.graph_objects as go
from fh_plotly import plotly2fasthtml, plotly_headers

########################
### FastHTML Section ###
########################

app, rt = fast_app(hdrs=plotly_headers)

@app.get('/')
def homepage():
    desc = """
    The Bloch Sphere is a 3D visualization of a single quantum state. 
    You can interact with the buttons (Gates) to see how the state changes. See the description below for more information on what each gate represents.
    """
    hx_vals = 'js:{"gates": document.getElementById("quantum_circuit").textContent}'
    return (Title("Interactive Bloch Sphere"), 
            Main(P(desc),
                 *[Button(gate, hx_get=f"/apply_gate/{gate}", hx_target="#chart", hx_swap="innerHTML", hx_vals=hx_vals,  title=f"Apply {gate} gate") for gate in single_qubit_gates.keys()], 
                 Button("Reset", hx_get="/reset", hx_target="#chart", hx_swap="innerHTML", title="Reset the circuit"),
                 Div(update_state_apply_gate.__wrapped__(), id="chart"),
                 H4("Available gates"),
                 Ul(Li(Strong("H :"),"Hadamard gate. Puts the state in superposition. "),
                    Li(Strong("X :"),"Pauli-X (NOT) gate. Rotate 180 degrees around the X-Axis."),
                    Li(Strong("Y :"),"Pauli-Y (\"bit-flip\") gate. Rotate 180 degrees around the Y-Axis."),
                    Li(Strong("Z :"),"Pauli-Z (\"phase-flip\") gate. Rotate 180 degrees around the Z-Axis."),
                    Li(Strong("S :"),"Phase gate. Rotates around the Z-axis by 90 degrees."),
                    Li(Strong("T :"),"π/8 gate. Rotates around the Z-axis by 45 degrees."))))

@app.get('/reset')
def reset(): return update_state_apply_gate.__wrapped__()

@app.get('/apply_gate/{gate}')
def update_state_apply_gate(gate: str=None, gates: str=None):
    if gates is None: gates = []
    else:
        # Transform from circuit representation to gate names
        gates = [g for g in gates if g in single_qubit_gates.keys()]
        gates.append(gate)
    # Create initial state
    state = np.array([1, 0]) # |0> basis state
    for gate in gates: state = single_qubit_gates[gate] @ state
    # Create visualization
    return Div(plot_bloch(state),
            H4(f"Quantum Circuit: {visualize_circuit(gates)}", id="quantum_circuit"),
            id="chart")

def visualize_circuit(gates: list[str]):
    circuit = "|0⟩-" 
    circuit += "".join([f"[{gate}]─" for gate in gates]) + "|"
    return circuit

############################
### Math/Quantum Section ###
############################


def calculate_coordinates(theta, phi):
    x = np.sin(theta) * np.cos(phi)
    y = np.sin(theta) * np.sin(phi)
    z = np.cos(theta)
    return x, y, z

def create_scenes():
    axis2ticktext = {'X': ['|-⟩', '|+⟩'], 'Y': ['|-i⟩', '|i⟩'], 'Z': ['|1⟩', '|0⟩']}
    scenes = {}
    for axis in ['X','Y','Z']:
        scenes[f'{axis.lower()}axis'] = dict(title=dict(text=axis, font=dict(size=25)), 
                range=[-1.2, 1.2], tickvals=[-1, 1], 
                ticktext=axis2ticktext[axis],
                tickfont=dict(size=15) )
    return scenes

def plot_bloch(state: np.array):
    fig = go.Figure()

    # State vector coordinates
    alpha, beta = state[0], state[1]
    theta = 2 * np.arccos(np.abs(alpha))
    phi = np.angle(beta) - np.angle(alpha)
    x, y, z = calculate_coordinates(theta, phi)

    # Surface coordinates
    surface_phi, surface_theta = np.mgrid[0:2*np.pi:100j, 0:np.pi:50j]
    xs, ys, zs = calculate_coordinates(surface_theta, surface_phi)

    fig.add_trace(go.Surface(x=xs, y=ys, z=zs, opacity=0.5, colorscale='Blues', showscale=False))

    fig.add_trace(go.Scatter3d(x=[0, x],y=[0, y],z=[0, z], mode='lines+markers+text', marker=dict(size=10, color='green'),
        line=dict(color='green', width=8), textposition="top center", showlegend=True,name=f"{alpha:.2f}|0⟩ + {beta:.2f}|1⟩"))

    # Mark basis states
    fig.add_trace(go.Scatter3d(x=[0, 0, 1, -1, 0, 0],y=[0, 0, 0, 0, 1, -1], z=[1, -1, 0, 0, 0, 0],
        mode='markers', marker=dict(size=5, color='black'), hovertext=['|0⟩', '|1⟩', '|+⟩', '|-⟩', '|i⟩', '|-i⟩'],
        showlegend=False, name="Basis states"))

    # Add lines across axes
    boundary_phi = np.linspace(0, 2 * np.pi, 100)
    coords = [(np.cos(boundary_phi), np.sin(boundary_phi), np.zeros_like(boundary_phi)),
              (np.zeros_like(boundary_phi), np.cos(boundary_phi), np.sin(boundary_phi)),
              (np.cos(boundary_phi), np.zeros_like(boundary_phi), np.sin(boundary_phi)) ]
    
    for x, y, z in coords:
        fig.add_trace(go.Scatter3d(x=x, y=y, z=z, mode='lines', line=dict(color='black', width=2), showlegend=False, name="Axes"))

    fig.update_layout(scene=dict(**create_scenes(), aspectmode='cube',),
                      legend=dict( font=dict(size=20), x=0.05,y=0.95, xanchor='left', yanchor='top', bgcolor='rgba(0,0,0,0)',),
                      margin=dict(l=0, r=0, t=0, b=0))
    
    return plotly2fasthtml(fig)


single_qubit_gates = {
    # Hadamard
    "H": np.array([[1, 1],
                   [1, -1]]) / np.sqrt(2),
    # Pauli matrices
    "X": np.array([[0, 1],
                   [1, 0]]),
    "Y": np.array([[0, -1j],
                   [1j, 0]]),
    "Z": np.array([[1, 0],
                   [0, -1]]),
    # Phase gates
    "S": np.array([[1, 0],
                   [0, 1j]]),
    "T": np.array([[1, 0],
                   [0, np.exp(1j * np.pi / 4)]])
}
           

Live Demo

Interactive Bloch Sphere

The Bloch Sphere is a 3D visualization of a single quantum state. You can interact with the buttons (Gates) to see how the state changes. See the description below for more information on what each gate represents.

Quantum Circuit: |0⟩-|

Available gates

  • H : Hadamard gate. Puts the state in superposition.
  • X : Pauli-X (NOT) gate. Rotate 180 degrees around the X-Axis.
  • Y : Pauli-Y ("bit-flip") gate. Rotate 180 degrees around the Y-Axis.
  • Z : Pauli-Z ("phase-flip") gate. Rotate 180 degrees around the Z-Axis.
  • S : Phase gate. Rotates around the Z-axis by 90 degrees.
  • T : π/8 gate. Rotates around the Z-axis by 45 degrees.