@empet I’m not sure how a cyclic colormap could help. Just to to be clear: I’m not interested in the heatmap, only the contour plot. I’ve also tried applying some periodic function to the imaginary part, such as cos, which maps [-π, π] to a cyclic interval and fixes the problem, but it changes the shape/spacing of the black contours, which is not what I want. Picture for reference:
@jules Ah didn’t know that, makes sense. And yeah, I’m also not confident that solely using the contour plot is enough for this, but I’ll look into the marching squares algorithm.
As a side note, I’ve made another plot in which the contour wasn’t the best option, because I was able to parameterize the contour lines and just simply draw them. I tried doing it using the contours, and it turned out OK:
# auxiliary functions
Re(x::Complex) = x.re
Im(x::Complex) = x.im
Re(x::Real) = x
Im(x::Real) = 0
# semi-infinite capacitor
using LambertW
V1 = 10 # Potential of lower plate
V2 = 100 # Potential of higher plate
function g(z::Complex)
# We need to use different branches of the lambert w function
k = 0
if Im(z) > π
k = 1
elseif Im(z) < -π
k = -1
end
-lambertw(exp(z-1), k) + z-1
end
Ω(z::Complex) = -im*(V2-V1)/(2π) * z + (V1+V2)/2
fig = Figure(font = "FiraCode Nerd Font")
axis = Axis(fig[1, 1],
title = L"\Omega(z) = -i \frac{V_2 - V_1}{2 \pi}\left(-W(e^{z-1}) + z-1\right) + \frac{V_1 + V_2}{2}",
aspect = DataAspect())
xmin, xmax = -5, 10
ymin, ymax = -5, 5
xs = LinRange(xmin, xmax, 100)
ys = LinRange(ymin, ymax, 100)
I = [Ω(g(x + y*im)) for x in xs, y in ys]
us = Re.(I)
vs = Im.(I)
vs = map(x -> if(isinf(x)) 0 else x end, vs)
contour!(xs, ys, us, levels = 20, linewidth=2, color = :deepskyblue)
contour!(xs, ys, vs, levels = 20, linewidth=2, color = :gray3)
xlims!(low = xmin, high = xmax)
ylims!(low = ymin, high = ymax)
xs = LinRange(xmin, 0, 100)
ys1 = -π*ones(100)
ys2 = π*ones(100)
lines!(xs,ys1, linewidth=8,color = :lightcoral)
lines!(xs,ys2, linewidth=8,color = :lightcoral)
fig
As you can see, no discontinuities, but I had to use different branches of the lambert W function. If I just used the default k = 0 branch:
But, because of the conformal mapping that is used, it is easier to parameterize the function(and as a bonus, we can plot stream arrows):
xmin, xmax = -5, 10
ymin, ymax = -5, 5
umin, umax = -10, 2.2
vmin, vmax = -π, π
# v = A => equipotentials
X(u, v) = 1 + u + exp(u)*cos(v)
Y(u, v) = v + exp(u)*sin(v)
f5 = Figure(font = "FiraCode Nerd Font")
axis = Axis(f5[1, 1],
title = L"$\Omega(z)$ for a semi-infinite capacitor in 2D",
aspect = DataAspect())
us = LinRange(umin, umax, 100)
vs = LinRange(vmin, vmax, 100)
vs_arr = LinRange(vmin+0.1, vmax-0.1, 10)
for v in LinRange(vmin, vmax, 30)
_x(t) = X(t, v)
_y(t) = Y(t, v)
lines!(_x.(us),_y.(us), linewidth=2,color = :deepskyblue)
end
for u in LinRange(umin, umax, 30)
_x(t) = X(u, t)
_y(t) = Y(u, t)
_xv(t) = -exp(u) * sin(t)
_yv(t) = 1 + exp(u) * cos(t)
lines!(_x.(vs),_y.(vs), linewidth=2,color = :gray3)
arrows!(_x.(vs_arr),_y.(vs_arr), _xv.(vs_arr),_yv.(vs_arr), arrowsize = 10, lengthscale = 0.01)
end
xs = LinRange(xmin, 0, 100)
ys1 = -π*ones(100)
ys2 = π*ones(100)
lines!(xs,ys1, linewidth=8,color = :lightcoral)
lines!(xs,ys2, linewidth=8,color = :lightcoral)
xlims!(low = xmin, high = xmax)
ylims!(low = ymin, high = ymax)
f5