Skip to content

Plotting on the Bloch Sphere

Introduction

When studying the dynamics of a two-level system, it's often convenient to visualize the state of the system by plotting the state vector or density matrix on the Bloch sphere.

In QuantumToolbox, this can be done using the Bloch or plot_bloch methods that provide same syntax as QuTiP.

Create a Bloch Sphere

In QuantumToolbox, creating a Bloch sphere is accomplished by calling either:

Import plotting libraries

Remember to import plotting libraries first. Here, we demonstrate the functionalities with CairoMakie.jl.

julia
b = Bloch()
Bloch Sphere

data:
-----
Number of points  = 0
Number of vectors = 0
Number of lines   = 0
Number of arcs    = 0

properties:
-----------
font_color          = black
font_size           = 20
frame_alpha         = 0.2
frame_color         = gray
frame_width         = 1.0
point_default_color = ["blue", "red", "green", "#CC6600"]
point_color         = Union{Nothing, String}[]
point_marker        = [:circle, :rect, :diamond, :utriangle]
point_size          = [5.5, 6.2, 6.5, 7.5]
point_style         = Symbol[]
point_alpha         = Float64[]
sphere_alpha        = 0.2
sphere_color        = #FFDDDD
vector_color        = ["green", "#CC6600", "blue", "red"]
vector_width        = 0.025
vector_arrowsize    = [0.07, 0.08, 0.08]
view                = [30, 30]
xlabel              = AbstractString[L"$x$", ""]
xlpos               = [1.2, -1.2]
ylabel              = AbstractString[L"$y$", ""]
ylpos               = [1.2, -1.2]
zlabel              = AbstractString[L"$|0\rangle$", L"$|1\rangle$"]
zlpos               = [1.2, -1.2]

which will load an instance of Bloch. Before getting into the details of these objects, we can simply plot the blank Bloch sphere associated with these instances via:

julia
fig, _ = render(b)
fig

See the API documentation for Bloch sphere for a full list of other available functions.

Add a single data point

As an example, we can add a single data point via add_points!:

julia
pnt = [1 / sqrt(3), 1 / sqrt(3), 1 / sqrt(3)]
add_points!(b, pnt)
fig, _ = render(b)
fig

Add a single vector

Add a single vector via add_vectors!:

julia
vec = [0, 1, 0]
add_vectors!(b, vec)
fig, _ = render(b)
fig

Add a single quantum state

Add another vector corresponding to the |0 state:

julia
z0 = basis(2, 0)
add_states!(b, z0)
fig, _ = render(b)
fig

Add multiple data

We can also plot multiple points, vectors, and states at the same time by passing arrays instead of individual elements via add_points!, add_vectors!, and add_states!, respectively. Before giving an example, we can use clear! to remove the current data from our Bloch sphere instead of creating a new instance:

julia
clear!(b)
fig, _ = render(b)
fig

Now on the same Bloch sphere, we can plot the three states via add_states! associated with the x, y, and z directions:

julia
x = basis(2, 0) + basis(2, 1)
y = basis(2, 0) + im * basis(2, 1)
z = basis(2, 0)
add_states!(b, [x, y, z])
fig, _ = render(b)
fig

State normalization

The function add_states! will automatically normalize the given quantum state(s), while add_vectors! does not normalize the given vectors.

A similar method works for adding vectors:

julia
clear!(b)
vecs = [[1, 0, 0], [0, 1, 0], [0, 0, 1]]
add_vectors!(b, vecs)
fig, _ = render(b)
fig

Add lines and arcs

You can also add lines and arcs via add_line! and add_arc! respectively:

julia
add_line!(b, x, y)
add_arc!(b, y, z)
fig, _ = render(b)
fig

Add multiple points

Adding multiple points to the Bloch sphere works slightly differently than adding multiple states or vectors. For example, lets add a set of 20 points around the equator (after calling clear!):

julia
clear!(b)

th = LinRange(0, , 20)
xp = cos.(th)
yp = sin.(th)
zp = zeros(20)
pnts = [xp, yp, zp]
add_points!(b, pnts)
fig, lscene = render(b)
fig

Notice that, in contrast to states or vectors, each point remains the same color as the initial point. This is because adding multiple data points using add_points! is interpreted, by default, to correspond to a single data point (single qubit state) plotted at different times. This is very useful when visualizing the dynamics of a qubit. If we want to plot additional qubit states we can call additional add_points! function:

julia
xz = zeros(20)
yz = sin.(th)
zz = cos.(th)
add_points!(b, [xz, yz, zz])
fig, lscene = render(b)
fig

The color and shape of the data points is varied automatically by Bloch. Notice how the color and point markers change for each set of data. Again, we have had to call add_points! twice because adding more than one set of multiple data points is not supported by the add_points! function.

What if we want to vary the color of our points. We can tell Bloch to vary the color of each point according to the colors listed in the point_color field (see Configuring the Bloch sphere below). Again, after clear!:

julia
clear!(b)

xp = cos.(th)
yp = sin.(th)
zp = zeros(20)
pnts = [xp, yp, zp]
add_points!(b, pnts, meth=:m) # add `meth=:m` to signify 'multi' colored points
fig, lscene = render(b)
fig

Now, the data points cycle through a variety of predefined colors. Now lets add another set of points, but this time we want the set to be a single color, representing say a qubit going from the |0 state to the |1 state in the y-z plane:

julia
pnts = [xz, yz, zz]
add_points!(b, pnts) # no `meth=:m`
fig, lscene = render(b)
fig

Configuring the Bloch sphere

At the end of the last section we saw that the colors and marker shapes of the data plotted on the Bloch sphere are automatically varied according to the number of points and vectors added. But what if you want a different choice of color, or you want your sphere to be purple with different axes labels? Well then you are in luck as the Bloch structure has many fields which one can control. Assuming b = Bloch():

Data storage

FieldDescriptionDefault setting
b.pointsPoints to plot on the Bloch sphere (3D coordinates)Vector{Matrix{Float64}}() (empty)
b.vectorsVectors to plot on the Bloch sphereVector{Vector{Float64}}() (empty)
b.linesLines to draw on the sphere with each line given as ([start_pt, end_pt], line_format)Vector{Tuple{Vector{Vector{Float64}},String}}() (empty)
b.arcsArcs to draw on the sphereVector{Vector{Vector{Float64}}}() (empty)

Properties

FieldDescriptionDefault setting
b.font_colorColor of axis labels and text"black"
b.font_sizeFont size for labels20
b.frame_alphaTransparency of the wire frame0.2
b.frame_colorColor of the wire frame"gray"
b.frame_widthWidth of wire frame1.0
b.point_default_colorDefault color cycle for points["blue", "red", "green", "#CC6600"]
b.point_colorList of colors for Bloch point markers to cycle throughUnion{Nothing,String}[]
b.point_markerList of point marker shapes to cycle through[:circle, :rect, :diamond, :utriangle]
b.point_sizeList of point marker sizes (not all markers look the same size when plotted)[5.5, 6.2, 6.5, 7.5]
b.point_styleList of marker stylesSymbol[]
b.point_alphaList of marker transparenciesFloat64[]
b.sphere_colorColor of Bloch sphere surface0.2
b.sphere_alphaTransparency of sphere surface"#FFDDDD"
b.vector_colorColors for vectors["green", "#CC6600", "blue", "red"]
b.vector_widthWidth of vectors0.025
b.vector_arrowsizeScales the size of the arrow head. The first two elements scale the radius (in x/y direction) and the last one is the length of the cone.[0.07, 0.08, 0.08]
b.viewAzimuthal and elevation viewing angles in degrees[30, 30]
b.xlabelLabels for x-axis[L"x", ""] (+x and x)
b.xlposPositions of x-axis labels[1.2, -1.2]
b.ylabelLabels for y-axis[L"y", ""] (+y and y)
b.ylposPositions of y-axis labels[1.2, -1.2]
b.zlabelLabels for z-axis[L"|0\rangle", L"|1\rangle]" (+z and z)
b.zlposPositions of z-axis labels[1.2, -1.2]

These properties can also be accessed via the print command:

julia
b = Bloch()
print(b)
Bloch Sphere

data:
-----
Number of points  = 0
Number of vectors = 0
Number of lines   = 0
Number of arcs    = 0

properties:
-----------
font_color          = black
font_size           = 20
frame_alpha         = 0.2
frame_color         = gray
frame_width         = 1.0
point_default_color = ["blue", "red", "green", "#CC6600"]
point_color         = Union{Nothing, String}[]
point_marker        = [:circle, :rect, :diamond, :utriangle]
point_size          = [5.5, 6.2, 6.5, 7.5]
point_style         = Symbol[]
point_alpha         = Float64[]
sphere_alpha        = 0.2
sphere_color        = #FFDDDD
vector_color        = ["green", "#CC6600", "blue", "red"]
vector_width        = 0.025
vector_arrowsize    = [0.07, 0.08, 0.08]
view                = [30, 30]
xlabel              = AbstractString[L"$x$", ""]
xlpos               = [1.2, -1.2]
ylabel              = AbstractString[L"$y$", ""]
ylpos               = [1.2, -1.2]
zlabel              = AbstractString[L"$|0\rangle$", L"$|1\rangle$"]
zlpos               = [1.2, -1.2]