Skip to content

Commit 64ec15d

Browse files
Improve Bloch sphere code structure and docs (#480)
Co-authored-by: Alberto Mercurio <[email protected]>
1 parent 47deb2c commit 64ec15d

File tree

10 files changed

+512
-442
lines changed

10 files changed

+512
-442
lines changed

CHANGELOG.md

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -9,7 +9,7 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
99

1010
- Introduce `Lanczos` solver for `spectrum`. ([#476])
1111
- Add Bloch-Redfield master equation solver. ([#473])
12-
- Implement Bloch Sphere rendering. ([#472])
12+
- Implement Bloch Sphere rendering and align style with qutip. ([#472], [#480])
1313

1414
## [v0.31.1]
1515
Release date: 2025-05-16
@@ -235,3 +235,4 @@ Release date: 2024-11-13
235235
[#472]: https://github.com/qutip/QuantumToolbox.jl/issues/472
236236
[#473]: https://github.com/qutip/QuantumToolbox.jl/issues/473
237237
[#476]: https://github.com/qutip/QuantumToolbox.jl/issues/476
238+
[#480]: https://github.com/qutip/QuantumToolbox.jl/issues/480

Project.toml

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -12,6 +12,7 @@ Distributed = "8ba89e20-285c-5b6f-9357-94700520ee1b"
1212
FFTW = "7a1cc6ca-52ef-59f5-83cd-3a7055c09341"
1313
Graphs = "86223c79-3864-5bf0-83f7-82e725a168b6"
1414
IncompleteLU = "40713840-3770-5561-ab4c-a76e7d0d7895"
15+
LaTeXStrings = "b964fa9f-0449-5b57-a5c2-d3ea65f4040f"
1516
LinearAlgebra = "37e2e46d-f89d-539d-b4ee-838fcccc9c8e"
1617
LinearSolve = "7ed4a6bd-45f5-4d41-b270-4a48e9bafcae"
1718
OrdinaryDiffEqCore = "bbf590c4-e513-4bbe-9b18-05decba2e5d8"
@@ -51,6 +52,7 @@ GPUArrays = "10, 11"
5152
Graphs = "1.7"
5253
IncompleteLU = "0.2"
5354
KernelAbstractions = "0.9.2"
55+
LaTeXStrings = "1.2"
5456
LinearAlgebra = "1"
5557
LinearSolve = "2, 3"
5658
Makie = "0.20, 0.21, 0.22"

docs/make.jl

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -18,8 +18,8 @@ end
1818
DocMeta.setdocmeta!(QuantumToolbox, :DocTestSetup, doctest_setup; recursive = true)
1919

2020
# some options for `makedocs`
21-
const DRAFT = false # set `true` to disable cell evaluation
22-
const DOCTEST = true # set `false` to skip doc tests
21+
const DRAFT = get(ENV, "DRAFT", false) == "true" # `DRAFT = true` disables cell evaluation
22+
const DOCTEST = get(ENV, "DOCTEST", true) == true # `DOCTEST = false` skips doc tests
2323

2424
# generate bibliography
2525
bib = CitationBibliography(
@@ -51,7 +51,6 @@ const PAGES = [
5151
],
5252
"Manipulating States and Operators" => "users_guide/states_and_operators.md",
5353
"Tensor Products and Partial Traces" => "users_guide/tensor.md",
54-
"Plotting on the Bloch Sphere" => "users_guide/plotting_the_bloch_sphere.md",
5554
"Time Evolution and Dynamics" => [
5655
"Introduction" => "users_guide/time_evolution/intro.md",
5756
"Time Evolution Solutions" => "users_guide/time_evolution/solution.md",
@@ -65,6 +64,7 @@ const PAGES = [
6564
"Hierarchical Equations of Motion" => "users_guide/HEOM.md",
6665
"Solving for Steady-State Solutions" => "users_guide/steadystate.md",
6766
"Two-time correlation functions" => "users_guide/two_time_corr_func.md",
67+
"Plotting on the Bloch Sphere" => "users_guide/plotting_the_bloch_sphere.md",
6868
"QuantumToolbox Settings" => "users_guide/settings.md",
6969
"Extensions" => [
7070
"Extension for CUDA.jl" => "users_guide/extensions/cuda.md",

docs/src/resources/api.md

Lines changed: 8 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -319,13 +319,18 @@ meshgrid
319319
```@docs
320320
plot_wigner
321321
plot_fock_distribution
322-
plot_bloch
322+
```
323+
324+
### [Bloch Sphere](@id doc-API:Bloch-Sphere)
325+
326+
```@docs
323327
Bloch
328+
plot_bloch
324329
render
325330
add_points!
326331
add_vectors!
327332
add_line!
328333
add_arc!
329-
clear!
330334
add_states!
331-
```
335+
clear!
336+
```

docs/src/users_guide/plotting_the_bloch_sphere.md

Lines changed: 96 additions & 53 deletions
Original file line numberDiff line numberDiff line change
@@ -7,61 +7,65 @@ using CairoMakie
77
CairoMakie.enable_only_mime!(MIME"image/svg+xml"())
88
```
99

10-
## [Introduction](@id doc:Bloch_sphere_rendering)
10+
## Introduction
1111

1212
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.
1313

14-
In [QuantumToolbox.jl](https://qutip.org/QuantumToolbox.jl/), this can be done using the [`Bloch`](@ref) or [`plot_bloch`](@ref) methods that provide same syntax as [QuTiP](https://qutip.readthedocs.io/en/stable/guide/guide-bloch.html).
14+
In [`QuantumToolbox`](https://qutip.org/QuantumToolbox.jl/), this can be done using the [`Bloch`](@ref) or [`plot_bloch`](@ref) methods that provide same syntax as [QuTiP](https://qutip.readthedocs.io/en/stable/guide/guide-bloch.html).
1515

1616
## Create a Bloch Sphere
1717

18-
In [QuantumToolbox.jl](https://qutip.org/QuantumToolbox.jl/), creating a [`Bloch`](@ref) sphere is accomplished by calling either:
18+
In [`QuantumToolbox`](https://qutip.org/QuantumToolbox.jl/), creating a [`Bloch`](@ref) sphere is accomplished by calling either:
1919

2020
```@example Bloch_sphere_rendering
21-
b = Bloch();
21+
b = Bloch()
2222
```
2323

2424
which will load an instance of [`Bloch`](@ref). Before getting into the details of these objects, we can simply plot the blank [`Bloch`](@ref) sphere associated with these instances via:
2525

2626
```@example Bloch_sphere_rendering
27-
fig, _ = render(b);
27+
fig, _ = render(b)
2828
fig
2929
```
3030

31-
## Add a Single Data Point
31+
See the [API documentation for Bloch sphere](@ref doc-API:Bloch-Sphere) for a full list of other available functions.
32+
33+
## Add a single data point
3234

3335
As an example, we can add a single data point via [`add_points!`](@ref):
3436

3537
```@example Bloch_sphere_rendering
36-
pnt = [1 / sqrt(3), 1 / sqrt(3), 1 / sqrt(3)];
37-
add_points!(b, pnt);
38-
fig, _ = render(b);
38+
pnt = [1 / sqrt(3), 1 / sqrt(3), 1 / sqrt(3)]
39+
add_points!(b, pnt)
40+
fig, _ = render(b)
3941
fig
4042
```
4143

42-
## Add a Single Vector
44+
## Add a single vector
4345

44-
and then a single vector via [`add_vectors!`](@ref):
46+
Add a single vector via [`add_vectors!`](@ref):
4547

4648
```@example Bloch_sphere_rendering
47-
vec = [0, 1, 0];
49+
vec = [0, 1, 0]
4850
add_vectors!(b, vec)
4951
fig, _ = render(b)
5052
fig
5153
```
5254

53-
and then add another vector corresponding to the ``|0\rangle`` state:
55+
## Add a single quantum state
56+
57+
Add another vector corresponding to the ``|0\rangle`` state:
5458

5559
```@example Bloch_sphere_rendering
56-
x = basis(2, 0)
57-
add_states!(b, [x])
60+
z0 = basis(2, 0)
61+
add_states!(b, z0)
5862
fig, _ = render(b)
5963
fig
6064
```
6165

62-
## Add Multiple Vectors
66+
## Add multiple data
6367

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

6670
```@example Bloch_sphere_rendering
6771
clear!(b)
@@ -73,14 +77,16 @@ Now on the same [`Bloch`](@ref) sphere, we can plot the three states via [`add_s
7377

7478
```@example Bloch_sphere_rendering
7579
x = basis(2, 0) + basis(2, 1)
76-
y = basis(2, 0) - im * basis(2, 1)
80+
y = basis(2, 0) + im * basis(2, 1)
7781
z = basis(2, 0)
78-
b = Bloch()
7982
add_states!(b, [x, y, z])
8083
fig, _ = render(b)
8184
fig
8285
```
8386

87+
!!! note "State normalization"
88+
The function [`add_states!`](@ref) will automatically normalize the given quantum state(s), while [`add_vectors!`](@ref) does not normalize the given vectors.
89+
8490
A similar method works for adding vectors:
8591

8692
```@example Bloch_sphere_rendering
@@ -91,70 +97,107 @@ fig, _ = render(b)
9197
fig
9298
```
9399

94-
# Add Arc, Line, and Vector
100+
# Add lines and arcs
95101

96102
You can also add lines and arcs via [`add_line!`](@ref) and [`add_arc!`](@ref) respectively:
97103

98104
```@example Bloch_sphere_rendering
99-
clear!(b)
100-
vec = [[1, 0, 0], [0, 1, 0], [0, 0, 1]];
101-
add_vectors!(b, vec);
102-
add_line!(b, [1,0,0], [0,1,0])
103-
add_arc!(b, [1, 0, 0], [0, 1, 0], [0, 0, 1])
105+
add_line!(b, x, y)
106+
add_arc!(b, y, z)
104107
fig, _ = render(b)
105108
fig
106109
```
107110

108-
## Add Multiple Points
111+
## Add multiple points
109112

110113
Adding multiple points to the [`Bloch`](@ref) 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!`](@ref)):
111114

112115
```@example Bloch_sphere_rendering
113-
th = range(0, 2π; length=20);
114116
clear!(b)
115-
xp = cos.(th);
116-
yp = sin.(th);
117-
zp = zeros(20);
118-
pnts = [xp, yp, zp];
119-
add_points!(b, pnts);
120-
fig, ax = render(b);
117+
118+
th = LinRange(0, 2π, 20)
119+
xp = cos.(th)
120+
yp = sin.(th)
121+
zp = zeros(20)
122+
pnts = [xp, yp, zp]
123+
add_points!(b, pnts)
124+
fig, ax = render(b)
121125
fig
122126
```
123127

124-
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!`](@ref) 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!`](@ref):
125-
126-
## Add Another Set of Points
128+
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!`](@ref) 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!`](@ref) function:
127129

128130
```@example Bloch_sphere_rendering
129-
xz = zeros(20);
130-
yz = sin.(th);
131-
zz = cos.(th);
132-
pnts = [xz, yz, zz];
133-
add_points!(b, pnts);
134-
fig, ax = render(b);
131+
xz = zeros(20)
132+
yz = sin.(th)
133+
zz = cos.(th)
134+
add_points!(b, [xz, yz, zz])
135+
fig, ax = render(b)
135136
fig
136137
```
137138

138-
The color and shape of the data points is varied automatically by [`Bloch`](@ref). Notice how the color and point markers change for each set of data.
139+
The color and shape of the data points is varied automatically by [`Bloch`](@ref). Notice how the color and point markers change for each set of data. Again, we have had to call [`add_points!`](@ref) twice because adding more than one set of multiple data points is not supported by the [`add_points!`](@ref) function.
139140

140-
What if we want to vary the color of our points. We can tell [`Bloch`](@ref) to vary the color of each point according to the colors listed in the `point_color` attribute.
141+
What if we want to vary the color of our points. We can tell [`Bloch`](@ref) to vary the color of each point according to the colors listed in the `point_color` field (see [Configuring the Bloch sphere](@ref doc:Configuring-the-Bloch-sphere) below). Again, after [`clear!`](@ref):
141142

142143
```@example Bloch_sphere_rendering
143144
clear!(b)
144-
xp = cos.(th);
145-
yp = sin.(th);
146-
zp = zeros(20);
147-
pnts = [xp, yp, zp];
148-
add_points!(b, pnts, meth=:m);
149-
fig, ax = render(b);
145+
146+
xp = cos.(th)
147+
yp = sin.(th)
148+
zp = zeros(20)
149+
pnts = [xp, yp, zp]
150+
add_points!(b, pnts, meth=:m) # add `meth=:m` to signify 'multi' colored points
151+
fig, ax = render(b)
150152
fig
151153
```
152154

153155
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\rangle`` state to the ``|1\rangle`` state in the `y-z` plane:
154156

155157
```@example Bloch_sphere_rendering
156-
pnts = [xz, yz, zz] ;
157-
add_points!(b, pnts);
158-
fig, ax = render(b);
158+
pnts = [xz, yz, zz]
159+
add_points!(b, pnts) # no `meth=:m`
160+
fig, ax = render(b)
159161
fig
160162
```
163+
164+
## [Configuring the Bloch sphere](@id doc:Configuring-the-Bloch-sphere)
165+
166+
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 class has many attributes which one can control. Assuming `b = Bloch()`:
167+
168+
| **Field** | **Description** | **Default setting** |
169+
|:----------|:----------------|:--------------------|
170+
| `b.points` | Points to plot on the Bloch sphere (3D coordinates) | `Vector{Matrix{Float64}}()` (empty) |
171+
| `b.vectors` | Vectors to plot on the Bloch sphere | `Vector{Vector{Float64}}()` (empty) |
172+
| `b.lines` | Lines to draw on the sphere (points, style, properties) | `Vector{Tuple{Vector{Vector{Float64}},String}}()` (empty) |
173+
| `b.arcs` | Arcs to draw on the sphere | `Vector{Vector{Vector{Float64}}}()` (empty) |
174+
| `b.font_color` | Color of axis labels and text | `"black"` |
175+
| `b.font_size` | Font size for labels | `15` |
176+
| `b.frame_alpha` | Transparency of the frame background | `0.1` |
177+
| `b.frame_color` | Background color of the frame | `"gray"` |
178+
| `b.frame_limit` | Axis limits for the 3D frame (symmetric around origin) | `1.2` |
179+
| `b.point_default_color` | Default color cycle for points | `["blue", "red", "green", "#CC6600"]` |
180+
| `b.point_color` | List of colors for Bloch point markers to cycle through | `Union{Nothing,String}[]` |
181+
| `b.point_marker` | List of point marker shapes to cycle through | `[:circle, :rect, :diamond, :utriangle]` |
182+
| `b.point_size` | List of point marker sizes (not all markers look the same size when plotted) | `[5.5, 6.2, 6.5, 7.5]` |
183+
| `b.point_style` | List of marker styles | `Symbol[]` |
184+
| `b.point_alpha` | List of marker transparencies | `Float64[]` |
185+
| `b.sphere_color` | Color of Bloch sphere surface | `0.2` |
186+
| `b.sphere_alpha` | Transparency of sphere surface | `"#FFDDDD"` |
187+
| `b.vector_color` | Colors for vectors | `["green", "#CC6600", "blue", "red"]` |
188+
| `b.vector_width` | Width of vectors | `0.025` |
189+
| `b.vector_arrowsize` | Arrow size parameters as (head length, head width, stem width) | `[0.07, 0.08, 0.08]` |
190+
| `b.view` | Azimuthal and elevation viewing angles in degrees | `[30, 30]` |
191+
| `b.xlabel` | Labels for x-axis | `[L"x", ""]` (``+x`` and ``-x``) |
192+
| `b.xlpos` | Positions of x-axis labels | `[1.0, -1.0]` |
193+
| `b.ylabel` | Labels for y-axis | `[L"y", ""]` (``+y`` and ``-y``) |
194+
| `b.ylpos` | Positions of y-axis labels | `[1.0, -1.0]` |
195+
| `b.zlabel` | Labels for z-axis | `[L"\|0\rangle", L"\|1\rangle]"` (``+z`` and ``-z``) |
196+
| `b.zlpos` | Positions of z-axis labels | `[1.0, -1.0]` |
197+
198+
These properties can also be accessed via the `print` command:
199+
200+
```@example Bloch_sphere_rendering
201+
b = Bloch()
202+
print(b)
203+
```

0 commit comments

Comments
 (0)