UnicodePlots: adjust layout width per column (#3825)

This commit is contained in:
t-bltg 2021-09-17 21:42:50 +02:00 committed by GitHub
parent 85739932f0
commit e2539a3d19
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
3 changed files with 134 additions and 136 deletions

View File

@ -911,16 +911,21 @@ const _gaston_scale = [:identity, :ln, :log2, :log10]
const _unicodeplots_attr = merge_with_base_supported([
:annotations,
:bins,
:guide,
# :grid,
:label,
:layout,
:legend,
:seriescolor,
:seriesalpha,
:lims,
:linealpha,
:linecolor,
:linestyle,
:markershape,
:bins,
:seriesalpha,
:seriescolor,
:scale,
:title,
:guide,
:lims,
])
const _unicodeplots_seriestype = [
:path,

View File

@ -1,12 +1,10 @@
# https://github.com/JuliaPlots/UnicodePlots.jl
# don't warn on unsupported... there's just too many warnings!!
warn_on_unsupported_args(::UnicodePlotsBackend, plotattributes::KW) = nothing
warn_on_unsupported_args(::UnicodePlotsBackend, plotattributes) = nothing
# --------------------------------------------------------------------------------------
_canvas_map() = (
# ------------------------------------------------------------------------------------------
const _canvas_map = (
ascii = UnicodePlots.AsciiCanvas,
block = UnicodePlots.BlockCanvas,
braille = UnicodePlots.BrailleCanvas,
@ -16,22 +14,26 @@ _canvas_map() = (
lookup = UnicodePlots.LookupCanvas,
)
# do all the magic here... build it all at once, since we need to know about all the series at the very beginning
# do all the magic here... build it all at once,
# since we need to know about all the series at the very beginning
function unicodeplots_rebuild(plt::Plot{UnicodePlotsBackend})
plt.o = UnicodePlots.Plot[]
canvas_map = _canvas_map()
for sp in plt.subplots
xaxis = sp[:xaxis]
yaxis = sp[:yaxis]
xlim = collect(axis_limits(sp, :x))
ylim = collect(axis_limits(sp, :y))
# we set x/y to have a single point, since we need to create the plot with some data.
# since this point is at the bottom left corner of the plot, it shouldn't actually be shown
# we set x/y to have a single point,
# since we need to create the plot with some data.
# since this point is at the bottom left corner of the plot,
# it shouldn't actually be shown
x = Float64[xlim[1]]
y = Float64[ylim[1]]
# create a plot window with xlim/ylim set, but the X/Y vectors are outside the bounds
# create a plot window with xlim/ylim set,
# but the X/Y vectors are outside the bounds
canvas_type = if (ct = _canvas_type[]) == :auto
isijulia() ? :ascii : :braille
else
@ -40,16 +42,16 @@ function unicodeplots_rebuild(plt::Plot{UnicodePlotsBackend})
kw = (
title = sp[:title],
xlim = xlim,
ylim = ylim,
border = isijulia() ? :ascii : :solid,
xlabel = xaxis[:guide],
ylabel = yaxis[:guide],
xscale = xaxis[:scale],
yscale = yaxis[:scale],
border = isijulia() ? :ascii : :solid,
xlim = xlim,
ylim = ylim,
)
o = UnicodePlots.Plot(x, y, canvas_map[canvas_type]; kw...)
o = UnicodePlots.Plot(x, y, _canvas_map[canvas_type]; kw...)
for series in series_list(sp)
o = addUnicodeSeries!(sp, o, kw, series, sp[:legend] != :none)
end
@ -58,7 +60,8 @@ function unicodeplots_rebuild(plt::Plot{UnicodePlotsBackend})
x, y, val = locate_annotation(sp, ann...)
o = UnicodePlots.annotate!(
o, x, y, val.str;
color = up_color(val.font.color), halign = val.font.halign, valign = val.font.valign
color = up_color(val.font.color),
halign = val.font.halign, valign = val.font.valign
)
end
@ -66,17 +69,10 @@ function unicodeplots_rebuild(plt::Plot{UnicodePlotsBackend})
end
end
function up_color(col)
if typeof(col) <: UnicodePlots.UserColorType
color = col
elseif typeof(col) <: RGBA
col = convert(ARGB32, col)
color = map(Int, (red(col).i, green(col).i, blue(col).i))
else
color = :auto
end
color
end
up_color(col::UnicodePlots.UserColorType) = col
up_color(col::RGBA) =
(c = convert(ARGB32, col); map(Int, (red(c).i, green(c).i, blue(c).i)))
up_color(col) = :auto
# add a single series
function addUnicodeSeries!(
@ -104,9 +100,7 @@ function addUnicodeSeries!(
cmap = [(red(c), green(c), blue(c)) for c in get(get_colorgradient(series), rng)]
return UnicodePlots.heatmap(
series[:z].surf;
zlabel = sp[:colorbar_title],
colormap = cmap,
kw...
zlabel = sp[:colorbar_title], colormap = cmap, kw...
)
elseif st == :spy
return UnicodePlots.spy(series[:z].surf; kw...)
@ -139,9 +133,10 @@ function addUnicodeSeries!(
return up
end
# -------------------------------
# ------------------------------------------------------------------------------------------
# since this is such a hack, it's only callable using `png`... should error during normal `show`
# since this is such a hack, it's only callable using `png`...
# should error during normal `show`
function png(plt::Plot{UnicodePlotsBackend}, fn::AbstractString)
fn = addExtension(fn, "png")
@ -149,17 +144,10 @@ function png(plt::Plot{UnicodePlotsBackend}, fn::AbstractString)
# make some whitespace and show the plot
println("\n\n\n\n\n\n")
gui(plt)
# BEGIN HACK
# wait while the plot gets drawn
sleep(0.5)
# use osx screen capture when my terminal is maximized and cursor starts at the bottom (I know, right?)
# TODO: compute size of plot to adjust these numbers (or maybe implement something good??)
# use osx screen capture when my terminal is maximized
# and cursor starts at the bottom (I know, right?)
run(`screencapture -R50,600,700,420 $fn`)
# END HACK (phew)
return
elseif Sys.islinux()
run(`clear`)
@ -169,12 +157,14 @@ function png(plt::Plot{UnicodePlotsBackend}, fn::AbstractString)
end
error(
"Can only savepng on MacOS or Linux with UnicodePlots (though even then I wouldn't do it)",
"Can only savepng on MacOS or Linux with UnicodePlots " *
"(though even then I wouldn't do it)"
)
end
# -------------------------------
Base.show(plt::Plot{UnicodePlotsBackend}) = _show(stdout, MIME("text/plain"), plt)
# ------------------------------------------------------------------------------------------
Base.show(plt::Plot{UnicodePlotsBackend}) = show(stdout, plt)
Base.show(io::IO, plt::Plot{UnicodePlotsBackend}) = _show(io, MIME("text/plain"), plt)
function _show(io::IO, ::MIME"text/plain", plt::Plot{UnicodePlotsBackend})
unicodeplots_rebuild(plt)
@ -182,9 +172,11 @@ function _show(io::IO, ::MIME"text/plain", plt::Plot{UnicodePlotsBackend})
lines_colored = Array{Union{Nothing,Vector{String}}}(undef, nr, nc)
lines_uncolored = copy(lines_colored)
l_max = zeros(Int, nr)
w_max = zeros(Int, nc)
buf = IOBuffer()
cbuf = IOContext(buf, :color => true)
sps = wmax = 0
re_col = r"\x1B\[[0-9;]*[a-zA-Z]"
sps = 0
for r in 1:nr
lmax = 0
for c in 1:nc
@ -198,27 +190,27 @@ function _show(io::IO, ::MIME"text/plain", plt::Plot{UnicodePlotsBackend})
sp = plt.o[sps += 1]
show(cbuf, sp)
colored = String(take!(buf))
uncolored = replace(colored, r"\x1B\[[0-9;]*[a-zA-Z]" => "")
uncolored = replace(colored, re_col => "")
lines_colored[r, c] = lc = split(colored, "\n")
lines_uncolored[r, c] = lu = split(uncolored, "\n")
lmax = max(length(lc), lmax)
wmax = max(maximum(length.(lu)), wmax)
w_max[c] = max(maximum(length.(lu)), w_max[c])
end
end
end
l_max[r] = lmax
end
empty = ' '^wmax
empty = String[' '^w for w w_max]
for r in 1:nr
for n in 1:l_max[r]
for c in 1:nc
pre = c == 1 ? '\0' : ' '
lc = lines_colored[r, c]
if lc === nothing || length(lc) < n
print(io, pre, empty)
print(io, pre, empty[c])
else
lu = lines_uncolored[r, c]
print(io, pre, lc[n], ' '^(wmax - length(lu[n])))
print(io, pre, lc[n], ' '^(w_max[c] - length(lu[n])))
end
end
println(io)

View File

@ -1,18 +1,20 @@
using Plots: guidefont, series_annotations, PLOTS_SEED
import ImageMagick
using VisualRegressionTests
using Plots
using Random
using StableRNGs
using Test
using TestImages
using FileIO
using Gtk
using LibGit2
import GeometryBasics
using Dates
using RecipesBase
using StableRNGs
using TestImages
using LibGit2
using Random
using FileIO
using Plots
using Dates
using JSON
using Test
using Gtk
import GeometryBasics
import ImageMagick
@testset "Infrastructure" begin
@test_nowarn JSON.Parser.parse(
@ -33,7 +35,7 @@ end
end
Plots.plotly_local_file_path[] = nothing
Plots.use_local_dependencies[] = temp
end # testset
end
include("test_defaults.jl")
include("test_pipeline.jl")
@ -55,7 +57,6 @@ function reference_file(backend, i, version)
refdir = reference_dir("Plots", string(backend))
fn = "ref$i.png"
versions = sort(VersionNumber.(readdir(refdir)), rev = true)
reffn = joinpath(refdir, string(version), fn)
for v in versions
tmpfn = joinpath(refdir, string(v), fn)
@ -64,7 +65,6 @@ function reference_file(backend, i, version)
break
end
end
return reffn
end
@ -79,9 +79,10 @@ if !isdir(reference_dir())
end
include("imgcomp.jl")
# don't actually show the plots
Random.seed!(PLOTS_SEED)
default(show = false, reuse = true)
default(show = false, reuse = true) # don't actually show the plots
is_ci() = get(ENV, "CI", "false") == "true"
const PLOTS_IMG_TOL = parse(Float64, get(ENV, "PLOTS_IMG_TOL", is_ci() ? "1e-4" : "1e-5"))
@ -106,68 +107,8 @@ const PLOTS_IMG_TOL = parse(Float64, get(ENV, "PLOTS_IMG_TOL", is_ci() ? "1e-4"
# image_comparison_facts(:pgfplotsx, tol=PLOTS_IMG_TOL, skip = Plots._backend_skips[:pgfplotsx])
# end
# 10 Histogram2D
##
@testset "Backends" begin
@testset "GR" begin
ENV["PLOTS_TEST"] = "true"
ENV["GKSwstype"] = "100"
@test gr() == Plots.GRBackend()
@test backend() == Plots.GRBackend()
@static if haskey(ENV, "APPVEYOR")
@info "Skipping GR image comparison tests on AppVeyor"
else
image_comparison_facts(
:gr,
tol = PLOTS_IMG_TOL,
skip = Plots._backend_skips[:gr],
)
end
end
@testset "UnicodePlots" begin
@test unicodeplots() == Plots.UnicodePlotsBackend()
@test backend() == Plots.UnicodePlotsBackend()
io = IOBuffer()
# lets just make sure it runs without error
p = plot(rand(10))
@test p isa Plots.Plot
@test show(io, p) isa Nothing
p = bar(randn(10))
@test p isa Plots.Plot
@test show(io, p) isa Nothing
p = plot([1, 2], [3, 4])
annotate!(p, [(1.5, 3.2, Plots.text("Test", :red, :center))])
hline!(p, [3.1])
@test p isa Plots.Plot
@test show(io, p) isa Nothing
p = plot([Dates.Date(2019, 1, 1), Dates.Date(2019, 2, 1)], [3, 4])
hline!(p, [3.1])
annotate!(p, [(Dates.Date(2019, 1, 15), 3.2, Plots.text("Test", :red, :center))])
@test p isa Plots.Plot
@test show(io, p) isa Nothing
p = plot([Dates.Date(2019, 1, 1), Dates.Date(2019, 2, 1)], [3, 4])
annotate!(p, [(Dates.Date(2019, 1, 15), 3.2, :auto)])
hline!(p, [3.1])
@test p isa Plots.Plot
@test show(io, p) isa Nothing
end
@testset "PlotlyJS" begin
@test plotlyjs() == Plots.PlotlyJSBackend()
@test backend() == Plots.PlotlyJSBackend()
p = plot(rand(10))
@test p isa Plots.Plot
@test_broken display(p) isa Nothing
end
end
@testset "Axes" begin
p = plot()
axis = p.subplots[1][:xaxis]
@ -187,6 +128,8 @@ end
@test unicodeplots() == Plots.UnicodePlotsBackend()
@test backend() == Plots.UnicodePlotsBackend()
dsp = TextDisplay(IOContext(IOBuffer(), :color => true))
@testset "Plot" begin
plots = [
histogram([1, 0, 0, 0, 0, 0]),
@ -199,21 +142,20 @@ end
plot(["a" "b"; missing "d"], [1 2; 3 4]),
]
for plt in plots
display(plt)
display(dsp, plt)
end
@test_nowarn plot(x -> x^2, 0, 2)
end
@testset "Bar" begin
p = bar([3, 2, 1], [1, 2, 3])
@test isa(p, Plots.Plot)
@test isa(display(p), Nothing) == true
@test p isa Plots.Plot
@test display(dsp, p) isa Nothing
end
end
@testset "EmptyAnim" begin
anim = @animate for i in []
end
anim = @animate for i in [] end
@test_throws ArgumentError gif(anim)
end
@ -257,3 +199,62 @@ end
Plots.process_clims(missing) ==
Plots.process_clims(:auto)
end
@testset "Backends" begin
@testset "UnicodePlots" begin
@test unicodeplots() == Plots.UnicodePlotsBackend()
@test backend() == Plots.UnicodePlotsBackend()
io = IOContext(IOBuffer(), :color => true)
# lets just make sure it runs without error
p = plot(rand(10))
@test p isa Plots.Plot
@test show(io, p) isa Nothing
p = bar(randn(10))
@test p isa Plots.Plot
@test show(io, p) isa Nothing
p = plot([1, 2], [3, 4])
annotate!(p, [(1.5, 3.2, Plots.text("Test", :red, :center))])
hline!(p, [3.1])
@test p isa Plots.Plot
@test show(io, p) isa Nothing
p = plot([Dates.Date(2019, 1, 1), Dates.Date(2019, 2, 1)], [3, 4])
hline!(p, [3.1])
annotate!(p, [(Dates.Date(2019, 1, 15), 3.2, Plots.text("Test", :red, :center))])
@test p isa Plots.Plot
@test show(io, p) isa Nothing
p = plot([Dates.Date(2019, 1, 1), Dates.Date(2019, 2, 1)], [3, 4])
annotate!(p, [(Dates.Date(2019, 1, 15), 3.2, :auto)])
hline!(p, [3.1])
@test p isa Plots.Plot
@test show(io, p) isa Nothing
end
@testset "PlotlyJS" begin
@test plotlyjs() == Plots.PlotlyJSBackend()
@test backend() == Plots.PlotlyJSBackend()
p = plot(rand(10))
@test p isa Plots.Plot
@test_broken display(p) isa Nothing
end
@testset "GR" begin
ENV["PLOTS_TEST"] = "true"
ENV["GKSwstype"] = "100"
@test gr() == Plots.GRBackend()
@test backend() == Plots.GRBackend()
@static if haskey(ENV, "APPVEYOR")
@info "Skipping GR image comparison tests on AppVeyor"
else
image_comparison_facts(
:gr,
tol = PLOTS_IMG_TOL,
skip = Plots._backend_skips[:gr],
)
end
end
end