# Plotting scatter points together with surface plot

Hello!

I have a function that i want to surface plot and a bunch of points that i want to add to that plot. Unfortunately this doesn’t look good the way i do it.

The problem appears to be that i first do the surface plot and afterwards i plot the scatter points on top of it.
Is there a more elegant way/ a different package i should use to receive a better looking plot (e.g. where the points are not just thrown on top of the surface plot but more “embedded”)?

In the following i give a working example of code - and a resulting plot.

``````using Plots
let
A=rand(Uniform(-3,3),2,10)
f(x,y)=-((1+cos(12sqrt(x^2+y^2)))/(0.5*(x^2+y^2)+2))

t1 = range(-5.12, 5.12, length=200)
t2 = range(-5.12,5.12, length=200)

# Creating Surface-Plot
surface_plot = surface(t1, t2, f, legend=false)

#Add scatter plots
scatter_x=A[1,:]
scatter_y=A[2,:]
scatter_z= [f for (t1, t2) in zip(scatter_x, scatter_y)]
scatter_points=scatter!(scatter_x, scatter_y, scatter_z, marker=:circle, markersize=5)

display(surface_plot)
end
``````

yields:

In Plots.jl 's, it should look better using `pythonplot()` or `plotlyjs()` backends, and cerise sur le gâteau, you will get interactive windows.

2 Likes

And welcome.

Probably this code here:

may be replaced by:

``````scatter_z = f.(scatter_x, scatter_y)
``````

This Julia feature is known as dot broadcasting - see the reference blog post here.

Both of your replies work and help me, thanks!

Is there a way to have the markershape as a ball/sphere instead of a circle?
I couldn’t find that in the documentation, my intuitive approach would be to make a new function that produces a ball/sphere and use surface to draw that ball/sphere.

This is possible in Makie.jl - see for instance here.

Using Plots.jl, I don’t know, except plotting N spheres (example here).

Using Plots.jl 's `plotlyjs()` backend, the sphere function in code linked above and:

``````surface(t1, t2, f, legend=false, lims=(-pi, pi), size=(1000,1000))
surface!([sphere(0.1, ri) for ri in zip(scatter_x, scatter_y, scatter_z)], c=:red)
``````

we can produce:

Thank you for your help!
i tried it with Makie.jl now, this appears to work but somehow my scatterpoints are stretched.

My code:

``````using Makie
using Distributions
using GLMakie

let
fig = Figure(fontsize = 22)
ax3d = Axis3(fig[1, 1];aspect = (1, 1, 1))

A=rand(Uniform(-3,3),2,10)
f(x,y)=-((1+cos(12sqrt(x^2+y^2)))/(0.5*(x^2+y^2)+2))

t1 = range(-5.12, 5.12, length=200)
t2 = range(-5.12,5.12, length=200)

x=A[1,:]
y=A[2,:]
z= f.(x,y)

pltobj = surface!(ax3d,t1, t2, f)
meshscatter!(x, y, z,markersize=0.2)

display(fig)
end
``````

Set the aspect ratio to 1.

I did in line 7.

Not a regular user of Makie, but would try:
`meshscatter!(ax3d, ...)`

I tried, the result is the same.

It needs to be `aspect = :data` as shown here Axis3 | Makie

Thanks, but this results in a plot like this:

we need `scale_marker=false` for meshscatter…

But how far would the sphere mesh extend into the surrounding mesh then? The screen space sized marker is easier to understand in 2d I think.

Ultimately i want the markers to have different sizes.

One simple thing you could do now is to pick the markersize depending on the limits of the Axis3, as long as you don’t have nonlinear axis transformations that would work. So let’s say the z axis has a scaling factor of 2 vs x and y then you could do `markersize = Vec(ms, ms, 0.5ms)`. You could lift `ax.finallimits` to compute the scaling factor, and correct for the `aspect` too if that’s not 1, 1, 1.

I am not quite sure if i understand what you mean with that. How is `ms` defined?

I tried with the sphere approach, unfortunately i get the same issue as with makie:

If i adjust the zaxis with (zlims=(-1,1)) the markers are stretched again:

This is not an issue, this is the correct display for aspect ratio = 1. If you want the same approach for a different aspect ratio, we need to draw ellipsoids that will look like spheres if the principal axes are inversely proportional to the aspect ratio.