How to produce a waterfall plot in Julia?

I want to produce a waterfall plot, sort of like this:

in Julia. The above plot was created in MATLAB with the command:

waterfall(xi, tdata, abs(u1data'))

where xi and tdata was 1d arrays and u1data is a 2d array containing u1 at each xi and t value. Is there a corresponding way of creating such a plot in Julia?

If not, how does one produce a surface plot with just matrices (no function for finding z from x and y)? I’ve tried this:

using PlotlyJS;
PlotlyJS.plot(surface(z=abs.(u1data), x=xi, y=tdata));

and absolutely no plot is generated (nor is an error message or warning message). I’ve issued this command both in the Julia REPL and in Jupyter Lab. I have WebIO installed using the command:

sudo python3 -m pip3 install webio_jupyter_extension

(where Jupyter Lab itself is installed system-wide also).

I’ve been able to answer the surface plot question of mine. I just converted xi and tdata to 2d arrays with each element corresponding to the value of the variable in question at the particular point in the grid, and used plot_surface from PyPlot. Specifically, using the code:

using PyPlot;
pygui(true);
PyPlot.figure(1);
PyPlot.xlabel(L"$\xi$")
PyPlot.ylabel(L"$t$")
PyPlot.zlabel(L"$|u|$")
PyPlot.plot_surface(ones(length(tdata))' .* xi, tdata' .* ones(length(xi)), abs.(u1datar))

PyPlot.figure(2);
PyPlot.xlabel(L"$\xi$")
PyPlot.ylabel(L"$t$")
PyPlot.zlabel(L"$|u|$")
PyPlot.plot_surface(ones(length(tdata))' .* xi, tdata' .* ones(length(xi)), abs.(u2datar))

pygui(true) makes the plot get launched as an interactive GUI (as opposed to a static image in the browser, which is the default); the xlabel, ylabel and zlabel commands are just adding in labels.

1 Like

Here’s something I came up with using Makie:

using CairoMakie

xi = -15:0.1:15
t = 0:30
u1data = [exp(-(x-0.5*(t-15))^2) for x in xi, t in t]

fig = Figure()
ax = Axis3(fig[1,1];
    azimuth=-1.46, elevation=1,
    xticks=-15:5:15, zticks=0:2,
    limits=(nothing, nothing, (0,2)),
    xgridvisible=false, ygridvisible=false, zgridvisible=false,
    (Symbol.([:x, :y, :z], "spinecolor_", [2 3]) .=> :transparent)...,
    xlabel=L"\xi", ylabel=L"t", zlabel=L"|u|")

for (tval, z) in Iterators.reverse(zip(t, eachcol(u1data)))
    tvals = fill(tval, length(xi))
    band!(Point3.(xi, tvals, 0), Point3.(xi, tvals, z), color=:white)
    lines!(xi, tvals, z, color=:black)
end

fig

(Use GLMakie or WGLMakie instead of CairoMakie for interactivity.)

With Makie you can do surface(xi, t, u1data) where xi and t are vectors and u1data is a matrix.

6 Likes

I would like to just say thank you for the obvious effort you put into your answer, it is very much appreciated. My tdata is not equally spaced and it has over 49,000 elements, so I had to adapt your code to my situation. Namely, I had to write code to cherry pick elements of tdata that were closest to the integer values of t. With this change, however, I find your code with WGLMackie did produce the required plot window.

2 Likes

I do have a follow up query though. How do you save this figure to a file? I’ve looked up the documentation for Makie but its save() function only seems to work when you feed it a scene object and there’s no scene object created in this code.

That must have been old docs, you can save Figure, Scene or FigureAxisPlot with save.

Thanks, I had just found Exporting a Figure with physical dimensions when you wrote that reply and it also mentions the option of saving a Figure object.