using PlotlyJS, Parameters
#-----------------------------------------------------------------------#
@with_kw mutable struct Quiver
x::AbstractArray #Array of x-coord for arrow positions
y::AbstractArray #Array of y-coord for arrow positions
u::AbstractArray #Array of first coord of the vector field
v::AbstractArray #Array of second coord of the vector field
vector_scale = 0.1 #scale factor in (0, 1] for the vector directions to avoid quiver overlapping
arrow_scale = 0.3
angle = π/9
scaleratio = 1.0 #aspect ratio for the 2d plot
d =1.0 #a scale factor in (0.9, 1] for the already scaled direction;
#d=0.95 makes a sharper arrow when barb line has width>1 (for example, when plotting single arrow)
end
function tuple_interleave(tu::Union{NTuple{3, Vector}, NTuple{4, Vector}})
#auxilliary function to interleave elements of a NTuple of vectors, N=3 or 4
zipped_data = collect(zip(tu...))
vv_zdata = [collect(elem) for elem in zipped_data]
return reduce(vcat, vv_zdata)
end
function quiverPlot(q::Quiver; color="RoyalBlue")
@unpack_Quiver q
x = vec(x)
y = vec(y)
u = vec(u)
v = vec(v)
(length(x) == length(y) == length(u) == length(v)) &&
vector_scale > 0 && arrow_scale > 0 ||
error("the vects x, y, u, v do not have the same length")
u = vector_scale * scaleratio *u
v = vector_scale * v
end_x = x .+ u
end_y = y .+ v
vect_nans = repeat([NaN], length(x))
barb_x = tuple_interleave((x, x .+ d*u, vect_nans))
barb_y = tuple_interleave((y, y .+ d*v, vect_nans))
barb_length = sqrt.((u/scaleratio) .^2 .+ v .^2)
arrow_length = arrow_scale * barb_length
barb_angle = atan.(v, u/scaleratio)
ang1 = barb_angle .+ angle
ang2 = barb_angle .- angle
seg1_x = arrow_length .* cos.(ang1)
seg1_y = arrow_length .* sin.(ang1)
seg2_x = arrow_length .* cos.(ang2)
seg2_y = arrow_length .* sin.(ang2)
arrowend1_x = end_x .- seg1_x *scaleratio
arrowend1_y = end_y .- seg1_y
arrowend2_x = end_x .- seg2_x *scaleratio
arrowend2_y = end_y .- seg2_y
arrow_x = tuple_interleave((arrowend1_x, end_x, arrowend2_x, vect_nans))
arrow_y = tuple_interleave((arrowend1_y, end_y, arrowend2_y, vect_nans))
barb = scatter(x=barb_x, y=barb_y, mode="lines", line_color=color, name="")
arrow = scatter(x=arrow_x, y=arrow_y, mode="lines", line_color=color,
fill="toself", fillcolor=color, hoverinfo="skip")
layout = Layout(yaxis=attr(scaleratio=scaleratio, scaleanchor="x"),
showlegend=false)
return Plot([barb, arrow], layout)
end
#--------------------------------------------------------------------------------#
The WebIO Jupyter extension was not detected. See the WebIO Jupyter integration documentation for more information.
quiverPlot (generic function with 1 method)
Examples
q= Quiver(x=[0],y=[0], u=[1], v=[1], vector_scale=1, angle=pi/18, d=0.95)
Quiver x: Array{Int64}((1,)) [0] y: Array{Int64}((1,)) [0] u: Array{Int64}((1,)) [1] v: Array{Int64}((1,)) [1] vector_scale: Int64 1 arrow_scale: Float64 0.3 angle: Float64 0.17453292519943295 scaleratio: Float64 1.0 d: Float64 0.95
fig1 = quiverPlot(q;)
update!(fig1, line_width=4, [1], layout=Layout(width=400, height=400))
display(fig1)
q2=Quiver(x=[0], y=[0], u=[1], v=[1], vector_scale=1, angle=pi/24, d=0.95)
fig2 = quiverPlot(q2;)
update!(fig2, line_width=4, [1], layout=Layout(width=400, height=400))
display(fig2)
Vector field:
xl = yl = -π:π/8:π
xq = [xi for yi in yl, xi in xl]
yq = [yi for yi in yl, xi in xl]
uq = sin.(yq)
vq = cos.(xq)
#norm_vects = sqrt.(uq .^2 + vq .^2)
q3 = Quiver(x=xq, y=yq, u=uq, v=vq, vector_scale=0.375, angle=pi/12)
fig3 = quiverPlot(q3;)
update!(fig3, line_width=0.75, [1],
layout=Layout(title_text="Quiver plot with PlotlyJS.jl", title_x=0.5,
width=500, height=500, xaxis_constain="domain",
yaxis_constain="domain"))
display(fig3)
xl = yl = range(0, 1, length=16)
x = [xi for yi in yl, xi in xl]
y = [yi for yi in yl, xi in xl]
u = @. sin(π*x) * cos(π*y)
v = @. cos(π*x) * sin(π*y)
q4 = Quiver(x=x, y=y, u=u, v=v, vector_scale=0.062)
fig4 = quiverPlot(q4; color="#8f180b")
update!(fig4, line_width=0.75, [1],
layout=Layout(width=500, height=500, plot_bgcolor="#faeee0",
template=nothing,
xaxis_zeroline=false, yaxis_zeroline=false))
display(fig4)