3D quiver plot?

Hello!

I am aware of the quiver function, but am not sure how to easily do a 3d quiver plot?

Kind regards

https://makie.juliaplots.org/stable/examples/plotting_functions/arrows/#example_2533070602242681981

Nice, thanks for letting me know.

I found this: Proposes a 3D quiver by kellertuer · Pull Request #3134 · JuliaPlots/Plots.jl · GitHub

And just tested, I was trying quiver3d, but basically just use quiver.

I don’t get any arrows though, which is annoying

Kind regards

You could try the arrow3d! user function posted here (NB: the code is posted below the figures).

It allows displaying either fixed arrowhead sizes or having these varying proportionally to vector length.

Thanks Rafael!

Do you have a solution which is not done in Julia 1.7.0? Since it is not fully released right now, I prefer to stay on a older version (1.5). I get this bug:

ERROR: MethodError: no method matching svd!(::Array{Float64,1}; full=true, alg=LinearAlgebra.DivideAndConquer())

Kind regards

For older Julia version, please try this, to get one normal vector out of nullspace()

Sorry, I am not getting it completely.

The code I have now is:

function arrow3d!(x, y, z,  u, v, w; as=0.1, lc=:black, la=1, lw=0.4, scale=:identity)
    (as < 0) && (nv0 = -maximum(norm.(eachrow([u v w]))))
    for (x,y,z, u,v,w) in zip(x,y,z, u,v,w)
        nv = sqrt(u^2 + v^2 + w^2)
        v1, v2 = -[u,v,w]/nv, collect(eachcol(nullspace(permutedims([u,v,w]))))
        v4 = (3*v1 + v2)/3.1623  # sqrt(10) to get unit vector
        v5 = v4 - 2*(v4'*v2)*v2
        (as < 0) && (nv = nv0) 
        v4, v5 = -as*nv*v4, -as*nv*v5
        plot!([x,x+u], [y,y+v], [z,z+w], lc=lc, la=la, lw=lw, scale=scale, label=false)
        plot!([x+u,x+u-v5[1]], [y+v,y+v-v5[2]], [z+w,z+w-v5[3]], lc=lc, la=la, lw=lw, label=false)
        plot!([x+u,x+u-v4[1]], [y+v,y+v-v4[2]], [z+w,z+w-v4[3]], lc=lc, la=la, lw=lw, label=false)
    end
end

I am not really sure how to fix this, it is now saying:

ERROR: MethodError: no method matching +(::Float64, ::SubArray{Float64,1,Array{Float64,2},Tuple{Base.Slice{Base.OneTo{Int64}},Int64},true})
For element-wise addition, use broadcasting with dot syntax: scalar .+ array

I struggle with the math, else I would have done what I could to fix it.

Kind regards

We need to collect just the first vector from the nullspace:

collect(eachcol(nullspace(permutedims([u,v,w]))))[1]

With this modification it works fine in Julia 1.6.2.

NB:
In the time available now could not make it to work without using collect() (@DNF to the rescue) and really not sure why the alternative below errors for the examples linked:

first.(eachcol(nullspace(permutedims([u,v,w]))))

I am using what you suggest now, but it also seemed to me to work with using:

nullspace(permutedims([u, v, w]))[:,1]

And arrows were pointing in the same direction as in your pictures etc. Perhaps this is a way to do it without collect?

I did not think about it too much, I just tried until I got something which seemingly worked.

But thank you for the code! Makes my life much easier. Wish quiver had this functionality build-in though

Kind regards

1 Like

PlotlyJS.jl provides a 3d quiver plot, called cone3d chart, and here are a few examples:

  1. https://nbviewer.jupyter.org/github/empet/3D-Viz-with-PlotlyJS.jl/blob/main/10-Cones-representing-a-vector-field.ipynb
  2. https://nbviewer.jupyter.org/github/empet/3D-Viz-with-PlotlyJS.jl/blob/main/11-Cone-plots-in-a-volume.ipynb

Reference: cone Traces | Julia | Plotly

1 Like

This makes me wonder why Robin Hood is still a legend:

1 Like