Skip to content

Commit f761096

Browse files
committed
Switch plotting backend from PythonCall to CairoMakie
1 parent 78a960f commit f761096

24 files changed

+246
-317
lines changed

.ci/Project.toml

-1
Original file line numberDiff line numberDiff line change
@@ -5,7 +5,6 @@ version = "0.1.0"
55

66
[deps]
77
Comonicon = "863f3e99-da2a-4334-8734-de3dacbe5542"
8-
CondaPkg = "992eb4ea-22a4-4c89-a5bb-47a3300528ab"
98
CoverageTools = "c36e975a-824b-4404-a568-ef97ca766997"
109
Literate = "98b081ad-f1c9-55d3-8b20-4c87d4299306"
1110
LiveServer = "16fef848-5104-11e9-1b77-fb7a48bbb589"

.ci/src/example.jl

-2
Original file line numberDiff line numberDiff line change
@@ -141,15 +141,13 @@ in parallel.
141141
example_dir = root_dir("examples")
142142
script = """
143143
using Pkg
144-
using CondaPkg
145144
using Literate
146145
for name in readdir(\"$example_dir\")
147146
project_dir = joinpath(\"$example_dir\", name)
148147
isdir(project_dir) || continue
149148
150149
Pkg.activate(project_dir)
151150
Pkg.instantiate()
152-
CondaPkg.resolve()
153151
154152
@info "building" project_dir
155153
Literate.$target(

CondaPkg.toml

-2
This file was deleted.

Project.toml

+1-2
Original file line numberDiff line numberDiff line change
@@ -9,11 +9,11 @@ BloqadeLattices = "bd27d05e-4ce1-5e79-84dd-c5d7d508bbe4"
99
BloqadeMIS = "bd27d05e-4ce1-5e74-84dd-c5d7d508bbe2"
1010
BloqadeODE = "bd27d05e-4ce1-5e79-84dd-c5d7d508bbe5"
1111
BloqadeWaveforms = "bd27d05e-4ce1-5e79-84dd-c5d7d508bbe7"
12+
CairoMakie = "13f3f980-e62b-5c42-98c6-ff1f3baf88f0"
1213
ColorSchemes = "35d6a980-a343-548e-a6ea-1d62b119f2f4"
1314
Colors = "5ae59095-9a9b-59fe-a467-6f913c188581"
1415
ForwardDiff = "f6369f11-7733-5829-9624-2563aa707210"
1516
Measurements = "eff96d63-e80a-5855-80a2-b1b0885c5ab7"
16-
PythonCall = "6099a3de-0909-46bc-b1f4-468b9a2dfc0d"
1717
Reexport = "189a3867-3050-52da-a836-e630ba90ab69"
1818
Yao = "5872b779-8223-5990-8dd0-5abbb0748c8c"
1919
YaoSubspaceArrayReg = "bd27d05e-4ce1-5e79-84dd-c5d7d508ade2"
@@ -29,7 +29,6 @@ ColorSchemes = "3"
2929
Colors = "0.12"
3030
ForwardDiff = "0.10"
3131
Measurements = "2"
32-
PythonCall = "0.8,0.9"
3332
Reexport = "1"
3433
Yao = "0.9"
3534
YaoSubspaceArrayReg = "0.2"

docs/Project.toml

-1
Original file line numberDiff line numberDiff line change
@@ -16,7 +16,6 @@ Documenter = "e30172f5-a6a5-5a46-863b-614d45cd2de4"
1616
Graphs = "86223c79-3864-5bf0-83f7-82e725a168b6"
1717
KrylovKit = "0b1a1467-8014-51b9-945f-bf0ae24f4b77"
1818
Literate = "98b081ad-f1c9-55d3-8b20-4c87d4299306"
19-
PythonCall = "6099a3de-0909-46bc-b1f4-468b9a2dfc0d"
2019
Unitful = "1986cc42-f94f-5a68-af5c-568840ba703d"
2120
Yao = "5872b779-8223-5990-8dd0-5abbb0748c8c"
2221
YaoAPI = "0843a435-28de-4971-9e8b-a9641b2983a8"

docs/src/install.md

-4
Original file line numberDiff line numberDiff line change
@@ -57,8 +57,6 @@ Built on top of Ubuntu Server 20.04 LTS, this image includes
5757
- [Yao.jl](https://yaoquantum.org/)
5858
- [Revise.jl](https://github.com/timholy/Revise.jl)
5959
- [BenchmarkTools.jl](https://juliaci.github.io/BenchmarkTools.jl/stable/)
60-
- [PythonCall.jl](https://cjdoris.github.io/PythonCall.jl/stable/)
61-
- Conda package manager, provided by [Miniconda](https://docs.conda.io/en/latest/miniconda.html)
6260

6361
#### Bloqade CUDA AMI
6462

@@ -227,8 +225,6 @@ Built on top of Ubuntu Server 20.04 LTS, this image includes
227225
- [Yao.jl](https://yaoquantum.org/)
228226
- [Revise.jl](https://github.com/timholy/Revise.jl)
229227
- [BenchmarkTools.jl](https://juliaci.github.io/BenchmarkTools.jl/stable/)
230-
- [PythonCall.jl](https://cjdoris.github.io/PythonCall.jl/stable/)
231-
- Conda package manager, provided by [Mamba](https://mamba.readthedocs.io/en/latest/index.html)
232228
- Jupyter Lab interface with dedicated Julia and Python kernels
233229
- Integrated Terminal for interactive command-line sessions
234230

docs/src/waveform.md

+17-10
Original file line numberDiff line numberDiff line change
@@ -17,14 +17,11 @@ which is a created by providing a callable object and a real number `duration`:
1717
Bloqade gives users the flexibility to specify general waveforms by inputting functions. The following code constructs a sinusoidal waveform with a time duration of 2 μs:
1818

1919
```@example waveform
20-
using Bloqade
21-
using PythonCall
22-
plt = pyimport("matplotlib.pyplot")
20+
using Bloqade, Bloqade.CairoMakie
2321
waveform = Waveform(t->2.2*2π*sin(2π*t), duration = 2);
2422
Bloqade.plot(waveform)
2523
```
26-
In our documentation, we use the
27-
python package [`matplotlib`](https://matplotlib.org) for plotting.
24+
In our documentation, we use the [`CairoMakie`](https://docs.makie.org/) for plotting.
2825

2926
Bloqade supports built-in waveforms for convenience (see References below).
3027
For example, the codes below create different waveform shapes with a single line:
@@ -63,7 +60,9 @@ wf1 = piecewise_linear(;clocks, values=values1);
6360
values2 = 2π*rand(length(clocks)-1)
6461
wf2 = piecewise_constant(;clocks, values=values2);
6562
66-
fig, (ax1, ax2) = plt.subplots(figsize=(12, 4), ncols=2)
63+
fig = Figure(size=(960, 400))
64+
ax1 = Axis(fig[1, 1])
65+
ax2 = Axis(fig[1, 2])
6766
Bloqade.plot!(ax1, wf1)
6867
Bloqade.plot!(ax2, wf2)
6968
fig
@@ -104,7 +103,9 @@ waveform:
104103
wf = piecewise_linear(clocks=[0.0, 2.0, 3.0, 4.0], values=2π*[0.0, 3.0, 1.1, 2.2]);
105104
swf = smooth(wf;kernel_radius=0.1);
106105
107-
fig, (ax1, ax2) = plt.subplots(figsize=(12, 4), ncols=2)
106+
fig = Figure(size=(960, 400))
107+
ax1 = Axis(fig[1, 1])
108+
ax2 = Axis(fig[1, 2])
108109
Bloqade.plot!(ax1, wf)
109110
Bloqade.plot!(ax2, swf)
110111
fig
@@ -120,7 +121,9 @@ wf2 = sinusoidal(duration = 2.2, amplitude = 2.2*2π);
120121
wf3 = wf1 + wf2;
121122
wf4 = wf1 - wf2;
122123
123-
fig, (ax1, ax2) = plt.subplots(figsize=(12, 4), ncols=2)
124+
fig = Figure(size=(960, 400))
125+
ax1 = Axis(fig[1, 1])
126+
ax2 = Axis(fig[1, 2])
124127
Bloqade.plot!(ax1, wf3)
125128
Bloqade.plot!(ax2, wf4)
126129
fig
@@ -133,7 +136,9 @@ To increase the strength of a waveform by some factors, we can directly use `*`:
133136
wf = linear_ramp(;duration=2.2, start_value=0.0, stop_value=1.0*2π);
134137
wf_t = 3 * wf;
135138
136-
fig, (ax1, ax2) = plt.subplots(figsize=(12, 4), ncols=2)
139+
fig = Figure(size=(960, 400))
140+
ax1 = Axis(fig[1, 1])
141+
ax2 = Axis(fig[1, 2])
137142
Bloqade.plot!(ax1, wf)
138143
Bloqade.plot!(ax2, wf_t)
139144
fig
@@ -144,7 +149,9 @@ Such operations can also be broadcasted by using `.*`:
144149
```@example waveform
145150
wf2, wf3 = [2.0, 3.0] .* wf1;
146151
147-
fig, (ax1, ax2) = plt.subplots(figsize=(12, 4), ncols=2)
152+
fig = Figure(size=(960, 400))
153+
ax1 = Axis(fig[1, 1])
154+
ax2 = Axis(fig[1, 2])
148155
Bloqade.plot!(ax1, wf2)
149156
Bloqade.plot!(ax2, wf3)
150157
fig

examples/1.blockade/Project.toml

-1
Original file line numberDiff line numberDiff line change
@@ -7,7 +7,6 @@ BloqadeMIS = "bd27d05e-4ce1-5e74-84dd-c5d7d508bbe2"
77
BloqadeODE = "bd27d05e-4ce1-5e79-84dd-c5d7d508bbe5"
88
BloqadeWaveforms = "bd27d05e-4ce1-5e79-84dd-c5d7d508bbe7"
99
Literate = "98b081ad-f1c9-55d3-8b20-4c87d4299306"
10-
PythonCall = "6099a3de-0909-46bc-b1f4-468b9a2dfc0d"
1110
Unitful = "1986cc42-f94f-5a68-af5c-568840ba703d"
1211
Yao = "5872b779-8223-5990-8dd0-5abbb0748c8c"
1312
YaoArrayRegister = "e600142f-9330-5003-8abb-0ebd767abc51"

examples/1.blockade/main.jl

+23-20
Original file line numberDiff line numberDiff line change
@@ -345,26 +345,29 @@ for _ in TimeChoiceIterator(integrator2, 0.0:dt:Tmax)
345345
end
346346

347347
# Plot the data:
348-
using PythonCall # Use matplotlib to generate plots
349-
matplotlib = pyimport("matplotlib")
350-
plt = pyimport("matplotlib.pyplot")
351-
352-
ax = plt.subplot(1, 1, 1)
353-
plt.plot(times, real(densities), "k", label = "Full space")
354-
plt.plot(times, real(densities2), "r--", label = "Subspace")
355-
ax.axis([0, Tmax, 0, 0.45])
356-
plt.xlabel("Time (us)")
357-
plt.ylabel("Rydberg density")
358-
plt.tight_layout()
359-
plt.legend()
360-
361-
inset_axes = pyimport("mpl_toolkits.axes_grid1.inset_locator")
362-
ax2 = inset_axes.inset_axes(ax, width = "20%", height = "30%", loc = "lower right", borderpad = 1)
363-
plt.plot(times, real(densities - densities2))
364-
plt.axis([0, 0.5, -0.001, 0.003])
365-
plt.ylabel("Difference", fontsize = 12)
366-
plt.yticks(LinRange(-0.001, 0.003, 5), fontsize = 12);
367-
plt.xticks([0, 0.2, 0.4, 0.6], fontsize = 12);
348+
using Bloqade.CairoMakie # Use CairoMakie to generate plots
349+
350+
fig = Figure()
351+
ax = Axis(fig[1, 1], xlabel = "Time (us)", ylabel = "Rydberg density", limits=(0.0, Tmax, 0.0, 0.45))
352+
lines!(ax, times, real(densities), label = "Full space", color=:black)
353+
lines!(ax, times, real(densities2), label = "Subspace", color=:red, linestyle=:dash)
354+
axislegend(ax, position = :rt)
355+
fig
356+
357+
# The inset axis
358+
ax2 = Axis(fig[1, 1],
359+
width=Relative(0.2),
360+
height=Relative(0.3),
361+
halign=0.9,
362+
valign=0.1,
363+
limits=(0.0, 0.5, -0.001, 0.003),
364+
ylabel="Difference",
365+
yticks=LinRange(-0.001, 0.003, 5),
366+
xticks=[0, 0.2, 0.4, 0.6],
367+
backgroundcolor=:lightgray)
368+
369+
lines!(ax2, times, real(densities - densities2), color = :black)
370+
fig;
368371

369372
# ![RydbergBlockadeSubspace](../../../assets/RydbergBlockadeSubspace.png)
370373

examples/2.adiabatic/Project.toml

-1
Original file line numberDiff line numberDiff line change
@@ -7,7 +7,6 @@ BloqadeMIS = "bd27d05e-4ce1-5e74-84dd-c5d7d508bbe2"
77
BloqadeODE = "bd27d05e-4ce1-5e79-84dd-c5d7d508bbe5"
88
BloqadeWaveforms = "bd27d05e-4ce1-5e79-84dd-c5d7d508bbe7"
99
KrylovKit = "0b1a1467-8014-51b9-945f-bf0ae24f4b77"
10-
PythonCall = "6099a3de-0909-46bc-b1f4-468b9a2dfc0d"
1110
YaoSubspaceArrayReg = "bd27d05e-4ce1-5e79-84dd-c5d7d508ade2"
1211

1312
[extras]

examples/2.adiabatic/main.jl

+30-51
Original file line numberDiff line numberDiff line change
@@ -19,12 +19,10 @@
1919
# Let's start by importing the required libraries:
2020

2121
using Bloqade
22-
using PythonCall
22+
using Bloqade.CairoMakie
2323
using KrylovKit
2424
using SparseArrays
2525

26-
plt = pyimport("matplotlib.pyplot");
27-
2826
# # Ground State Properties
2927

3028
# We start by probing the ground state properties of the Rydberg Hamiltonian in a 1D system.
@@ -59,21 +57,15 @@ end
5957

6058
# To compare, we first plot the density profile when ``\Delta= -2π \times 10`` MHz:
6159

62-
fig, ax = plt.subplots(figsize = (10, 4))
63-
ax.bar(1:nsites, density_g[1, :])
64-
ax.set_xticks(1:nsites)
65-
ax.set_xlabel("Sites")
66-
ax.set_ylabel("Rydberg density")
67-
ax.set_title("Density Profile: 1D Chain, Δ = -2π * 10 MHz")
60+
fig = Figure(size=(800, 320))
61+
ax = Axis(fig[1, 1], xlabel = "Sites", ylabel = "Rydberg density", title = "Density Profile: 1D Chain, Δ = -2π * 10 MHz", xticks = 1:nsites)
62+
barplot!(ax, 1:nsites, density_g[1, :])
6863
fig
6964

7065
# We can see that the Rydberg densities in this case are close to 0 for all sites. In contrast, for ``\Delta= 2π \times 10`` MHz, the density shows a clear ``Z_2`` ordered profile:
71-
fig, ax = plt.subplots(figsize = (10, 4))
72-
ax.bar(1:nsites, density_g[30, :])
73-
ax.set_xticks(1:nsites)
74-
ax.set_xlabel("Sites")
75-
ax.set_ylabel("Rydberg density")
76-
ax.set_title("Density Profile: 1D Chain, Δ = 2π * 10 MHz")
66+
fig = Figure(size=(800, 320))
67+
ax = Axis(fig[1, 1], xlabel = "Sites", ylabel = "Rydberg density", title = "Density Profile: 1D Chain, Δ = 2π * 10 MHz", xticks = 1:nsites)
68+
barplot!(ax, 1:nsites, density_g[30, :])
7769
fig
7870

7971
# More generally, we can plot an order parameter as a function of ``\Delta`` to clearly see the onset of phase transition.
@@ -83,13 +75,10 @@ order_para = map(1:Δ_step) do ii
8375
return sum(density_g[ii, 1:2:nsites]) - sum(density_g[ii, 2:2:nsites]) # density on odd sites - density on even sites
8476
end
8577

86-
fig, ax = plt.subplots(figsize = (10, 4))
87-
ax.plot/ 2π, order_para)
88-
ax.set_xlabel("Δ/2π (MHz) ")
89-
ax.set_ylabel("Order parameter")
78+
fig = Figure(size=(800, 320))
79+
ax = Axis(fig[1, 1], xlabel = "Δ/2π (MHz)", ylabel = "Order parameter")
80+
lines!(ax, Δ / (2π), order_para)
9081
fig
91-
92-
# From the density profile of ground states and the change in the order parameter, we can observe a phase transition with changing ``\Delta``.
9382
# Below, we show that by slowly changing the parameters of the Hamiltonian, we can follow the trajectory of the ground states and adiabatically evolve the atoms from the ground state to the ``Z_2``
9483
# ordered state.
9584

@@ -106,13 +95,12 @@ U2 = 2π * 10;
10695
Δ = piecewise_linear(clocks = [0.0, 0.6, 2.1, total_time], values = [U1, U1, U2, U2]);
10796

10897
# We plot the two waveforms:
109-
fig, (ax1, ax2) = plt.subplots(ncols = 2, figsize = (12, 4))
110-
Bloqade.plot!(ax1, Ω)
111-
ax1.set_ylabel("Ω/2π (MHz)")
112-
Bloqade.plot!(ax2, Δ)
113-
ax2.set_ylabel("Δ/2π (MHz)")
98+
fig = Figure(size=(960, 320))
99+
ax1 = Axis(fig[1, 1], ylabel = "Ω/2π (MHz)")
100+
ax2 = Axis(fig[1, 2], ylabel = "Δ/2π (MHz)")
101+
Bloqade.plot!(ax1, Ω / (2π))
102+
Bloqade.plot!(ax2, Δ / (2π))
114103
fig
115-
116104
# We generate the positions for a 1D atomic chain again:
117105

118106
nsites = 9
@@ -136,19 +124,13 @@ densities = []
136124
for _ in TimeChoiceIterator(integrator, 0.0:1e-3:total_time)
137125
push!(densities, rydberg_density(reg))
138126
end
139-
D = hcat(densities...);
140-
141-
# and finally plot the time-dependent dynamics of Rydberg density for each site:
142-
fig, ax = plt.subplots(figsize = (10, 4))
143-
shw = ax.imshow(real(D), interpolation = "nearest", aspect = "auto", extent = [0, total_time, 0.5, nsites + 0.5])
144-
ax.set_xlabel("time (μs)")
145-
ax.set_ylabel("site")
146-
ax.set_xticks(0:0.2:total_time)
147-
ax.set_yticks(1:nsites)
148-
bar = fig.colorbar(shw)
149-
fig
127+
D = hcat(densities...)';
150128

151-
# We can clearly see that a ``Z_2`` ordered state has been generated by the specified adiabatic pulse sequence.
129+
fig = Figure(size=(800, 320))
130+
ax = Axis(fig[1, 1], xlabel = "time (μs)", ylabel = "site", xticks=0:0.2:total_time, yticks=(0.5:1:nsites, string.(1:nsites)))
131+
shw = heatmap!(ax, LinRange(0.0, total_time, size(D, 1)), LinRange(0.5, nsites - 0.5, size(D, 2)), real(D))
132+
Colorbar(fig[1, 2], shw, label = "Rydberg density")
133+
fig
152134
# We can also confirm it by plotting the bitstring distribution at the final time step:
153135

154136
bitstring_hist(reg; nlargest = 20)
@@ -194,11 +176,11 @@ total_time = 2.9
194176
U = 2π * 15.0
195177
Δ = piecewise_linear(clocks = [0.0, 0.3, 2.6, total_time], values = [-U, -U, U, U]);
196178

197-
fig, (ax1, ax2) = plt.subplots(ncols = 2, figsize = (10, 4))
179+
fig = Figure(size=(800, 320))
180+
ax1 = Axis(fig[1, 1], ylabel = "Ω/2π (MHz)")
181+
ax2 = Axis(fig[1, 2], ylabel = "Δ/2π (MHz)")
198182
Bloqade.plot!(ax1, Ω)
199-
ax1.set_ylabel("Ω/2π (MHz)")
200183
Bloqade.plot!(ax2, Δ)
201-
ax2.set_ylabel("Δ/2π (MHz)")
202184
fig
203185

204186
# Then, we use the waveforms and atom positions to create a Hamiltonian and define a time evolution problem:
@@ -213,13 +195,10 @@ densities = [];
213195
for _ in TimeChoiceIterator(integrator, 0.0:1e-3:total_time)
214196
push!(densities, rydberg_density(reg))
215197
end
216-
D = hcat(densities...)
217-
218-
fig, ax = plt.subplots(figsize = (10, 4))
219-
shw = ax.imshow(real(D), interpolation = "nearest", aspect = "auto", extent = [0, total_time, 0.5, nsites + 0.5])
220-
ax.set_xlabel("time (μs)")
221-
ax.set_ylabel("site")
222-
ax.set_xticks(0:0.2:total_time)
223-
ax.set_yticks(1:nsites)
224-
bar = fig.colorbar(shw)
198+
D = hcat(densities...)'
199+
200+
fig = Figure(size=(800, 320))
201+
ax = Axis(fig[1, 1], xlabel = "time (μs)", ylabel = "site", xticks=0:0.2:total_time, yticks=(0.5:1:nsites, string.(1:nsites)))
202+
shw = heatmap!(ax, LinRange(0.0, total_time, size(D, 1)), LinRange(0.5, nsites - 0.5, size(D, 2)), real(D))
203+
Colorbar(fig[1, 2], shw, label = "Rydberg density")
225204
fig

examples/3.quantum-scar/Project.toml

+1-2
Original file line numberDiff line numberDiff line change
@@ -1,14 +1,13 @@
11
[deps]
2-
CairoMakie = "13f3f980-e62b-5c42-98c6-ff1f3baf88f0"
32
Bloqade = "bd27d05e-4ce1-5e79-84dd-c5d7d508bbe1"
43
BloqadeExpr = "bd27d05e-4ce1-5e79-84dd-c5d7d508abe2"
54
BloqadeKrylov = "bd27d05e-4cd1-5e79-84dd-c5d7d508ade2"
65
BloqadeLattices = "bd27d05e-4ce1-5e79-84dd-c5d7d508bbe4"
76
BloqadeMIS = "bd27d05e-4ce1-5e74-84dd-c5d7d508bbe2"
87
BloqadeODE = "bd27d05e-4ce1-5e79-84dd-c5d7d508bbe5"
98
BloqadeWaveforms = "bd27d05e-4ce1-5e79-84dd-c5d7d508bbe7"
9+
CairoMakie = "13f3f980-e62b-5c42-98c6-ff1f3baf88f0"
1010
Literate = "98b081ad-f1c9-55d3-8b20-4c87d4299306"
11-
PythonCall = "6099a3de-0909-46bc-b1f4-468b9a2dfc0d"
1211
Unitful = "1986cc42-f94f-5a68-af5c-568840ba703d"
1312
Yao = "5872b779-8223-5990-8dd0-5abbb0748c8c"
1413
YaoArrayRegister = "e600142f-9330-5003-8abb-0ebd767abc51"

0 commit comments

Comments
 (0)