# Surface plot using plots.jl

I have two very basic questions about surface plots.

One is that when I have a dataset `S = [(x1, y1, z1), (x2, y2, z2), ..., (xn, yn, zn)]`, how can I create a surface plot for `z`? Here, `(xi, yi)≠(xj, yj)` for `i≠j` are guaranteed. For example, `plot(X, Y, Z, st=:surface)` doesn’t work for `X = [x1, x2, ..., xn]`, `Y = [y1, y2, ..., yn]`, and `Z = [z1, z2, ..., zn]`.

The other question is, can I obtain interpolated data points, meaning data points that are not present in the original dataset, from the surface plot function?

For a surface, one would typically have a grid of domain points and a `z` value defined for each.
See for example: 3D surface with axis guides · Plots

The Interpolations.jl package may be useful: General usage · Interpolations.jl , possibly using “gridded interpolation”(Interpolation algorithms · Interpolations.jl)

You also might be interested in GitHub - mdmaas/PColorPlot.jl: Adding interpolated heatmaps to Plots.jl via a pcolor recipe. That should be straightforward to apply to surfaces also.

So, do we always need a grid? I mean, for a region that cannot be represented by a tensor product (or direct product) of `X` and `Y`, is it not possible to create a surface plot?

This looks good. Thank you!

``````using Plots
using Interpolations

#original data
xs = 0.1:0.05:2.0
ys = 0.2:0.1:2.0
X = [x for x = xs for _ = ys]
Y = [y for _ = xs for y = ys]
Z = [1/x + y*x^2 for x in xs for y in ys]

#interpolations
ZIp = [1/x + y*x^2 for x in xs, y in ys] #make a length(xs)×length(ys) matrix
interp_linear = linear_interpolation((xs, ys), ZIp) # linear interpolation
interp_cubic = cubic_spline_interpolation((xs, ys), ZIp) # cubic spline interpolation
#define a interpolation function
ZIp1(x,y) = interp_linear(x,y)
ZIp2(x,y) = interp_cubic(x,y)

#interpolated region
xsIp = 0.1:0.01:2.0
ysIp = 0.2:0.05:2.0
XIp = [x for x = xsIp for _ = ysIp]
YIp = [y for _ = xsIp for y = ysIp]

plot(XIp,YIp,ZIp1.(XIp,YIp),st=:scatter,markercolor=:blue,markerstrokecolor=:blue,markerstrokewidth=0,markersize=3,label="linear interpolation")
plot!(X,Y,Z,st=:scatter,markercolor=:pink,markerstrokecolor=:pink,markerstrokewidth=0,markersize=2,label="original data")
fig1 = plot!(xlabel="x",ylabel="y",zlabel="z",foreground_color_legend=nothing)
plot(XIp,YIp,ZIp2.(XIp,YIp),st=:scatter,markercolor=:blue,markerstrokecolor=:blue,markerstrokewidth=0,markersize=3,label="cubic spline interpolation")
plot!(X,Y,Z,st=:scatter,markercolor=:pink,markerstrokecolor=:pink,markerstrokewidth=0,markersize=2,label="original data")
fig2 = plot!(xlabel="x",ylabel="y",zlabel="z",foreground_color_legend=nothing)
plot(fig1,fig2,layout=(1,2))
``````

1 Like

Thanks! This also looks promising, but how can I create a function (or array) like `ZIp1(x, y)` as I mentioned in the reply to @jd-foster? I need the underlying numerical data itself, not an image.

This uses GitHub - kbarbary/Dierckx.jl: Julia package for 1-d and 2-d splines for the interpolation

It went well. Thank you!

``````using Plots
using Dierckx

#original data
xs = 0.1:0.05:2.0
ys = 0.2:0.1:2.0
X = [x for x = xs for _ = ys]
Y = [y for _ = xs for y = ys]
Z = [1/x + y*x^2 for x in xs for y in ys]

#interpolations
ZIp = [1/x + y*x^2 for x in xs, y in ys] #make a length(xs)×length(ys) matrix
interp = Spline2D(xs, ys, ZIp) # interpolation
#define a interpolation function
ZIp1(x,y) = evaluate(interp,x,y)

#interpolated region
xsIp = 0.1:0.01:2.0
ysIp = 0.2:0.05:2.0
XIp = [x for x = xsIp for _ = ysIp]
YIp = [y for _ = xsIp for y = ysIp]

plot(XIp,YIp,ZIp1.(XIp,YIp),st=:scatter,markercolor=:blue,markerstrokecolor=:blue,markerstrokewidth=0,markersize=3,label="linear interpolation")
plot!(X,Y,Z,st=:scatter,markercolor=:pink,markerstrokecolor=:pink,markerstrokewidth=0,markersize=2,label="original data")
plot!(xlabel="x",ylabel="y",zlabel="z",foreground_color_legend=nothing)
``````

2 Likes

You might find ApproxFun interesting too: Home · ApproxFun.jl