Smoothing Discontinuities in 3D Plots

Hi there, I have a fairly simple problem. I am trying to do a 3D plot of a function that has discontinuities, but I can’t figure out how to get the boundary of the discontinuity to look smooth instead of spikey.

Here is an example code, (I am sure there must be a more elegant way to write this).

using Plots
plotlyjs()

function f(x,y)
    a = sin.(x).*y
    if a.<=1
        asin.(a)
    else
        NaN
    end
end

f2(x,y)=(x,y,f(x,y))

x=0:.01:pi/2
y=0:.01:2

xm, ym, zm = [[pt[i] for pt in f2.(x,y')] for i in 1:3]

surface(xm,ym,zm)

I get a jagged edge at the discontinuity.
juliasurface

In comparison, when I make the following plot in Mathematica I get a smooth edge.

Plot3D[ArcSin[Sin[a]*b], {a, 0, Pi/2}, {b, 0, 2}]

mathematicasurface

I have tried increasing the sampling for the values of x and y but that still results in a spikey edge. I am guessing there is an interpolation step that the mathematica plotter is doing that I am missing with my script in Julia, but I am not sure how to implement it.

1 Like

I would say that Mathematica is very clever, doing what you want instead of what you ask for! :wink: . When I look at the individual points in a scatter plot…

scatter3d(vec(xm),vec(ym),vec(zm),ms=0.5)

orig

it appears that Plots is plotting what is actually there. The best I can think of is to “pin” your function output values rather than set them to NaNs. So, by replacing NaN with π/2 in your function f, I get

pinned

1 Like

Another way is to write y function of x and z.
PS: edited the order of the variables to preserve the Cartesian axes right-handedness.

using Plots; plotlyjs()
g(z, x) = sin(z) ./ sin(x)
x = 1e-3:.01:π/2
z = 0:.01:π/2
Plots.surface(z, x, g, xlabel="z",ylabel="x",zlabel="y"; zlims=(0,2),
    color=:reds,  colorbar=false)

1 Like

Another way is to use a parametric surface.

S(x,z) = (x, sin(z)/sin(x), z)
x = 1e-3:.02:π/2
z = 0:.02:π/2
xs, ys, zs = [[p[i] for p in S.(x, z')] for i in 1:3];
using Plots; plotlyjs()
Plots.surface(xs,ys,zs, xlabel="x",ylabel="y",zlabel="z"; ylims=(0,2),colorbar=false)


.
.
In Makie this works but the y-axis cannot be properly tamed with ylims:

using Makie
fig = Makie.surface(xs,ys,zs, backgroundcolor=:black)
Makie.ylims!(fig.axis.scene, 0, 2.0)  # ylims not really working as expected

4 Likes