# Plotting an ellipsoid as 2D surface in 3D, given the principal axes

**URL:** <https://discourse.julialang.org/t/plotting-an-ellipsoid-as-2d-surface-in-3d-given-the-principal-axes/60393>\
**Category:** Visualization\
**Tags:** makie\
**Created:** [May 1, 2021, 7:23pm UTC](https://discourse.julialang.org/t/plotting-an-ellipsoid-as-2d-surface-in-3d-given-the-principal-axes/60393 "2021-05-01T19:23:47Z")\
**Posts on this page:** 15\
**Page:** 1

<div class="post-metadata">

**Author:** ![Datseris](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/datseris/32/13406_2.png) [@Datseris](https://discourse.julialang.org/u/Datseris)\
**Post date:** [May 1, 2021, 7:23pm UTC](https://discourse.julialang.org/t/plotting-an-ellipsoid-as-2d-surface-in-3d-given-the-principal-axes/60393/1 "2021-05-01T19:23:47Z")

</div>

Hi there,

Let’s say I have some lengths `[5.0, 2.0, 1.0]` and I want to plot an ellipsoid whose axis have these lengths as a surface in 3D. Extra bonus if I can also provide two angles of rotation for azimuth / polar angles for the orientation of the ellipsoid.

How do I do this in Makie.jl?

---

<div class="post-metadata">

**Author:** ![jules](https://avatars.discourse-cdn.com/v4/letter/j/41988e/32.png) [@jules](https://discourse.julialang.org/u/jules)\
**Post date:** [May 1, 2021, 7:29pm UTC](https://discourse.julialang.org/t/plotting-an-ellipsoid-as-2d-surface-in-3d-given-the-principal-axes/60393/2 "2021-05-01T19:29:09Z")

</div>

Isn’t there maybe a sphere primitive in geometrybasics that you could transform to a mesh, which you then transform to an ellipse with a matrix multiplication?

---

<div class="post-metadata">

**Author:** ![Datseris](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/datseris/32/13406_2.png) [@Datseris](https://discourse.julialang.org/u/Datseris)\
**Post date:** [May 1, 2021, 7:42pm UTC](https://discourse.julialang.org/t/plotting-an-ellipsoid-as-2d-surface-in-3d-given-the-principal-axes/60393/3 "2021-05-01T19:42:24Z")

</div>

Would really appreciate some help, as GeometryBasics is a bit hard. I have:

```julia
using GLMakie, AbstractPlotting, StaticArrays
sphere = Sphere(Point3f0(0), 1)
spheremesh = AbstractPlotting.GeometryBasics.mesh(sphere)

fig = Figure(resolution = (800, 600))
ax3D = fig[1,1] = Axis3(fig)
mesh!(ax3D, spheremesh)

```

this works, but is pure black

 ![image](https://global.discourse-cdn.com/julialang/original/3X/5/9/5998a93c6591b2ce197c89fe605c86a5127f77be.png)

I’m trying to color the surface but

```julia
c = [RGBAf0(rand(3)...) for i in 1:length(spheremesh)]
mesh!(ax3D, spheremesh; color = c)

```

errors claiming that lengths do not match, which I’m not sure it makes sense.

Nevertheless, I really don’t know how to transform this `spheremesh` and then plot it either, because:

```julia
mat = rand(3,3)
newmesh = [mat*point for point in spheremesh]

```

errors

---

<div class="post-metadata">

**Author:** ![jules](https://avatars.discourse-cdn.com/v4/letter/j/41988e/32.png) [@jules](https://discourse.julialang.org/u/jules)\
**Post date:** [May 1, 2021, 7:57pm UTC](https://discourse.julialang.org/t/plotting-an-ellipsoid-as-2d-surface-in-3d-given-the-principal-axes/60393/4 "2021-05-01T19:57:49Z")

</div>

I think meshes are iterated as triangles, so it’s slightly more complicated than just multiplying points. And can’t you set color = :red or something? The length if you pass an array should probably be equal to the number of vertices, not faces.

---

<div class="post-metadata">

**Author:** ![lazarusA](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/lazarusa/32/6571_2.png) [@lazarusA](https://discourse.julialang.org/u/lazarusA)\
**Post date:** [May 1, 2021, 7:58pm UTC](https://discourse.julialang.org/t/plotting-an-ellipsoid-as-2d-surface-in-3d-given-the-principal-axes/60393/5 "2021-05-01T19:58:21Z")

</div>

A few days back I was discussing with [Andrew Bylard](https://app.slack.com/team/UENUXK2MS) about the same thing… but our problem was to properly rotate the ellipsoid…I (we) didn’t succeed, nevertheless here is the code.

```julia
using GLMakie, Rotations
fig = Figure(resolution = (600,600))
box_center = Vec(0.,0.,0.)
box_widths = Vec(10.,10.,10.)
box = Rect(box_center - box_widths/2, box_widths)
r = [2., 3., 5.]
p_center = zeros(3)
ax = Axis3(fig, aspect = :data)
mesh!(ax, box, color = (:dodgerblue, 0.5), transparency = true)
sphere = Sphere(Point(p_center...), 1)

meshplot = mesh!(ax, sphere, color = :red)

scale!(meshplot, r[1], r[2], r[3])
obj = ax.scene[end]

rotation = RotY(π/2)
q = UnitQuaternion(rotation)
qrot = Quaternionf0(q.w, q.x, q.y, q.z) # Quaternionf0(0.5, 0.5, 0.6, 0.5)
GLMakie.rotate!(obj, qrot) # 

fig[1,1] = ax
fig

```

 ![ellipsoid_in_abox](https://global.discourse-cdn.com/julialang/original/3X/3/8/38d29120e09388071013aaddc7f30272dabb6e07.png)

---

<div class="post-metadata">

**Author:** ![mschauer](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/mschauer/32/13946_2.png) [@mschauer](https://discourse.julialang.org/u/mschauer)\
**Post date:** [May 1, 2021, 8:06pm UTC](https://discourse.julialang.org/t/plotting-an-ellipsoid-as-2d-surface-in-3d-given-the-principal-axes/60393/6 "2021-05-01T20:06:45Z")

</div>

A version for “uncertainty balls”

```julia
using Distributions, StaticArrays, LinearAlgebra
using GLMakie

"""
    quaternion(m::SMatrix{3,3})

Compute the (rotation-) quarternion of a 3x3 rotation matrix. Useful to create
isodensity ellipses from spheres in GL visualizations.
"""
function quaternion(m)
    qw2 = 1 + m[1,1] + m[2,2] + m[3,3]
    if qw2 < 0
        qw2 = -qw2
    end

    qw = sqrt(qw2)/2
    qx = (m[3,2] - m[2,3])/(4qw)
    qy = (m[1,3] - m[3,1])/(4qw)
    qz = (m[2,1] - m[1,2])/(4qw)
    SVector{4}(qx,qy,qz,qw)
end

"""
    svd3(mcstates) -> mean, q, sv

Decompose variance into singular values `sv` and 
3d rotation quaternion `q`. 

Returns vectors of appropriate `GeometryTypes`.
"""
function svd3(vs)
    scal = Point3f0[]
    rot = Vec4f0[]
    for v in vs
        s = svd(v)
        push!(scal, sqrt.(s.S))
        push!(rot, quaternion(s.U))
    end
    rot, scal
end

qu = 0.95

xs = cos.(1:0.5:20)
ys = sin.(1:0.5:20)
zs = LinRange(0, 3, length(xs))
outer(x) = x*x'
rot, scal = svd3([0.005outer(randn(3,3) + 0.2I) for i in 1:length(xs)])

c = sqrt(quantile(Chisq(3), qu))

meshscatter(xs, ys, zs, color = zs,
    markersize = c*(scal),      
    rotations = rot,        
    markerspace=SceneSpace 
)

```

 ![uncertainty](https://global.discourse-cdn.com/julialang/original/3X/f/5/f52983aa3a2264b45762852554cc7713ba3a0eb4.jpeg)

---

<div class="post-metadata">

**Author:** ![Datseris](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/datseris/32/13406_2.png) [@Datseris](https://discourse.julialang.org/u/Datseris)\
**Post date:** [May 1, 2021, 8:12pm UTC](https://discourse.julialang.org/t/plotting-an-ellipsoid-as-2d-surface-in-3d-given-the-principal-axes/60393/7 "2021-05-01T20:12:44Z")

</div>

Thank you both, I’ll use your answers. I am not sure how I can take advantage of the answer of @mschauer , because I only need to plot 1 ellipsoid whose color _changes along the ellipsoid_. To be precise, I want to color it so that it is red at the top and green at the bottom, etc. (I have a map from coordinates to colors already)

---

<div class="post-metadata">

**Author:** ![jules](https://avatars.discourse-cdn.com/v4/letter/j/41988e/32.png) [@jules](https://discourse.julialang.org/u/jules)\
**Post date:** [May 1, 2021, 8:25pm UTC](https://discourse.julialang.org/t/plotting-an-ellipsoid-as-2d-surface-in-3d-given-the-principal-axes/60393/8 "2021-05-01T20:25:34Z")

</div>

I tried out something as well, although I always struggle with the GeometryBasics interface. Never know how I’m supposed to do things like transformations, accessing points, constructing meshes, etc.

Anyway:

```julia
import AbstractPlotting.GeometryBasics as GB

f = Figure()

sphere = Sphere(Point3f0(0), 1)
spheremesh = GB.mesh(sphere)

function transform_mesh(msh, mat4x4)
    pos_trans = Point3f0.(Ref(mat4x4) .* to_ndim.(Point4f0, spheremesh.position, 0))
    GB.Mesh(pos_trans, GB.faces(msh))
end

m = AbstractPlotting.rotationmatrix_y(pi/4) *
        AbstractPlotting.scalematrix(Vec3f0(1, 1, 2))

colors = [randn() for p in spheremesh.position]

ax = Axis3(f[1, 1], aspect = :data)
mesh!(transform_mesh(spheremesh, m), color = colors)

f

```

 ![grafik](https://global.discourse-cdn.com/julialang/original/3X/f/c/fccb2a9423ffbcdbd04de82d0ac1a3477eda5f95.jpeg)

---

<div class="post-metadata">

**Author:** ![lazarusA](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/lazarusa/32/6571_2.png) [@lazarusA](https://discourse.julialang.org/u/lazarusA)\
**Post date:** [May 1, 2021, 8:28pm UTC](https://discourse.julialang.org/t/plotting-an-ellipsoid-as-2d-surface-in-3d-given-the-principal-axes/60393/9 "2021-05-01T20:28:39Z")

</div>

something like this: (this code you can find it the [gallery beautiful makie,](https://lazarusa.github.io/Webpage/codeJuliaMakie.html)

```julia
using AbstractPlotting: get_dim, surface_normals
using GLMakie, Rotations, GeometryBasics

function getMesh(x,y,z)
    positions = vec(map(CartesianIndices(z)) do i
    GeometryBasics.Point{3, Float32}(
        get_dim(x, i, 1, size(z)),
        get_dim(y, i, 2, size(z)),
        z[i])
    end)
    faces = decompose(GLTriangleFace, Rect2D(0f0, 0f0, 1f0, 1f0), size(z))
    normals = surface_normals(x, y, z)
    vertices = GeometryBasics.meta(positions; normals=normals) 
    meshObj = GeometryBasics.Mesh(vertices, faces)
    meshObj 
end

Θ = LinRange(0, 2π, 100) # 50
Φ = LinRange(0, π, 100)
r = 0.5
x = [r * cos(θ) * sin(ϕ) for θ in Θ, ϕ in Φ]
y = [r * sin(θ) * sin(ϕ) for θ in Θ, ϕ in Φ]
z = [r * cos(ϕ) for θ in Θ, ϕ in Φ]

meshSphere = getMesh(x,y, z)

fig = Figure(resolution = (600,600))

r = [0.5, 0.6, 0.95]

ax = Axis3(fig, aspect = :data)

meshplot = mesh!(ax, meshSphere, color= [v[3] for v in coordinates(meshSphere)], # color = z, # v[3]
    colormap = (:green,:red), shading = true)
scale!(meshplot, r[1], r[2], r[3])

fig[1,1] = ax
fig

```

 ![ellipsoid_green_red](https://global.discourse-cdn.com/julialang/original/3X/0/3/03db93d572e399d0a878b7714ac0fc468c3b0f94.png)

I suppose the right way to do the transformations, rotations should be done as @mschauer just mentioned above.

---

<div class="post-metadata">

**Author:** ![lazarusA](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/lazarusa/32/6571_2.png) [@lazarusA](https://discourse.julialang.org/u/lazarusA)\
**Post date:** [May 1, 2021, 8:45pm UTC](https://discourse.julialang.org/t/plotting-an-ellipsoid-as-2d-surface-in-3d-given-the-principal-axes/60393/10 "2021-05-01T20:45:40Z")

</div>

this solution is nice (@jules):  
for your case @Datseris, just change

`colors = [p[3] for p in spheremesh.position]`  
and add  
`colormap = (:green, :red)` in mesh!(…). Although the surface looks too opaque. Probably something to do with normals.

---

<div class="post-metadata">

**Author:** ![rafael.guerra](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/rafael.guerra/32/216610_2.png) [@rafael.guerra](https://discourse.julialang.org/u/rafael.guerra)\
**Post date:** [May 1, 2021, 11:00pm UTC](https://discourse.julialang.org/t/plotting-an-ellipsoid-as-2d-surface-in-3d-given-the-principal-axes/60393/11 "2021-05-01T23:00:27Z")

</div>

Using Makie and [Rotations.jl](https://github.com/JuliaGeometry/Rotations.jl):

```julia
using Makie, Rotations

M(u,v) = [a/2*cos(u)*sin(v), b/2*sin(u)*sin(v), c/2*cos(v)] # ellipsoid

RM(u,v) = RotXYZ(α,β,γ) * M(u,v) .+ C # rotated ellipsoid

C = [1,1,2] # center of ellipsoid
α, β, γ = π/4, 0, π/3 # Euler angles
a, b, c = 5.0, 2.0, 1.0 # ellipsoid principal axes
u, v = range(0, 2π, length=72), range(0, π, length=72)
xs, ys, zs = [[p[i] for p in RM.(u, v')] for i in 1:3]
Makie.surface(xs,ys,zs, lightposition = Vec3f0(0,-10,0))

```

 ![Rotated_ellipsoid_Makie](https://global.discourse-cdn.com/julialang/original/3X/5/7/57b76f53e99234fb75f23c400b6a69322c5b0c5f.png)

---

<div class="post-metadata">

**Author:** ![Datseris](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/datseris/32/13406_2.png) [@Datseris](https://discourse.julialang.org/u/Datseris)\
**Post date:** [May 2, 2021, 1:03pm UTC](https://discourse.julialang.org/t/plotting-an-ellipsoid-as-2d-surface-in-3d-given-the-principal-axes/60393/12 "2021-05-02T13:03:55Z")

</div>

Thank you very much @jules , in the end your code was the one that was most useful to me and suitable to my application. With it was able to make the following educative illustration:

![volume_growth_Lorenz63](https://global.discourse-cdn.com/julialang/original/3X/d/a/dadc3531ac37589ccbd8f7b0233ad2eb72cda034.gif)

(only thing left for me to do is find out how the purple line in left plot can be plotted _always_ on top of the grey lines)

This discussion made me realize that this is not something a user could find on their own. Should we have some kind of documentation page about this online? If yes, where? Do we have some kind of “official examples library” in the documentation, like PyPlot does?

---

<div class="post-metadata">

**Author:** ![jules](https://avatars.discourse-cdn.com/v4/letter/j/41988e/32.png) [@jules](https://discourse.julialang.org/u/jules)\
**Post date:** [May 2, 2021, 1:59pm UTC](https://discourse.julialang.org/t/plotting-an-ellipsoid-as-2d-surface-in-3d-given-the-principal-axes/60393/13 "2021-05-02T13:59:26Z")

</div>

Try transparency = true or overdraw = true for the purple line?

---

<div class="post-metadata">

**Author:** ![jules](https://avatars.discourse-cdn.com/v4/letter/j/41988e/32.png) [@jules](https://discourse.julialang.org/u/jules)\
**Post date:** [May 2, 2021, 3:15pm UTC](https://discourse.julialang.org/t/plotting-an-ellipsoid-as-2d-surface-in-3d-given-the-principal-axes/60393/14 "2021-05-02T15:15:42Z")

</div>

also using `tightlimits!(ax, Bottom())` with the barplots would probably look nicer. And you can try `transparency = true` on the lorenz attractor lines as well, they lose their white jagged edges that way

---

<div class="post-metadata">

**Author:** ![Datseris](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/datseris/32/13406_2.png) [@Datseris](https://discourse.julialang.org/u/Datseris)\
**Post date:** [May 2, 2021, 3:28pm UTC](https://discourse.julialang.org/t/plotting-an-ellipsoid-as-2d-surface-in-3d-given-the-principal-axes/60393/15 "2021-05-02T15:28:17Z")

</div>

Thanks, looks much crisper now:

![volume_growth_Lorenz63](https://global.discourse-cdn.com/julialang/original/3X/4/7/474a4e618071f609c69813b3f0ed5ca88e2c2a5d.gif)
