diff --git a/.pre-commit-config.yaml b/.pre-commit-config.yaml index 0527eb0..c9eee48 100755 --- a/.pre-commit-config.yaml +++ b/.pre-commit-config.yaml @@ -16,10 +16,10 @@ repos: hooks: - id: gitleaks - repo: https://github.com/fredrikekre/runic-pre-commit - rev: v2.0.1 + rev: v2.2.0 hooks: - id: runic - repo: https://github.com/codespell-project/codespell - rev: v2.4.1 + rev: v2.4.2 hooks: - id: codespell diff --git a/CHANGELOG.md b/CHANGELOG.md index b0918d2..43b5ef6 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,6 +1,7 @@ # Changelog -## [1.18.2] - 2026-04-21 +## [1.19.0] - 2026-XX-XX +- `UnicodePlots` does support multiplots if the package `Term` is loaded. - Add colorbar for cell regions in 2D `gridplot!` with `Py[thon]Plot` ## [1.18.0] - 2026-04-15 diff --git a/Project.toml b/Project.toml index 298e773..5b53cb2 100644 --- a/Project.toml +++ b/Project.toml @@ -1,7 +1,7 @@ name = "GridVisualize" uuid = "5eed8a63-0fb0-45eb-886d-8d5a387d12b8" +version = "1.19.0" authors = ["Juergen Fuhrmann ", "Patrick Jaap "] -version = "1.18.2" [deps] ColorSchemes = "35d6a980-a343-548e-a6ea-1d62b119f2f4" @@ -64,6 +64,7 @@ Printf = "1.6" PyPlot = "2" PythonPlot = "1" StaticArrays = "1" +Term = "2.0.8" Triangulate = "2, 3" UnicodePlots = "3" VTKView = "0.1,0.2" @@ -75,8 +76,9 @@ ExtendableGrids = "cfc395e8-590f-11e8-1f13-43a2532b2fa8" Pkg = "44cfe95a-1eb2-52ea-b672-e2afdf69b78f" PlutoVista = "646e1f28-b900-46d7-9d87-d554eb38a413" PyPlot = "d330b81b-6aea-500a-939a-2ce795aea3ee" +Term = "22787eb5-b846-44ae-b979-8e399b8463ab" Test = "8dfed614-e22c-5e08-85e1-65c5234f0b40" Triangulate = "f7e6ffb2-c36d-4f8f-a77e-16e897189344" [targets] -test = ["CairoMakie", "ExtendableGrids", "Pkg", "PlutoVista", "PyPlot", "Test", "Triangulate"] +test = ["CairoMakie", "ExtendableGrids", "Pkg", "PlutoVista", "PyPlot", "Term", "Test", "Triangulate", "UnicodePlots"] diff --git a/README.md b/README.md index 551028d..5dfa128 100644 --- a/README.md +++ b/README.md @@ -135,18 +135,18 @@ and all plotting functions will do nothing. | | PyPlot/PythonPlot | Makie | PlutoVista | Plots | VTKView | UnicodePlots | |----------------|--------------------|-------|------------|-------|---------|--------------| | scalarplot, 1D | y | y | y,i | y | y | y | -| vectorplot, 1D | y | y | y | y | y | | +| vectorplot, 1D | y | y | y | y | y | n | | gridplot, 1D | y | y | y | y | | y | | scalarplot, 2D | y | y | y | (y) | y,i | y | -| vectorplot, 2D | y | y | y | y | | -| streamplot, 2D | y | y | p | n | | +| vectorplot, 2D | y | y | y | y | | y +| streamplot, 2D | y | y | p | n | | n | gridplot, 2D | y | y,i | y | (y) | y,i | y | -| scalarplot, 3D | y | y,i | y,i | n | y,i | | -| gridplot, 3D | y | y,i | y,i | n | y,i | | -| vectorplot, 3D | p | p | p | n | | | -| streamplot, 3D | | p | p | n | | | -| movie | n | y | n | y | | | -| triangulateio | y | y | n | n | n | | +| scalarplot, 3D | y | y,i | y,i | n | y,i | n | +| gridplot, 3D | y | y,i | y,i | n | y,i | n | +| vectorplot, 3D | p | p | p | n | | n | +| streamplot, 3D | | p | p | n | | n | +| movie | n | y | n | y | | n | +| triangulateio | y | y | n | n | n | n | ## Sample output @@ -166,6 +166,10 @@ and all plotting functions will do nothing. ### [VTKView](https://github.com/j-fu/VTKView.jl) (experimental): ![](https://github.com/WIAS-PDELib/GridVisualize.jl/blob/main/docs/src/assets/multiscene_vtkview.png?raw=true") +### [UnicodePlots](https://github.com/JuliaPlots/UnicodePlots.jl) (experimental): +![](https://github.com/WIAS-PDELib/GridVisualize.jl/blob/main/docs/src/assets/multiscene_unicodeplots.png?raw=true") + + ## vscode Plotting into the plot pane of Visual Studio Code is working. Here, you can use CairoMakie or WGLMakie as backend. This works only with the mutating functions, i.e. you should use something like ``` diff --git a/docs/src/assets/multiscene_unicodeplots.png b/docs/src/assets/multiscene_unicodeplots.png new file mode 100644 index 0000000..cc46cba Binary files /dev/null and b/docs/src/assets/multiscene_unicodeplots.png differ diff --git a/ext/GridVisualizeUnicodePlotsExt.jl b/ext/GridVisualizeUnicodePlotsExt.jl index 31336cd..133538a 100644 --- a/ext/GridVisualizeUnicodePlotsExt.jl +++ b/ext/GridVisualizeUnicodePlotsExt.jl @@ -5,46 +5,57 @@ Extension module for UnicodePlots.jl """ module GridVisualizeUnicodePlotsExt -import GridVisualize: initialize!, gridplot!, scalarplot!, bregion_cmap, region_cmap, reveal -using GridVisualize: UnicodePlotsType, GridVisualizer, SubVisualizer +import GridVisualize: initialize!, gridplot!, scalarplot!, vectorplot!, bregion_cmap, region_cmap, reveal, streamplot! +using GridVisualize: UnicodePlotsType, GridVisualizer, SubVisualizer, vectorsample, quiverdata using UnicodePlots: UnicodePlots using ExtendableGrids: Coordinates, simplexgrid, ON_CELLS, ON_FACES, ON_EDGES, CellNodes, FaceNodes, BFaceNodes, CellGeometries, CellRegions, BFaceRegions, num_cells, num_nodes, local_celledgenodes, num_bfaceregions, num_cellregions, num_targets, interpolate! -using Colors: Colors, RGB, RGBA +using Colors: Colors, RGB, RGBA, red, green, blue +using ColorSchemes: colorschemes, color initialize!(p, ::Type{UnicodePlotsType}) = nothing function reveal(p::GridVisualizer, ::Type{UnicodePlotsType}) - return p.context[:figure] + layout = p.context[:layout] + subplots = @views permutedims(p.subplots)[:] + + if layout == (1, 1) + display(subplots[1][:figure]) + else + if !isdefined(Main, :Term) + @warn "A GridVisualizer with multiple UnicodePlots requires 'Term.jl' to be loaded: add Term.jl to your environment." + else + figures = [subplot[:figure] for subplot in subplots if haskey(subplot, :figure)] + grid_plot = UnicodePlots.gridplot(figures, layout = p.context[:layout], show_placeholder = true) + display(grid_plot) + end + end + return nothing end function reveal(ctx::SubVisualizer, TP::Type{UnicodePlotsType}) if ctx[:show] || ctx[:reveal] - display(ctx[:figure]) + return reveal(ctx[:GridVisualizer], TP) end return nothing end -function region_legend!(canvas, title, x, y, colors) +function region_legend!(plt, title, y0, colors) # legend by annotate! - for (i, char) in enumerate(title) - UnicodePlots.char_point!(canvas, x + i - 1, y, char, UInt32(0), false) - end - startx = x + length(title) + UnicodePlots.label!(plt, :r, y0, title) for r in 1:length(colors) red, green, blue = UInt32.(colors[r]) uint_color = (red << 16) | (green << 8) | blue - reg_string = "$r " - for char in reg_string - startx += 1 - UnicodePlots.char_point!(canvas, startx, y, char, uint_color, false) - end + y0 += 1 + UnicodePlots.label!(plt, :r, y0, " " * string(r), uint_color) end - return + return y0 end +gridplot!(ctx, TP::Type{UnicodePlotsType}, ::Type{Val{3}}, grid) = @warn "3D gridplots are not implemented for the UnicodePlots backend" + function gridplot!(ctx, TP::Type{UnicodePlotsType}, ::Type{Val{2}}, grid) UnicodePlots = ctx[:Plotter] @@ -65,8 +76,9 @@ function gridplot!(ctx, TP::Type{UnicodePlotsType}, ::Type{Val{2}}, grid) end # determine resolution (divided by 10, to reduce pixel count in the terminal) - resolution = ctx[:size] ./ 10 - legend_space = 4 + layout = ctx[:layout] + resolution = ctx[:size] ./ 12 ./ (layout[2], layout[1]) + legend_space = 0 aspect = ctx[:aspect] * resolution[1] / (resolution[1] + legend_space) if (true) # auto scale feature, do we want this? @@ -84,7 +96,7 @@ function gridplot!(ctx, TP::Type{UnicodePlotsType}, ::Type{Val{2}}, grid) resolution = @. Int(round(resolution)) # create UnicodePlots.Canvas - padding = 0.1 * max(ex[2] - ex[1], ey[2] - ey[1]) + padding = 0 #0.1 * max(ex[2] - ex[1], ey[2] - ey[1]) ex = (ex[1] - 2 * padding, ex[2] + 0.5 * padding) ey = (ey[1] - padding, ey[2] + padding) CanvasType = UnicodePlots.BrailleCanvas # should this be a changeable parameter ? @@ -180,25 +192,33 @@ function gridplot!(ctx, TP::Type{UnicodePlotsType}, ::Type{Val{2}}, grid) ) end - region_legend!(canvas, "cell regions: ", 2, 1, colors) - region_legend!(canvas, "bface regions:", 2, 2, bcolors) + + plt = UnicodePlots.Plot(canvas; title = ctx[:title], border = ctx[:border]) + + y0 = region_legend!(plt, " cell", 1, []) + y0 = region_legend!(plt, "regions", 2, colors) + region_legend!(plt, " bface", y0 + 2, []) + region_legend!(plt, "regions", y0 + 3, bcolors) # corner coordinates ex = extrema(view(coords, 1, :)) ey = extrema(view(coords, 2, :)) - UnicodePlots.annotate!(canvas, ex[1], ey[1], "$(ex[1])", UInt32(0), false; valign = :top) - UnicodePlots.annotate!(canvas, ex[2], ey[1], "$(ex[2])", UInt32(0), false; valign = :top, halign = :right) - UnicodePlots.annotate!(canvas, ex[1] - 1.5 * padding, ey[1], "$(ey[1])", UInt32(0), false; halign = :left) - UnicodePlots.annotate!(canvas, ex[1] - 1.5 * padding, ey[2], "$(ey[2])", UInt32(0), false; halign = :left) + UnicodePlots.label!(plt, :bl, string(Float16(ex[1])), UnicodePlots.ansi_color(UnicodePlots.BORDER_COLOR[])) + UnicodePlots.label!(plt, :b, "x") + UnicodePlots.label!(plt, :br, string(Float16(ex[2])), UnicodePlots.ansi_color(UnicodePlots.BORDER_COLOR[])) + UnicodePlots.label!(plt, :l, 1, string(Float16(ey[2])), UnicodePlots.ansi_color(UnicodePlots.BORDER_COLOR[])) + UnicodePlots.label!(plt, :l, round(Int, (resolution[2] + 1) / 2), "y") + UnicodePlots.label!(plt, :l, resolution[2], string(Float16(ey[1])), UnicodePlots.ansi_color(UnicodePlots.BORDER_COLOR[])) # plot - ctx[:figure] = UnicodePlots.Plot(canvas; title = ctx[:title]) + ctx[:figure] = plt return reveal(ctx, TP) end function gridplot!(ctx, TP::Type{UnicodePlotsType}, ::Type{Val{1}}, grid) UnicodePlots = ctx[:Plotter] + text_color = UnicodePlots.ansi_color(:normal) # find bounding box coords = grid[Coordinates] @@ -215,12 +235,15 @@ function gridplot!(ctx, TP::Type{UnicodePlotsType}, ::Type{Val{1}}, grid) color = ctx[:color] end - # determine resolution (divided by 10, to reduce pixel count in the terminal) - resolution = (Int(round(ctx[:size][1] / 10)), 5) + # determine resolution (divided by 5, to reduce pixel count in the terminal) + ncellregions = num_cellregions(grid) + nbregions = num_bfaceregions(grid) + layout = ctx[:layout] + resolution = (Int(round(ctx[:size][1] / 6 / layout[2])), max(7, 5 + ncellregions + nbregions)) # create UnicodePlots.Canvas - legend_space = 5 - padding = 0.05 * (ex[2] - ex[1]) + legend_space = 0 #5 + padding = 0 #0.05 * (ex[2] - ex[1]) ex = (ex[1] - padding, ex[2] + padding) CanvasType = UnicodePlots.BrailleCanvas # should this be a changeable parameter ? canvas = CanvasType( @@ -231,7 +254,6 @@ function gridplot!(ctx, TP::Type{UnicodePlotsType}, ::Type{Val{1}}, grid) # plot all edges in the grid cellregions = grid[CellRegions] - ncellregions = num_cellregions(grid) cmap = region_cmap(max(2, ncellregions)) ctx[:cmap] = cmap colors = [ @@ -251,18 +273,17 @@ function gridplot!(ctx, TP::Type{UnicodePlotsType}, ::Type{Val{1}}, grid) for k in 1:size(cen, 2) UnicodePlots.lines!( canvas, - coords[1, cellnodes[cen[1, k], j]], 0.3, - coords[1, cellnodes[cen[2, k], j]], 0.3; + coords[1, cellnodes[cen[1, k], j]], 0.5, + coords[1, cellnodes[cen[2, k], j]], 0.5; color = colors[r] ) end end for j in 1:nnodes - UnicodePlots.annotate!(canvas, coords[1, j], 0.4, "•", UInt32(0), false) + UnicodePlots.annotate!(canvas, coords[1, j], 0.5, "•", text_color, false) end # plot boundary nodes with bregion_cmap colors - nbregions = num_bfaceregions(grid) bcmap = bregion_cmap(nbregions) ctx[:bcmap] = bcmap bcolors = [ @@ -278,19 +299,25 @@ function gridplot!(ctx, TP::Type{UnicodePlotsType}, ::Type{Val{1}}, grid) for j in 1:nbfaces red, green, blue = UInt32.(bcolors[bfaceregions[j]]) uint_color = (red << 16) | (green << 8) | blue - UnicodePlots.annotate!(canvas, coords[1, bfacenodes[1, j]], 0.4, "•", UInt32(uint_color), false) + UnicodePlots.annotate!(canvas, coords[1, bfacenodes[1, j]], 0.5, "•", UInt32(uint_color), false) end - region_legend!(canvas, "cell regions: ", 2, 1, colors) - region_legend!(canvas, "bface regions:", 2, 2, bcolors) + plt = UnicodePlots.Plot(canvas; title = ctx[:title], border = ctx[:border]) + + y0 = region_legend!(plt, " cell", 1, []) + y0 = region_legend!(plt, "regions", 2, colors) + region_legend!(plt, " bface", y0 + 2, []) + region_legend!(plt, "regions", y0 + 3, bcolors) + # corner coordinates ex = extrema(view(coords, 1, :)) - UnicodePlots.annotate!(canvas, 0, 0.1, "$(ex[1])", UInt32(0), false) - UnicodePlots.annotate!(canvas, ex[2], 0.1, "$(ex[2])", UInt32(0), false) + UnicodePlots.label!(plt, :bl, string(Float16(ex[1])), UnicodePlots.ansi_color(UnicodePlots.BORDER_COLOR[])) + UnicodePlots.label!(plt, :b, "x") + UnicodePlots.label!(plt, :br, string(Float16(ex[2])), UnicodePlots.ansi_color(UnicodePlots.BORDER_COLOR[])) # plot - ctx[:figure] = UnicodePlots.Plot(canvas; title = ctx[:title]) + ctx[:figure] = plt return reveal(ctx, TP) end @@ -306,7 +333,8 @@ function scalarplot!( ) nfuncs = length(funcs) - resolution = @. Int(round(ctx[:size] ./ 10)) # reduce pixel count in the terminal + layout = ctx[:layout] + resolution = @. Int(round(ctx[:size] ./ 6 ./ (layout[2], layout[1] * 2))) # reduce pixel count in the terminal (size is then compatible to other plots) ylim = ctx[:limits] if ylim[1] > ylim[2] @@ -314,15 +342,60 @@ function scalarplot!( ylim = (minimum([minimum(func) for func in funcs]), maximum([maximum(func) for func in funcs])) end - plt = ctx[:clear] ? nothing : ctx[:figure] + if ctx[:clear] || !haskey(ctx, :figure) + plt = nothing + else + plt = ctx[:figure] + end + + xlim = ctx[:xlimits] + if xlim[1] > xlim[2] + # invalid, try to find the optimal range + coord_min = min(ctx[:xlimits][1], minimum.([grid[Coordinates] for grid in grids])...) + coord_max = max(ctx[:xlimits][2], maximum.([grid[Coordinates] for grid in grids])...) + xlim = (coord_min, coord_max) + end + + xscale = ctx[:xscale] + xscale == :log && (xscale = :log10) + xscale == :symlog && (xscale = x -> sign(x) * (log10(1 + abs(x)))) + + yscale = ctx[:yscale] + yscale == :log && (yscale = :log10) + yscale == :symlog && (yscale = x -> sign(x) * (log10(1 + abs(x)))) + + color = UnicodePlots.ansi_color(Symbol(ctx[:color])) + for ifunc in 1:nfuncs func = funcs[ifunc] grid = grids[ifunc] coord = grid[Coordinates] * ctx[:gridscale] - if ifunc == 1 - plt = UnicodePlots.lineplot(coord[1, :], func; ylim, xlabel = "x", name = ctx[:label], height = resolution[2], width = resolution[1]) + name = name = isnothing(ctx[:label]) ? "" : ctx[:label] + + if isnothing(plt) + plt = UnicodePlots.lineplot( + coord[1, :], + func; + xlim, + ylim, + xscale, + yscale, + xlabel = String(ctx[:xlabel]), + name, + height = resolution[2], + width = resolution[1], + title = ctx[:title], + border = ctx[:border], + color + ) else - UnicodePlots.lineplot!(plt, coord[1, :], func; name = ctx[:label]) + UnicodePlots.lineplot!( + plt, + coord[1, :], + func; + name, + color + ) end end ctx[:figure] = plt @@ -341,7 +414,8 @@ function scalarplot!( ) func = funcs[1] - resolution = @. Int(round(ctx[:size] ./ 10)) # reduce pixel count in the terminal + layout = ctx[:layout] + resolution = ctx[:size] ./ 6 ./ (layout[2], layout[1]) # reduce pixel count in the terminal ylim = ctx[:limits] colormap = ctx[:colormap] @@ -354,6 +428,20 @@ function scalarplot!( ex = extrema(view(coords, 1, :)) ey = extrema(view(coords, 2, :)) + if (true) # auto scale feature, do we want this? + wx = ex[2] - ex[1] + wy = ey[2] - ey[1] + rescale = wx / wy * (resolution[1] / (resolution[2])) + if rescale > 1 + resolution = (resolution[1], resolution[2] / rescale) + else + resolution = (resolution[1] / rescale, resolution[2]) + end + end + + # we need an integer resolution + resolution = @. Int(round(resolution)) + X = LinRange(ex[1], ex[2], resolution[1]) Y = LinRange(ey[1], ey[2], resolution[2]) xgrid_plot = simplexgrid(X, Y) @@ -372,9 +460,125 @@ function scalarplot!( yoffset = ey[1], title = ctx[:title], colormap = colormap, + height = resolution[2], + width = resolution[1], + xscale = ctx[:xscale], + yscale = ctx[:yscale], + border = ctx[:border] + ) + + return reveal(ctx, TP) +end + +scalarplot!(ctx, TP::Type{UnicodePlotsType}, ::Type{Val{3}}, grids, parentgrid, funcs) = @warn "3D scalarplot is not implemented for the UnicodePlots backend" + +function vectorplot!(ctx, TP::Type{UnicodePlotsType}, ::Type{Val{2}}, grid, func) + + layout = ctx[:layout] + resolution = ctx[:size] ./ 12 ./ (layout[2], layout[1]) # reduce pixel count in the terminal + + # find bounding box + coords = grid[Coordinates] + ex = extrema(view(coords, 1, :)) + ey = extrema(view(coords, 2, :)) + + aspect = ctx[:aspect] * resolution[1] / resolution[1] + + if (true) # auto scale feature, do we want this? + wx = ex[2] - ex[1] + wy = ey[2] - ey[1] + rescale = wx / wy * (resolution[1] / (2 * resolution[2])) + if rescale > 1 + resolution = (resolution[1] * aspect, Int(ceil(resolution[2] / rescale))) + else + resolution = (Int(ceil(resolution[1] * aspect / rescale)), resolution[2]) + end + end + + # we need an integer resolution + resolution = @. Int(round(resolution)) + + # query vector field raster points + rc, rv = vectorsample(grid, func; gridscale = ctx[:gridscale], rasterpoints = ((resolution[1] - 1) / 2, 2 * (resolution[2] - 1)), offset = ctx[:offset]) + qc, qv = quiverdata(rc, rv; vscale = ctx[:vscale], vnormalize = ctx[:vnormalize], vconstant = ctx[:vconstant]) + + # construct canvas + CanvasType = UnicodePlots.BrailleCanvas # should this be a changeable parameter ? + canvas = CanvasType( + resolution[2], resolution[1], # number of rows and columns (characters) + origin_y = ey[1], origin_x = ex[1], # position in virtual space + height = (ey[2] - ey[1]), width = (ex[2] - ex[1]); blend = false ) + # plot arrows + scale = minimum(resolution) / maximum(ctx[:rasterpoints]) / 300 + narrows = size(qv, 2) + vscale = ctx[:vscale] # vscale steers arrow thickness + if vscale <= 0.25 + arrows = ['↙', '↓', '↘', '→', '↗', '↑', '↖', '←'] + elseif vscale <= 0.5 + arrows = ['🡯', '🡫', '🡮', '🡪', '🡭', '🡩', '🡬', '🡨'] + elseif vscale <= 1 + arrows = ['🡷', '🡳', '🡶', '🡲', '🡵', '🡱', '🡴', '🡰'] + else + arrows = ['🢇', '🢃', '🢆', '🢂', '🢅', '🢁', '🢄', '🢀'] + end + maxnorm = maximum(sqrt.(sum(qv .^ 2, dims = 1))) + colormap = colorschemes[ctx[:colormap]] + for a in 1:narrows + # calculate angle of arrow + angle = atan(qv[2, a], qv[1, a]) + anorm = sqrt(qv[1, a]^2 + qv[2, a]^2) + scale = anorm / maxnorm + uint_color = UnicodePlots.ansi_color(colormap[scale]) + if angle > -7 * π / 8 && angle <= -5 * π / 8 + char = arrows[1] + elseif angle > -5 * π / 8 && angle <= -3 * π / 8 + char = arrows[2] + elseif angle > -3 * π / 8 && angle <= -π / 8 + char = arrows[3] + elseif angle > -π / 8 && angle <= π / 8 + char = arrows[4] + elseif angle > π / 8 && angle <= 3 * π / 8 + char = arrows[5] + elseif angle > 3 * π / 8 && angle <= 5 * π / 8 + char = arrows[6] + elseif angle > 5 * π / 8 && angle <= 7 * π / 8 + char = arrows[7] + else + char = arrows[8] + end + if scale < 1.0e-2 + char = '•' # use a dot for very small vectors + end + + UnicodePlots.annotate!(canvas, qc[1, a], qc[2, a], char, uint_color, false) + end + + # generate plot + plt = UnicodePlots.Plot(canvas; title = ctx[:title], border = ctx[:border]) + + # add colormap + plt.cmap.bar = ctx[:colorbar] == :none ? false : true + plt.cmap.lim = (0, Float16(maxnorm)) + plt.cmap.callback = UnicodePlots.colormap_callback(ctx[:colormap]) + + # corner coordinates + ex = extrema(view(coords, 1, :)) + ey = extrema(view(coords, 2, :)) + UnicodePlots.label!(plt, :bl, string(Float16(ex[1])), UnicodePlots.ansi_color(UnicodePlots.BORDER_COLOR[])) + UnicodePlots.label!(plt, :b, "x") + UnicodePlots.label!(plt, :br, string(Float16(ex[2])), UnicodePlots.ansi_color(UnicodePlots.BORDER_COLOR[])) + UnicodePlots.label!(plt, :l, 1, string(Float16(ey[2])), UnicodePlots.ansi_color(UnicodePlots.BORDER_COLOR[])) + UnicodePlots.label!(plt, :l, round(Int, (resolution[2] + 1) / 2), "y") + UnicodePlots.label!(plt, :l, resolution[2], string(Float16(ey[1])), UnicodePlots.ansi_color(UnicodePlots.BORDER_COLOR[])) + + ctx[:figure] = plt + return reveal(ctx, TP) end +streamplot!(ctx, TP::Type{UnicodePlotsType}, ::Type{Val{2}}, grid, func) = @warn "2D streamplot is not implemented for the UnicodePlots backend" + + end # module diff --git a/src/common.jl b/src/common.jl index e5a98a0..4bfa21c 100644 --- a/src/common.jl +++ b/src/common.jl @@ -213,6 +213,10 @@ function vectorsample( eltype = dim == 2 ? Triangle2D : Tetrahedron3D + if typeof(rasterpoints) <: Integer + rasterpoints = (rasterpoints, rasterpoints) + end + scaledgrid = grid if gridscale != 1.0 scaledgrid = ExtendableGrid{coord_type(grid), index_type(grid)}() @@ -253,7 +257,7 @@ function vectorsample( tol = reltol * extent # point spacing - spacing = [extent / rasterpoints for i in 1:dim] + spacing = [extent / rasterpoints[i] for i in 1:dim] # index range ijkmax = ones(Int, 3) diff --git a/src/dispatch.jl b/src/dispatch.jl index 97a3dad..9d5b9e9 100644 --- a/src/dispatch.jl +++ b/src/dispatch.jl @@ -331,6 +331,7 @@ function default_plot_kwargs() :azim => Pair(-60, "3D azimuth angle (in degrees)"), :aspect => Pair(1.0, "XY Aspect ratio modification"), :backend => Pair(:default, "Backend for PlutoVista plot"), + :border => Pair(:solid, "border style (only for UnicodePlots), possible values: :corners, :solid, :bold, :dashed, :dotted, :ascii, :none"), :cellcoloring => Pair( :cellregions, "Coloring of cells: one of [:cellregions, :pcolors, :partitions]" diff --git a/test/runtests.jl b/test/runtests.jl index a548257..965174b 100644 --- a/test/runtests.jl +++ b/test/runtests.jl @@ -1,6 +1,6 @@ using Test, ExtendableGrids, GridVisualize, Pkg, LinearAlgebra -import CairoMakie, PyPlot, PlutoVista +import CairoMakie, PyPlot, PlutoVista, UnicodePlots, Term CairoMakie.activate!(; type = "svg", visible = false) @@ -21,10 +21,15 @@ for Plotter in [CairoMakie] end # Some Plotters cannot perform the `makeplots` run, only try a `multiscene` -for Plotter in [PyPlot, PlutoVista] +for Plotter in [PyPlot, PlutoVista, UnicodePlots] @eval begin @testset "plotting_multiscene - $(nameof($Plotter))" begin - @test plotting_multiscene(Plotter = $Plotter) !== nothing + try + plotting_multiscene(Plotter = $Plotter) + @test true + catch e + @test false + end end end end