[ANN] UnicodePlots.jl v2.8.0 - 3D plots

Announcing UnicodePlots v2.8.0, which brings up 3D plots.

Examples:

surfaceplot


isosurface

Useful for in situ post-processing of simulations, or as a development helper for 3D codes.

In case you missed out, contourplot was also recently added.

127 Likes

This is crazy and amazing! :slight_smile:

17 Likes

Very cool! Any chance there might be 3D scatter plots? We would have some applications for that, though they might be difficult for human consumption in general.

3 Likes

Yes, I’ve modified scatterplot and lineplot to take z values, so you can use something like:

scatterplot(
  x, y, z;
  projection = :orthographic  # or :perspective, or a full `MVP` matrix.
)

Internally, surfaceplot uses points! unless kw lines = true is passed (which is slower and more dense).

7 Likes

Inconceivable!

8 Likes

A dream come true!
Now we need interactivity :innocent:

1 Like

Amazing.

Is there any support for animations?

There is Makie.jl for that, and for animations :slight_smile: I don’t think this should be the target of UnicodePlots (which is intended to be a lightweight swiss army knife with very few dependencies, that just works right out of the box).

EDIT: after discussion with @AlexisRenchon on slack, we can maybe make animations work from within Plots.jl, since UnicodePlots is a supported backend.

9 Likes

This is fantastic! I loved this package before, but now there is simply no Julia for me without UnicodePlots. :muscle:t2::blush::pray:t2:

1 Like

How cool - I definitely want to try to find a way to work it into my current work/packages :slight_smile:

1 Like
using Plots; unicodeplots()  # using `Plots@master`, with linux ;), maybe works on macOS

main() = begin
  anim = @animate for i = -180:10:180
    surface(
      -8:.5:8, -8:.5:8, (x, y) -> 15sinc(√(x^2 + y^2) / π),
      colormap=:jet, camera=(i, 30)
    )
  end
  gif(anim, "anim_fps5.gif", fps=5)
end

main()

anim_fps5

using Plots; unicodeplots()

main() = begin
  Plots.UnicodePlots.default_size!(width=120)
  anim = @animate for i ∈ -180:10:180
    surface(
      -8:8, -8:8, (x, y) -> 15sinc(√(x^2 + y^2) / π),
      camera=(i, 30),
      extra_kwargs = Dict(
        :subplot => (zoom=1.25,),
        :series =>(colormap=:jet, lines=true)
      )
    )
  end
  gif(anim, "anim_lines_fps5.gif", fps=5)
end

main()

anim_lines_fps5

39 Likes

and it may be the only backend that supports multi-threading animation (making independent frames in parallel) because all other backends are stateful as hell

7 Likes

I just wanted to report back here that I managed to get relatively good “animation” just by clearing the REPL before plotting (Thanks to @Tamas_Papp here). This allows for live plotting (i.e. closer to using observables like in Makie).

MWE:

using UnicodePlots
import REPL
terminal = REPL.Terminals.TTYTerminal("", stdin, stdout, stderr)

xs = range(0, 7, length=40)
fps = 30
for t in 0:1/fps:100
  ys = sin.(xs .- t)
  REPL.Terminals.clear(terminal)
  println(lineplot(xs, ys, xlim = (0, 7), ylim = (-1, 1)))
  sleep(1/fps)
end

animation

It’s a bit jumpy, but saves the day on diagnosing a headless server without XForwarding…

9 Likes

It helps if you hide the cursor :slight_smile:

https://github.com/cesaraustralia/DynamicGrids.jl/blob/master/src/outputs/repl.jl#L55-L71

DynamicGrids.jl has repl simulations and they’re pretty smooth using these tricks

7 Likes

Right you are:
animation

Still some flickering…

1 Like

Thanks for sharing this !

Still some flickering…

You can move the show logic before clearing the screen:

using UnicodePlots
import REPL

_cursor_hide(io::IO) = print(io, "\x1b[?25l")
_cursor_show(io::IO) = print(io, "\x1b[?25h")

main() = begin
  terminal = REPL.Terminals.TTYTerminal("", stdin, stdout, stderr)

  fps = 30
  xs = range(0, 7, length=40)
  _cursor_hide(stdout)
  io = IOContext(PipeBuffer(), :color=>true)
  for t ∈ 0:(1 / fps):100
    ys = sin.(xs .- t)
    show(io, lineplot(xs, ys, xlim=(0, 7), ylim=(-1, 1)))
    out = read(io, String)
    REPL.Terminals.clear(terminal)
    println(out)
    sleep(1 / fps)
  end
  _cursor_show(stdout)
  return
end

main()
3 Likes

animation
Better…

6 Likes

Ooooh… when I were lad I used the CERN HBOOK package to plot histograms on line printers using music ruled paper.
I guess I can still do the same - if I Can find a line printer!
Seriously - the 3D stuff is coooollll

1 Like

Stupid (in a good way) that unicode plotting in the REPL is almost at parity with other plotting libraries in Julia haha

3 Likes