diff --git a/Project.toml b/Project.toml index 49b453af5..342e1b52e 100644 --- a/Project.toml +++ b/Project.toml @@ -55,7 +55,7 @@ Scratch = "1" Showoff = "0.3.1, 1.0" StatsBase = "0.32 - 0.33" UnicodeFun = "0.4" -UnicodePlots = "2.4" +UnicodePlots = "2.6" Unzip = "0.1" julia = "1.6" diff --git a/src/backends.jl b/src/backends.jl index 87f0014bf..5911f90a8 100644 --- a/src/backends.jl +++ b/src/backends.jl @@ -923,6 +923,8 @@ const _unicodeplots_attr = merge_with_base_supported([ :linecolor, :linestyle, :markershape, + :quiver, + :arrow, :seriesalpha, :seriescolor, :scale, @@ -936,6 +938,7 @@ const _unicodeplots_seriestype = [ :shape, :histogram2d, :heatmap, + :contour, :spy, ] const _unicodeplots_style = [:auto, :solid] @@ -970,10 +973,10 @@ const _unicodeplots_marker = [ const _unicodeplots_scale = [:identity, :ln, :log2, :log10] # Additional constants -const _unicodeplots_canvas = Ref(:auto) -const _unicodeplots_border = Ref(:auto) -const _unicodeplots_height = Ref(15) -const _unicodeplots_width = Ref(40) +const _up_colormap = Ref(:none) +const _up_canvas = Ref(:auto) +const _up_border = Ref(:auto) +const _up_fix_ar = Ref(true) # ------------------------------------------------------------------------------ # hdf5 diff --git a/src/backends/unicodeplots.jl b/src/backends/unicodeplots.jl index 5f9314d22..ef09268d6 100644 --- a/src/backends/unicodeplots.jl +++ b/src/backends/unicodeplots.jl @@ -24,35 +24,55 @@ function unicodeplots_rebuild(plt::Plot{UnicodePlotsBackend}) yaxis = sp[:yaxis] xlim = collect(axis_limits(sp, :x)) ylim = collect(axis_limits(sp, :y)) + F = float(eltype(xlim)) # 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 should be hidden by consecutive plotting commands. - x = Float64[xlim[1]] - y = Float64[ylim[1]] + x = F[xlim[1]] + y = F[ylim[1]] # create a plot window with xlim/ylim set, # but the X/Y vectors are outside the bounds - canvas = if (up_c = _unicodeplots_canvas[]) == :auto + canvas = if (up_c = _up_canvas[]) == :auto isijulia() ? :ascii : :braille else up_c end - border = if (up_b = _unicodeplots_border[]) == :auto + border = if (up_b = _up_border[]) == :auto isijulia() ? :ascii : :solid else up_b end + width, height = UnicodePlots.DEFAULT_WIDTH[], UnicodePlots.DEFAULT_HEIGHT[] + + grid = xaxis[:grid] && yaxis[:grid] + quiver = contour = false + for series in series_list(sp) + st = series[:seriestype] + quiver |= series[:arrow] isa Arrow # post-pipeline detection (:quiver -> :path) + contour |= st === :contour + if st === :histogram2d + xlim = ylim = (0, 0) + elseif st === :spy || st === :heatmap + width = height = 0 + grid = false + end + end + grid &= !contour && !quiver + kw = ( compact = true, title = texmath2unicode(sp[:title]), xlabel = texmath2unicode(xaxis[:guide]), ylabel = texmath2unicode(yaxis[:guide]), - height = _unicodeplots_height[], - width = _unicodeplots_width[], + grid = grid, + blend = !(quiver || contour), + height = height, + width = width, xscale = xaxis[:scale], yscale = yaxis[:scale], border = border, @@ -87,6 +107,11 @@ up_color(col::RGBA) = (c = convert(ARGB32, col); map(Int, (red(c).i, green(c).i, blue(c).i))) up_color(col) = :auto +function up_cmap(series) + rng = range(0, 1, length = length(UnicodePlots.COLOR_MAP_DATA[:viridis])) + [(red(c), green(c), blue(c)) for c in get(get_colorgradient(series), rng)] +end + # add a single series function addUnicodeSeries!( sp::Subplot{UnicodePlotsBackend}, @@ -98,41 +123,44 @@ function addUnicodeSeries!( st = series[:seriestype] # get the series data and label - x, y = if st == :straightline + x, y = if st === :straightline straightline_data(series) - elseif st == :shape + elseif st === :shape shape_data(series) else float(series[:x]), float(series[:y]) end # special handling (src/interface) - if st == :histogram2d - kw[:xlim][:] .= kw[:ylim][:] .= 0 + if st === :histogram2d return UnicodePlots.densityplot(x, y; kw...) - elseif st == :heatmap - rng = range(0, 1, length = length(UnicodePlots.COLOR_MAP_DATA[:viridis])) - 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, + elseif st === :spy + return UnicodePlots.spy(series[:z].surf; fix_ar = _up_fix_ar[], kw...) + elseif st in (:contour, :heatmap) + kw = ( kw..., + zlabel = sp[:colorbar_title], + colormap = (cm = _up_colormap[] === :none) ? up_cmap(series) : cm, + colorbar = hascolorbar(sp), ) - elseif st == :spy - return UnicodePlots.spy(series[:z].surf; kw...) + if st === :contour + isfilledcontour(series) && @warn "Plots(UnicodePlots): filled contour is not implemented" + return UnicodePlots.contourplot(x, y, series[:z].surf; kw..., levels = series[:levels]) + elseif st === :heatmap + return UnicodePlots.heatmap(series[:z].surf; fix_ar = _up_fix_ar[], kw...) + # zlim = collect(axis_limits(sp, :z)) + end end - series_kw = (;) - # now use the ! functions to add to the plot if st in (:path, :straightline, :shape) func = UnicodePlots.lineplot! - elseif st == :scatter || series[:markershape] != :none + series_kw = (; head_tail = series[:arrow] isa Arrow ? series[:arrow].side : nothing) + elseif st === :scatter || series[:markershape] != :none func = UnicodePlots.scatterplot! series_kw = (; marker = series[:markershape]) else - error("Series type $st not supported by UnicodePlots") + error("Plots(UnicodePlots): series type $st not supported") end label = addlegend ? series[:label] : "" @@ -162,7 +190,7 @@ function addUnicodeSeries!( ) end - return up + up end # ------------------------------------------------------------------------------------------ @@ -198,7 +226,7 @@ end Base.show(plt::Plot{UnicodePlotsBackend}) = show(stdout, plt) Base.show(io::IO, plt::Plot{UnicodePlotsBackend}) = _show(io, MIME("text/plain"), plt) -# NOTE: _show(..) must be kept for Base.showable (src/output.jl) +# NOTE: _show(...) must be kept for Base.showable (src/output.jl) function _show(io::IO, ::MIME"text/plain", plt::Plot{UnicodePlotsBackend}) unicodeplots_rebuild(plt) nr, nc = size(plt.layout) @@ -222,7 +250,7 @@ function _show(io::IO, ::MIME"text/plain", plt::Plot{UnicodePlotsBackend}) for c in 1:nc l = plt.layout[r, c] if l isa GridLayout && size(l) != (1, 1) - @error "UnicodePlots: complex nested layout is currently unsupported !" + @error "Plots(UnicodePlots): complex nested layout is currently unsupported" else if get(l.attr, :blank, false) lines_colored[r, c] = lines_uncolored[r, c] = nothing diff --git a/src/examples.jl b/src/examples.jl index 0c56bce97..1c148af85 100644 --- a/src/examples.jl +++ b/src/examples.jl @@ -1289,7 +1289,6 @@ _backend_skips = Dict( 6, # embedded images unsupported 16, # nested layout unsupported 21, # custom markers unsupported - 22, # contours unsupported 24, # 3D unsupported 26, # nested layout unsupported 27, # polar plots unsupported