Announcing UnicodePlots
v2.8.0, which brings up 3D plots.
Examples:
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.
Announcing UnicodePlots
v2.8.0, which brings up 3D plots.
Examples:
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.
This is crazy and amazing!
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.
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).
Inconceivable!
A dream come true!
Now we need interactivity
Amazing.
Is there any support for animations?
There is Makie.jl for that, and for animations 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.
This is fantastic! I loved this package before, but now there is simply no Julia for me without UnicodePlots.
How cool - I definitely want to try to find a way to work it into my current work/packages
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()
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()
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
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
It’s a bit jumpy, but saves the day on diagnosing a headless server without XForwarding…
It helps if you hide the cursor
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
Right you are:
Still some flickering…
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()
Better…
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
Stupid (in a good way) that unicode plotting in the REPL is almost at parity with other plotting libraries in Julia haha