Skip to content

Commit 68115cb

Browse files
committed
fix opposite axis
1 parent 26cd2fb commit 68115cb

File tree

5 files changed

+118
-111
lines changed

5 files changed

+118
-111
lines changed

docs/make.jl

Lines changed: 2 additions & 2 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 = get(ENV, "DRAFT", false) == "true" # set `true` to disable cell evaluation
22-
const DOCTEST = get(ENV, "DOCTEST", true) == "true" # set `false` to skip doc tests
21+
const DRAFT = get(ENV, "DRAFT", false) == true # set `true` to disable cell evaluation
22+
const DOCTEST = get(ENV, "DOCTEST", true) == false # set `false` to skip doc tests
2323

2424
# generate bibliography
2525
bib = CitationBibliography(

docs/src/users_guide/plotting_the_bloch_sphere.md

Lines changed: 11 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -65,7 +65,7 @@ fig
6565

6666
## Add multiple data
6767

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:
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:
6969

7070
```@example Bloch_sphere_rendering
7171
clear!(b)
@@ -77,7 +77,7 @@ Now on the same [`Bloch`](@ref) sphere, we can plot the three states via [`add_s
7777

7878
```@example Bloch_sphere_rendering
7979
x = basis(2, 0) + basis(2, 1)
80-
y = basis(2, 0) - im * basis(2, 1)
80+
y = basis(2, 0) + im * basis(2, 1)
8181
z = basis(2, 0)
8282
add_states!(b, [x, y, z])
8383
fig, _ = render(b)
@@ -175,7 +175,7 @@ At the end of the last section we saw that the colors and marker shapes of the d
175175
| `b.font_size` | Font size for labels | `15` |
176176
| `b.frame_alpha` | Transparency of the frame background | `0.1` |
177177
| `b.frame_color` | Background color of the frame | `"gray"` |
178-
| `b.frame_limit` | Axis limits for the 3D frame (symmetric around origin) | `1.14` |
178+
| `b.frame_limit` | Axis limits for the 3D frame (symmetric around origin) | `1.2` |
179179
| `b.point_default_color` | Default color cycle for points | `["blue", "red", "green", "#CC6600"]` |
180180
| `b.point_color` | List of colors for Bloch point markers to cycle through | `Union{Nothing,String}[]` |
181181
| `b.point_marker` | List of point marker shapes to cycle through | `[:circle, :rect, :diamond, :utriangle]` |
@@ -186,14 +186,14 @@ At the end of the last section we saw that the colors and marker shapes of the d
186186
| `b.sphere_alpha` | Transparency of sphere surface | `"#FFDDDD"` |
187187
| `b.vector_color` | Colors for vectors | `["green", "#CC6600", "blue", "red"]` |
188188
| `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 | `(-60, 30)` |
191-
| `b.xlabel` | Labels for x-axis | `(L"x", "")` |
192-
| `b.xlpos` | Positions of x-axis labels | `(1.0, -1.0)` |
193-
| `b.ylabel` | Labels for y-axis | `(L"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)"` |
196-
| `b.zlpos` | Positions of z-axis labels | `(1.0, -1.0)` |
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]` |
197197

198198
These properties can also be accessed via the `print` command:
199199

ext/QuantumToolboxMakieExt.jl

Lines changed: 70 additions & 71 deletions
Original file line numberDiff line numberDiff line change
@@ -398,8 +398,10 @@ function _setup_bloch_plot!(b::Bloch, location)
398398
yspinesvisible = false,
399399
zspinesvisible = false,
400400
protrusions = (0, 0, 0, 0),
401+
perspectiveness = 0.2,
401402
viewmode = :fit,
402403
)
404+
length(b.view) == 2 || throw(ArgumentError("The length of `Bloch.view` must be 2."))
403405
ax.azimuth[] = deg2rad(b.view[1])
404406
ax.elevation[] = deg2rad(b.view[2])
405407
return fig, ax
@@ -452,9 +454,9 @@ function _draw_reference_circles!(ax)
452454
φ = range(0, 2π, length = 100)
453455
# XY, YZ, XZ circles
454456
circles = [
455-
[Point3f(sin(φi), -cos(φi), 0) for φi in φ], # XY
456-
[Point3f(0, -cos(φi), sin(φi)) for φi in φ], # YZ
457-
[Point3f(sin(φi), 0, cos(φi)) for φi in φ], # XZ
457+
[Point3f(cos(φi), sin(φi), 0) for φi in φ], # XY
458+
[Point3f(0, cos(φi), sin(φi)) for φi in φ], # YZ
459+
[Point3f(cos(φi), 0, sin(φi)) for φi in φ], # XZ
458460
]
459461
for circle in circles
460462
lines!(ax, circle; color = wire_color, linewidth = 1.0)
@@ -475,9 +477,9 @@ function _draw_axes!(ax)
475477
axis_color = RGBAf(0.3, 0.3, 0.3, 0.8)
476478
axis_width = 0.8
477479
axes = [
478-
([Point3f(0, -1.0, 0), Point3f(0, 1.0, 0)], "y"), # Y-axis
479-
([Point3f(-1.0, 0, 0), Point3f(1.0, 0, 0)], "x"), # X-axis
480-
([Point3f(0, 0, -1.0), Point3f(0, 0, 1.0)], "z"), # Z-axis
480+
([Point3f(1.0, 0, 0), Point3f(-1.0, 0, 0)], "x"), # X-axis
481+
([Point3f(0, 1.0, 0), Point3f(0, -1.0, 0)], "y"), # Y-axis
482+
([Point3f(0, 0, 1.0), Point3f(0, 0, -1.0)], "z"), # Z-axis
481483
]
482484
for (points, _) in axes
483485
lines!(ax, points; color = axis_color, linewidth = axis_width)
@@ -503,8 +505,8 @@ function _plot_points!(b::Bloch, ax)
503505
marker = b.point_marker[mod1(k, length(b.point_marker))]
504506
N = size(pts, 2)
505507

506-
raw_x = pts[2, :]
507-
raw_y = -pts[1, :]
508+
raw_x = pts[1, :]
509+
raw_y = pts[2, :]
508510
raw_z = pts[3, :]
509511

510512
ds = vec(sqrt.(sum(abs2, pts; dims = 1)))
@@ -607,10 +609,10 @@ function _plot_arcs!(b::Bloch, ax)
607609
θ = acos(clamp(dot(v1, v2), -1.0, 1.0))
608610
if length(arc_pts) == 3
609611
vm = normalize(arc_pts[2])
610-
dot(cross(v1, vm), n) < 0 &&= 2π - θ)
612+
dot(cross(v1, vm), n) < 0 &&-= 2π)
611613
end
612614
t_range = range(0, θ, length = 100)
613-
arc_points = [Point3f((v1*cos(t) + cross(n, v1)*sin(t))...) for t in t_range]
615+
arc_points = [Point3f((v1 * cos(t) + cross(n, v1) * sin(t))) for t in t_range]
614616
lines!(ax, arc_points; color = RGBAf(0.8, 0.4, 0.1, 0.9), linewidth = 2.0, linestyle = :solid)
615617
end
616618
end
@@ -632,7 +634,7 @@ function _plot_vectors!(b::Bloch, ax)
632634
r = 1.0
633635
for (i, v) in enumerate(b.vectors)
634636
color = get(b.vector_color, i, RGBAf(0.2, 0.5, 0.8, 0.9))
635-
vec = Vec3f(v[2], -v[1], v[3])
637+
vec = Vec3f(v...)
636638
length = norm(vec)
637639
max_length = r * 0.90
638640
vec = length > max_length ? (vec/length) * max_length : vec
@@ -660,69 +662,66 @@ Add axis labels and state labels to the Bloch sphere.
660662
Positions standard labels `(x, y, |0⟩, |1⟩)` at appropriate locations.
661663
"""
662664
function _add_labels!(b::Bloch, ax)
665+
length(b.xlabel) == 2 || throw(ArgumentError("The length of `Bloch.xlabel` must be 2."))
666+
length(b.ylabel) == 2 || throw(ArgumentError("The length of `Bloch.ylabel` must be 2."))
667+
length(b.zlabel) == 2 || throw(ArgumentError("The length of `Bloch.zlabel` must be 2."))
668+
length(b.xlpos) == 2 || throw(ArgumentError("The length of `Bloch.xlpos` must be 2."))
669+
length(b.ylpos) == 2 || throw(ArgumentError("The length of `Bloch.ylpos` must be 2."))
670+
length(b.zlpos) == 2 || throw(ArgumentError("The length of `Bloch.zlpos` must be 2."))
671+
663672
label_color = parse(RGBf, b.font_color)
664673
label_size = b.font_size
665674
offset_scale = b.frame_limit
666-
if b.xlabel[1] != ""
667-
text!(
668-
ax,
669-
b.xlabel[1],
670-
position = Point3f(0, -offset_scale * b.xlpos[1], 0),
671-
color = label_color,
672-
fontsize = label_size,
673-
align = (:center, :center),
674-
)
675-
end
676-
if b.xlabel[2] != ""
677-
text!(
678-
ax,
679-
b.xlabel[2],
680-
position = Point3f(0, -offset_scale * b.xlpos[2], 0),
681-
color = label_color,
682-
fontsize = label_size,
683-
align = (:center, :center),
684-
)
685-
end
686-
if b.ylabel[1] != ""
687-
text!(
688-
ax,
689-
b.ylabel[1],
690-
position = Point3f(offset_scale * b.ylpos[1], 0, 0),
691-
color = label_color,
692-
fontsize = label_size,
693-
align = (:center, :center),
694-
)
695-
end
696-
if b.ylabel[2] != ""
697-
text!(
698-
ax,
699-
b.ylabel[2],
700-
position = Point3f(offset_scale * b.ylpos[2], 0, 0),
701-
color = label_color,
702-
fontsize = label_size,
703-
align = (:center, :center),
704-
)
705-
end
706-
if b.zlabel[1] != ""
707-
text!(
708-
ax,
709-
b.zlabel[1],
710-
position = Point3f(0, 0, offset_scale * b.zlpos[1]),
711-
color = label_color,
712-
fontsize = label_size,
713-
align = (:center, :center),
714-
)
715-
end
716-
if b.zlabel[2] != ""
717-
text!(
718-
ax,
719-
b.zlabel[2],
720-
position = Point3f(0, 0, offset_scale * b.zlpos[2]),
721-
color = label_color,
722-
fontsize = label_size,
723-
align = (:center, :center),
724-
)
725-
end
675+
676+
(b.xlabel[1] == "") || text!(
677+
ax,
678+
b.xlabel[1],
679+
position = Point3f(offset_scale * b.xlpos[1], 0, 0),
680+
color = label_color,
681+
fontsize = label_size,
682+
align = (:center, :center),
683+
)
684+
(b.xlabel[2] == "") || text!(
685+
ax,
686+
b.xlabel[2],
687+
position = Point3f(offset_scale * b.xlpos[2], 0, 0),
688+
color = label_color,
689+
fontsize = label_size,
690+
align = (:center, :center),
691+
)
692+
(b.ylabel[1] == "") || text!(
693+
ax,
694+
b.ylabel[1],
695+
position = Point3f(0, offset_scale * b.ylpos[1], 0),
696+
color = label_color,
697+
fontsize = label_size,
698+
align = (:center, :center),
699+
)
700+
(b.ylabel[2] == "") || text!(
701+
ax,
702+
b.ylabel[2],
703+
position = Point3f(0, offset_scale * b.ylpos[2], 0),
704+
color = label_color,
705+
fontsize = label_size,
706+
align = (:center, :center),
707+
)
708+
(b.zlabel[1] == "") || text!(
709+
ax,
710+
b.zlabel[1],
711+
position = Point3f(0, 0, offset_scale * b.zlpos[1]),
712+
color = label_color,
713+
fontsize = label_size,
714+
align = (:center, :center),
715+
)
716+
(b.zlabel[2] == "") || text!(
717+
ax,
718+
b.zlabel[2],
719+
position = Point3f(0, 0, offset_scale * b.zlpos[2]),
720+
color = label_color,
721+
fontsize = label_size,
722+
align = (:center, :center),
723+
)
724+
return nothing
726725
end
727726

728727
@doc raw"""

src/visualization.jl

Lines changed: 23 additions & 22 deletions
Original file line numberDiff line numberDiff line change
@@ -103,19 +103,19 @@ A structure representing a Bloch sphere visualization for quantum states.
103103
104104
- `vector_color`::Vector{String}: Colors for vectors
105105
- `vector_width`::Float64: Width of vectors
106-
- `vector_arrowsize`::NTuple{3, Real}: Arrow size parameters as (head length, head width, stem width)
106+
- `vector_arrowsize`::Vector{Float64}: Arrow size parameters as [head length, head width, stem width]
107107
108108
## Layout properties
109109
110-
- `view::Tuple{Int,Int}}`: Azimuthal and elevation viewing angles in degrees. Default: `(-60, 30)`
110+
- `view::Vector{Int}`: Azimuthal and elevation viewing angles in degrees. Default: `[30, 30]`
111111
112112
## Label properties
113-
- `xlabel::Tuple{AbstractString,AbstractString}`: Labels for x-axis. Default: `(L"x", "")`
114-
- `xlpos::Tuple{Float64,Float64}`: Positions of x-axis labels. Default: `(1.0, -1.0)`
115-
- `ylabel::Tuple{AbstractString,AbstractString}`: Labels for y-axis. Default: `(L"y", "")`
116-
- `ylpos::Tuple{Float64,Float64}`: Positions of y-axis labels. Default: `(1.0, -1.0)`
117-
- `zlabel::Tuple{AbstractString,AbstractString}`: Labels for z-axis. Default: `(L"|0\rangle", L"|1\rangle")`
118-
- `zlpos::Tuple{Float64,Float64}`: Positions of z-axis labels. Default: `(1.0, -1.0)`
113+
- `xlabel::Vector{AbstractString}`: Labels for x-axis. Default: `[L"x", ""]`
114+
- `xlpos::Vector{Float64}`: Positions of x-axis labels. Default: `[1.0, -1.0]`
115+
- `ylabel::Vector{AbstractString}`: Labels for y-axis. Default: `[L"y", ""]`
116+
- `ylpos::Vector{Float64}`: Positions of y-axis labels. Default: `[1.0, -1.0]`
117+
- `zlabel::Vector{AbstractString}`: Labels for z-axis. Default: `[L"|0\rangle", L"|1\rangle"]`
118+
- `zlpos::Vector{Float64}`: Positions of z-axis labels. Default: `[1.0, -1.0]`
119119
"""
120120
@kwdef mutable struct Bloch
121121
points::Vector{Matrix{Float64}} = Vector{Matrix{Float64}}()
@@ -126,7 +126,7 @@ A structure representing a Bloch sphere visualization for quantum states.
126126
font_size::Int = 15
127127
frame_alpha::Float64 = 0.1
128128
frame_color::String = "gray"
129-
frame_limit::Float64 = 1.14
129+
frame_limit::Float64 = 1.2
130130
point_default_color::Vector{String} = ["blue", "red", "green", "#CC6600"]
131131
point_color::Vector{Union{Nothing,String}} = Union{Nothing,String}[]
132132
point_marker::Vector{Symbol} = [:circle, :rect, :diamond, :utriangle]
@@ -137,14 +137,14 @@ A structure representing a Bloch sphere visualization for quantum states.
137137
sphere_color::String = "#FFDDDD"
138138
vector_color::Vector{String} = ["green", "#CC6600", "blue", "red"]
139139
vector_width::Float64 = 0.025
140-
vector_arrowsize::NTuple{3,Real} = (0.07, 0.08, 0.08)
141-
view::Tuple{Int,Int} = (-60, 30)
142-
xlabel::Tuple{AbstractString,AbstractString} = (L"x", "")
143-
xlpos::Tuple{Float64,Float64} = (1.0, -1.0)
144-
ylabel::Tuple{AbstractString,AbstractString} = (L"y", "")
145-
ylpos::Tuple{Float64,Float64} = (1.0, -1.0)
146-
zlabel::Tuple{AbstractString,AbstractString} = (L"|0\rangle", L"|1\rangle")
147-
zlpos::Tuple{Float64,Float64} = (1.0, -1.0)
140+
vector_arrowsize::Vector{Float64} = [0.07, 0.08, 0.08]
141+
view::Vector{Int} = [30, 30]
142+
xlabel::Vector{AbstractString} = [L"x", ""]
143+
xlpos::Vector{Float64} = [1.0, -1.0]
144+
ylabel::Vector{AbstractString} = [L"y", ""]
145+
ylpos::Vector{Float64} = [1.0, -1.0]
146+
zlabel::Vector{AbstractString} = [L"|0\rangle", L"|1\rangle"]
147+
zlpos::Vector{Float64} = [1.0, -1.0]
148148
end
149149

150150
const BLOCH_DATA_FIELDS = (:points, :vectors, :lines, :arcs)
@@ -260,10 +260,10 @@ Add a line between two points on the Bloch sphere.
260260
"""
261261
function add_line!(b::Bloch, p1::Vector{<:Real}, p2::Vector{<:Real}; fmt = "k")
262262
(length(p1) != 3 || length(p2) != 3) && throw(ArgumentError("Points must be 3D vectors"))
263-
x = [p1[2], p2[2]]
264-
y = [-p1[1], -p2[1]]
263+
x = [p1[1], p2[1]]
264+
y = [p1[2], p2[2]]
265265
z = [p1[3], p2[3]]
266-
push!(b.lines, (([x, y, z]), fmt))
266+
push!(b.lines, ([x, y, z], fmt))
267267
return b
268268
end
269269

@@ -443,8 +443,9 @@ function _ket_to_bloch(state::QuantumObject{Ket})
443443
ψ = state.data
444444
end
445445

446-
x = 2 * real(ψ[1] * conj(ψ[2]))
447-
y = 2 * imag(ψ[1] * conj(ψ[2]))
446+
c = conj(ψ[1]) * ψ[2]
447+
x = 2 * real(c)
448+
y = 2 * imag(c)
448449
z = abs2(ψ[1]) - abs2(ψ[2])
449450
return [x, y, z]
450451
end

test/ext-test/cpu/makie/makie_ext.jl

Lines changed: 12 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -160,15 +160,22 @@ end
160160
@test false
161161
@info "Render threw unexpected error" exception=e
162162
end
163+
164+
# test `state to Bloch vector` conversion and `add_states!` function
163165
b = Bloch()
164-
add_states!(b, basis(2, 0))
165-
x = normalize!(basis(2, 0) + basis(2, 1)) # normalized
166-
y = basis(2, 0) - im * basis(2, 1) # unnormalized Ket
166+
Pauli_Ops = [sigmax(), sigmay(), sigmaz()]
167+
ψ = rand_ket(2)
168+
ρ = rand_dm(2)
169+
x = basis(2, 0) + basis(2, 1) # unnormalized Ket
167170
ρ1 = 0.3 * rand_dm(2) + 0.4 * rand_dm(2) # unnormalized density operator
168171
ρ2 = Qobj(rand(ComplexF64, 2, 2)) # unnormalized and non-Hermitian Operator
169-
@test_logs (:warn,) (:warn,) (:warn,) (:warn,) add_states!(b, [x, y, ρ1, ρ2])
172+
add_states!(b, [ψ, ρ])
173+
@test_logs (:warn,) (:warn,) (:warn,) (:warn,) add_states!(b, [x, ρ1, ρ2])
174+
@test all(expect(Pauli_Ops, ψ) .≈ (b.vectors[1]))
175+
@test all(expect(Pauli_Ops, ρ) .≈ (b.vectors[2]))
170176
@test length(b.vectors) == 5
171-
th = range(0, 2π; length = 20);
177+
178+
th = range(0, 2π; length = 20)
172179
xp = cos.(th);
173180
yp = sin.(th);
174181
zp = zeros(20);

0 commit comments

Comments
 (0)