From 0a7a413f16040a245680c538b18a63ab7f15df9d Mon Sep 17 00:00:00 2001 From: Patrick Jaap Date: Thu, 23 Apr 2026 16:16:06 +0200 Subject: [PATCH 01/17] Make detection of Term.jl more robust --- ext/GridVisualizeUnicodePlotsExt.jl | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/ext/GridVisualizeUnicodePlotsExt.jl b/ext/GridVisualizeUnicodePlotsExt.jl index 133538a..999b5eb 100644 --- a/ext/GridVisualizeUnicodePlotsExt.jl +++ b/ext/GridVisualizeUnicodePlotsExt.jl @@ -22,7 +22,7 @@ function reveal(p::GridVisualizer, ::Type{UnicodePlotsType}) if layout == (1, 1) display(subplots[1][:figure]) else - if !isdefined(Main, :Term) + if :Term ∉ Symbol.(Base.loaded_modules_array()) @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)] From e8c8083056d3e7d14bd5a2b9ca4859272e3204e5 Mon Sep 17 00:00:00 2001 From: Patrick Jaap Date: Thu, 23 Apr 2026 16:16:24 +0200 Subject: [PATCH 02/17] Remove unused code --- ext/GridVisualizeUnicodePlotsExt.jl | 11 ----------- 1 file changed, 11 deletions(-) diff --git a/ext/GridVisualizeUnicodePlotsExt.jl b/ext/GridVisualizeUnicodePlotsExt.jl index 999b5eb..1366855 100644 --- a/ext/GridVisualizeUnicodePlotsExt.jl +++ b/ext/GridVisualizeUnicodePlotsExt.jl @@ -224,17 +224,6 @@ function gridplot!(ctx, TP::Type{UnicodePlotsType}, ::Type{Val{1}}, grid) coords = grid[Coordinates] ex = extrema(view(coords, 1, :)) - # line color for interior edges - if typeof(ctx[:color]) <: RGB - color = ( - Int(round(ctx[:color].r * 255)), - Int(round(ctx[:color].g * 255)), - Int(round(ctx[:color].b * 255)), - ) - else - color = ctx[:color] - end - # determine resolution (divided by 5, to reduce pixel count in the terminal) ncellregions = num_cellregions(grid) nbregions = num_bfaceregions(grid) From 186db0f558df7a95cbf02541af5ebd4330f90262 Mon Sep 17 00:00:00 2001 From: Patrick Jaap Date: Thu, 23 Apr 2026 16:16:49 +0200 Subject: [PATCH 03/17] convert color correctly in scalarplot --- ext/GridVisualizeUnicodePlotsExt.jl | 13 ++++++++++++- 1 file changed, 12 insertions(+), 1 deletion(-) diff --git a/ext/GridVisualizeUnicodePlotsExt.jl b/ext/GridVisualizeUnicodePlotsExt.jl index 1366855..a1352f5 100644 --- a/ext/GridVisualizeUnicodePlotsExt.jl +++ b/ext/GridVisualizeUnicodePlotsExt.jl @@ -353,7 +353,18 @@ function scalarplot!( yscale == :log && (yscale = :log10) yscale == :symlog && (yscale = x -> sign(x) * (log10(1 + abs(x)))) - color = UnicodePlots.ansi_color(Symbol(ctx[:color])) + if typeof(ctx[:color]) <: String || typeof(ctx[:color]) <: Symbol + color = UnicodePlots.ansi_color(Symbol(ctx[:color])) + elseif typeof(ctx[:color]) <: RGB + color = ( + Int(round(ctx[:color].r * 255)), + Int(round(ctx[:color].g * 255)), + Int(round(ctx[:color].b * 255)), + ) + else + color = ctx[:color] + end + for ifunc in 1:nfuncs func = funcs[ifunc] From e98c4f22719579d7b821bc9493ab54e58e233a56 Mon Sep 17 00:00:00 2001 From: Patrick Jaap Date: Thu, 23 Apr 2026 16:17:18 +0200 Subject: [PATCH 04/17] slice_plot: use simplexgrid constructor --- src/slice_plots.jl | 17 ++++++++--------- 1 file changed, 8 insertions(+), 9 deletions(-) diff --git a/src/slice_plots.jl b/src/slice_plots.jl index 4360142..82c5d0c 100644 --- a/src/slice_plots.jl +++ b/src/slice_plots.jl @@ -214,9 +214,6 @@ function slice_plot!(ctx, ::Type{Val{3}}, grid, values) # get new data from marching_tetrahedra new_coords, new_triangles, new_values = GridVisualize.marching_tetrahedra(grid, values, [plane], []) - # construct new 2D grid - grid_2d = ExtendableGrid{Float64, Int32}() - a::Float64, b::Float64, c::Float64, _ = plane # transformation matrix @@ -242,23 +239,25 @@ function slice_plot!(ctx, ::Type{Val{3}}, grid, values) rotation_matrix = compute_3d_z_rotation_matrix([a, b, c]) end - grid_2d[Coordinates] = Matrix{Float64}(undef, 2, length(new_coords)) + coords = Matrix{Float64}(undef, 2, length(new_coords)) for (ip, p) in enumerate(new_coords) # to obtain the projected coordinates, we can simply use the transpose of the rotation matrix - @views grid_2d[Coordinates][:, ip] .= (rotation_matrix'p)[1:2] + @views coords[:, ip] .= (rotation_matrix'p)[1:2] end if (a, b, c) ∉ [(1.0, 0.0, 0.0), (0.0, 1.0, 0.0), (0.0, 0.0, 1.0)] # adjust the coordinates s.t. the minimal coordinate is zero - @views grid_2d[Coordinates][1, :] .-= minimum(grid_2d[Coordinates][1, :]) - @views grid_2d[Coordinates][2, :] .-= minimum(grid_2d[Coordinates][2, :]) + @views coords[1, :] .-= minimum(coords[1, :]) + @views coords[2, :] .-= minimum(coords[2, :]) end - grid_2d[CellNodes] = Matrix{Int32}(undef, 3, length(new_triangles)) + cellnodes = Matrix{Int32}(undef, 3, length(new_triangles)) for (it, t) in enumerate(new_triangles) - @views grid_2d[CellNodes][:, it] .= t + @views cellnodes[:, it] .= t end + # construct new 2D grid + grid_2d = simplexgrid(coords, cellnodes) return scalarplot!(ctx, grid_2d, new_values) end From e6c65b633c7efb63054cc5dc2b7c0fdefefa265d Mon Sep 17 00:00:00 2001 From: Patrick Jaap Date: Thu, 23 Apr 2026 16:17:38 +0200 Subject: [PATCH 05/17] CHANGELOG + Patch version --- CHANGELOG.md | 6 +++++- Project.toml | 2 +- 2 files changed, 6 insertions(+), 2 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 43b5ef6..6b2e8f6 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,6 +1,10 @@ # Changelog -## [1.19.0] - 2026-XX-XX +## [1.19.1] - 2026-04-23 +- several small fixes in `UnicodePlots` extension. +- fix in slice plotting: use `simplexgrid` constructor for the resulting grid to ensure a consistent grid. + +## [1.19.0] - 2026-04-23 - `UnicodePlots` does support multiplots if the package `Term` is loaded. - Add colorbar for cell regions in 2D `gridplot!` with `Py[thon]Plot` diff --git a/Project.toml b/Project.toml index 5b53cb2..09a170e 100644 --- a/Project.toml +++ b/Project.toml @@ -1,6 +1,6 @@ name = "GridVisualize" uuid = "5eed8a63-0fb0-45eb-886d-8d5a387d12b8" -version = "1.19.0" +version = "1.19.1" authors = ["Juergen Fuhrmann ", "Patrick Jaap "] [deps] From e45b28406940d75003ba606f559e1f35dfd190b3 Mon Sep 17 00:00:00 2001 From: Patrick Jaap Date: Thu, 23 Apr 2026 17:07:06 +0200 Subject: [PATCH 06/17] Use default color in gridplot 2d --- ext/GridVisualizeUnicodePlotsExt.jl | 18 +++++------------- 1 file changed, 5 insertions(+), 13 deletions(-) diff --git a/ext/GridVisualizeUnicodePlotsExt.jl b/ext/GridVisualizeUnicodePlotsExt.jl index a1352f5..540f70d 100644 --- a/ext/GridVisualizeUnicodePlotsExt.jl +++ b/ext/GridVisualizeUnicodePlotsExt.jl @@ -65,15 +65,7 @@ function gridplot!(ctx, TP::Type{UnicodePlotsType}, ::Type{Val{2}}, grid) ey = extrema(view(coords, 2, :)) # line color for interior edges - if typeof(ctx[:color]) <: RGB - color = ( - Int(round(ctx[:color].r * 255)), - Int(round(ctx[:color].g * 255)), - Int(round(ctx[:color].b * 255)), - ) - else - color = ctx[:color] - end + edge_color = UnicodePlots.ansi_color(:normal) # determine resolution (divided by 10, to reduce pixel count in the terminal) layout = ctx[:layout] @@ -117,7 +109,7 @@ function gridplot!(ctx, TP::Type{UnicodePlotsType}, ::Type{Val{2}}, grid) canvas, coords[1, facenodes[1, j]], coords[2, facenodes[1, j]], # from coords[1, facenodes[2, j]], coords[2, facenodes[2, j]]; # to - color = color + color = edge_color ) end elseif plot_based == ON_CELLS @@ -143,7 +135,7 @@ function gridplot!(ctx, TP::Type{UnicodePlotsType}, ::Type{Val{2}}, grid) ncellregions = num_cellregions(grid) cmap = region_cmap(max(2, ncellregions)) ctx[:cmap] = cmap - colors = [ + cell_colors = [ ( Int(round(cmap[i].r * 255)), Int(round(cmap[i].g * 255)), @@ -165,7 +157,7 @@ function gridplot!(ctx, TP::Type{UnicodePlotsType}, ::Type{Val{2}}, grid) UnicodePlots.points!( canvas, midpoint[1], midpoint[2]; - color = colors[r] + color = cell_colors[r] ) end @@ -196,7 +188,7 @@ function gridplot!(ctx, TP::Type{UnicodePlotsType}, ::Type{Val{2}}, grid) plt = UnicodePlots.Plot(canvas; title = ctx[:title], border = ctx[:border]) y0 = region_legend!(plt, " cell", 1, []) - y0 = region_legend!(plt, "regions", 2, colors) + y0 = region_legend!(plt, "regions", 2, cell_colors) region_legend!(plt, " bface", y0 + 2, []) region_legend!(plt, "regions", y0 + 3, bcolors) From 0a1738fe4229c7db4faff0ff0dbad6e316d4dd3a Mon Sep 17 00:00:00 2001 From: Patrick Jaap Date: Thu, 23 Apr 2026 17:38:46 +0200 Subject: [PATCH 07/17] UnicodePlots: respect linewidth and markersize --- ext/GridVisualizeUnicodePlotsExt.jl | 91 +++++++++++++++++++---------- 1 file changed, 59 insertions(+), 32 deletions(-) diff --git a/ext/GridVisualizeUnicodePlotsExt.jl b/ext/GridVisualizeUnicodePlotsExt.jl index 540f70d..fbc4fb3 100644 --- a/ext/GridVisualizeUnicodePlotsExt.jl +++ b/ext/GridVisualizeUnicodePlotsExt.jl @@ -98,35 +98,38 @@ function gridplot!(ctx, TP::Type{UnicodePlotsType}, ::Type{Val{2}}, grid) height = (ey[2] - ey[1]) / (resolution[1] / (resolution[1] + legend_space)), width = ex[2] - ex[1]; blend = false ) - ## plot all edges in the grid - plot_based = ctx[:cellwise] ? ON_CELLS : ON_FACES - if plot_based in [ON_FACES, ON_EDGES] - # plot all edges via FaceNodes - facenodes = grid[FaceNodes] - nfaces = size(facenodes, 2) - for j in 1:nfaces - UnicodePlots.lines!( - canvas, - coords[1, facenodes[1, j]], coords[2, facenodes[1, j]], # from - coords[1, facenodes[2, j]], coords[2, facenodes[2, j]]; # to - color = edge_color - ) - end - elseif plot_based == ON_CELLS - # plot all edges via CellNodes and local_celledgenodes - cellnodes = grid[CellNodes] - cellgeoms = grid[CellGeometries] - ncells = num_cells(grid) - for j in 1:ncells - cen = local_celledgenodes(cellgeoms[j]) - for k in 1:size(cen, 2) + linewidth = ctx[:linewidth] + if linewidth > 0 + ## plot all edges in the grid + plot_based = ctx[:cellwise] ? ON_CELLS : ON_FACES + if plot_based in [ON_FACES, ON_EDGES] + # plot all edges via FaceNodes + facenodes = grid[FaceNodes] + nfaces = size(facenodes, 2) + for j in 1:nfaces UnicodePlots.lines!( canvas, - coords[1, cellnodes[cen[1, k], j]], coords[2, cellnodes[cen[1, k], j]], - coords[1, cellnodes[cen[2, k], j]], coords[2, cellnodes[cen[2, k], j]]; - color = color + coords[1, facenodes[1, j]], coords[2, facenodes[1, j]], # from + coords[1, facenodes[2, j]], coords[2, facenodes[2, j]]; # to + color = edge_color ) end + elseif plot_based == ON_CELLS + # plot all edges via CellNodes and local_celledgenodes + cellnodes = grid[CellNodes] + cellgeoms = grid[CellGeometries] + ncells = num_cells(grid) + for j in 1:ncells + cen = local_celledgenodes(cellgeoms[j]) + for k in 1:size(cen, 2) + UnicodePlots.lines!( + canvas, + coords[1, cellnodes[cen[1, k], j]], coords[2, cellnodes[cen[1, k], j]], + coords[1, cellnodes[cen[2, k], j]], coords[2, cellnodes[cen[2, k], j]]; + color = color + ) + end + end end end @@ -146,6 +149,7 @@ function gridplot!(ctx, TP::Type{UnicodePlotsType}, ::Type{Val{2}}, grid) cellgeoms = grid[CellGeometries] ncells = num_cells(grid) midpoint = [0.0, 0.0] + markersize = ctx[:markersize] for j in 1:ncells fill!(midpoint, 0.0) nvertices = num_targets(cellnodes, j) @@ -154,11 +158,31 @@ function gridplot!(ctx, TP::Type{UnicodePlotsType}, ::Type{Val{2}}, grid) end midpoint ./= nvertices r = cellregions[j] - UnicodePlots.points!( - canvas, - midpoint[1], midpoint[2]; - color = cell_colors[r] - ) + if markersize > 0 + if markersize < 4 + UnicodePlots.points!( + canvas, + midpoint[1], midpoint[2]; + color = cell_colors[r] + ) + else + if markersize < 6 + character = "•" + elseif markersize < 8 + character = "●" + else + character = "⬤" + end + UnicodePlots.annotate!( + canvas, + midpoint[1], midpoint[2], + character, + UnicodePlots.ansi_color(cell_colors[r]), + false + ) + end + end + end # plot boundary faces with bregion_cmap colors @@ -187,8 +211,11 @@ function gridplot!(ctx, TP::Type{UnicodePlotsType}, ::Type{Val{2}}, grid) plt = UnicodePlots.Plot(canvas; title = ctx[:title], border = ctx[:border]) - y0 = region_legend!(plt, " cell", 1, []) - y0 = region_legend!(plt, "regions", 2, cell_colors) + y0 = 0 + if markersize > 0 + y0 = region_legend!(plt, " cell", 1, []) + y0 = region_legend!(plt, "regions", 2, cell_colors) + end region_legend!(plt, " bface", y0 + 2, []) region_legend!(plt, "regions", y0 + 3, bcolors) From 18d8e7c8a7322b6108e707abadb93508a821f0aa Mon Sep 17 00:00:00 2001 From: chmerdon Date: Thu, 23 Apr 2026 11:24:08 +0200 Subject: [PATCH 08/17] gridplots don't ignore xlimits and ylimits anymore, 1d plot only plots nodes if resolution is high enough, fixed text_color in 1d scalarplot, removed old padding code --- ext/GridVisualizeUnicodePlotsExt.jl | 52 ++++++++++++++++------------- 1 file changed, 29 insertions(+), 23 deletions(-) diff --git a/ext/GridVisualizeUnicodePlotsExt.jl b/ext/GridVisualizeUnicodePlotsExt.jl index fbc4fb3..b45f29f 100644 --- a/ext/GridVisualizeUnicodePlotsExt.jl +++ b/ext/GridVisualizeUnicodePlotsExt.jl @@ -61,8 +61,18 @@ function gridplot!(ctx, TP::Type{UnicodePlotsType}, ::Type{Val{2}}, grid) # find bounding box coords = grid[Coordinates] - ex = extrema(view(coords, 1, :)) - ey = extrema(view(coords, 2, :)) + xlimits = ctx[:xlimits] + ylimits = ctx[:ylimits] + if xlimits[1] < xlimits[2] + ex = xlimits + else + ex = extrema(view(coords, 1, :)) + end + if ylimits[1] < ylimits[2] + ey = ylimits + else + ey = extrema(view(coords, 2, :)) + end # line color for interior edges edge_color = UnicodePlots.ansi_color(:normal) @@ -70,8 +80,7 @@ function gridplot!(ctx, TP::Type{UnicodePlotsType}, ::Type{Val{2}}, grid) # determine resolution (divided by 10, to reduce pixel count in the terminal) layout = ctx[:layout] resolution = ctx[:size] ./ 12 ./ (layout[2], layout[1]) - legend_space = 0 - aspect = ctx[:aspect] * resolution[1] / (resolution[1] + legend_space) + aspect = ctx[:aspect] * resolution[1] / (resolution[1]) if (true) # auto scale feature, do we want this? wx = ex[2] - ex[1] @@ -88,14 +97,11 @@ function gridplot!(ctx, TP::Type{UnicodePlotsType}, ::Type{Val{2}}, grid) resolution = @. Int(round(resolution)) # create UnicodePlots.Canvas - 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 ? canvas = CanvasType( - resolution[2], resolution[1] + legend_space, # number of rows and columns (characters) + 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]) / (resolution[1] / (resolution[1] + legend_space)), width = ex[2] - ex[1]; blend = false + height = (ey[2] - ey[1]), width = ex[2] - ex[1]; blend = false ) linewidth = ctx[:linewidth] @@ -220,8 +226,6 @@ function gridplot!(ctx, TP::Type{UnicodePlotsType}, ::Type{Val{2}}, grid) region_legend!(plt, "regions", y0 + 3, bcolors) # 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[])) @@ -237,11 +241,15 @@ end function gridplot!(ctx, TP::Type{UnicodePlotsType}, ::Type{Val{1}}, grid) UnicodePlots = ctx[:Plotter] - text_color = UnicodePlots.ansi_color(:normal) # find bounding box + xlimits = ctx[:xlimits] coords = grid[Coordinates] - ex = extrema(view(coords, 1, :)) + if xlimits[1] < xlimits[2] + ex = xlimits + else + ex = extrema(view(coords, 1, :)) + end # determine resolution (divided by 5, to reduce pixel count in the terminal) ncellregions = num_cellregions(grid) @@ -250,12 +258,9 @@ function gridplot!(ctx, TP::Type{UnicodePlotsType}, ::Type{Val{1}}, grid) resolution = (Int(round(ctx[:size][1] / 6 / layout[2])), max(7, 5 + ncellregions + nbregions)) # create UnicodePlots.Canvas - 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( - resolution[2], resolution[1] + legend_space, # number of rows and columns (characters) + resolution[2], resolution[1], # number of rows and columns (characters) origin_y = 0, origin_x = ex[1], # position in virtual space height = 1, width = ex[2] - ex[1]; blend = false ) @@ -275,6 +280,12 @@ function gridplot!(ctx, TP::Type{UnicodePlotsType}, ::Type{Val{1}}, grid) cellgeoms = grid[CellGeometries] ncells = num_cells(grid) nnodes = num_nodes(grid) + text_color = UnicodePlots.ansi_color(:normal) + if nnodes < resolution[1] / 2 + for j in 1:nnodes + UnicodePlots.annotate!(canvas, coords[1, j], 0.5, "•", text_color, false) + end + end for j in 1:ncells cen = local_celledgenodes(cellgeoms[j]) r = cellregions[j] @@ -287,9 +298,6 @@ function gridplot!(ctx, TP::Type{UnicodePlotsType}, ::Type{Val{1}}, grid) ) end end - for j in 1:nnodes - UnicodePlots.annotate!(canvas, coords[1, j], 0.5, "•", text_color, false) - end # plot boundary nodes with bregion_cmap colors bcmap = bregion_cmap(nbregions) @@ -307,7 +315,7 @@ 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.5, "•", UInt32(uint_color), false) + UnicodePlots.annotate!(canvas, coords[1, bfacenodes[1, j]], 0.5, "•", uint_color, false) end plt = UnicodePlots.Plot(canvas; title = ctx[:title], border = ctx[:border]) @@ -319,7 +327,6 @@ function gridplot!(ctx, TP::Type{UnicodePlotsType}, ::Type{Val{1}}, grid) # corner coordinates - ex = extrema(view(coords, 1, :)) 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[])) @@ -384,7 +391,6 @@ function scalarplot!( color = ctx[:color] end - for ifunc in 1:nfuncs func = funcs[ifunc] grid = grids[ifunc] From 9b457e86215bbd8c4bdf237cf794531577b57483 Mon Sep 17 00:00:00 2001 From: chmerdon Date: Thu, 23 Apr 2026 16:30:50 +0200 Subject: [PATCH 09/17] fixed spacing of vector samples --- ext/GridVisualizeUnicodePlotsExt.jl | 30 ++++++++++++++++++++--------- src/common.jl | 2 +- 2 files changed, 22 insertions(+), 10 deletions(-) diff --git a/ext/GridVisualizeUnicodePlotsExt.jl b/ext/GridVisualizeUnicodePlotsExt.jl index b45f29f..99061dd 100644 --- a/ext/GridVisualizeUnicodePlotsExt.jl +++ b/ext/GridVisualizeUnicodePlotsExt.jl @@ -80,7 +80,7 @@ function gridplot!(ctx, TP::Type{UnicodePlotsType}, ::Type{Val{2}}, grid) # determine resolution (divided by 10, to reduce pixel count in the terminal) layout = ctx[:layout] resolution = ctx[:size] ./ 12 ./ (layout[2], layout[1]) - aspect = ctx[:aspect] * resolution[1] / (resolution[1]) + aspect = ctx[:aspect] if (true) # auto scale feature, do we want this? wx = ex[2] - ex[1] @@ -96,6 +96,11 @@ function gridplot!(ctx, TP::Type{UnicodePlotsType}, ::Type{Val{2}}, grid) # we need an integer resolution resolution = @. Int(round(resolution)) + # ensure that legend fits + ncellregions = num_cellregions(grid) + nbregions = num_bfaceregions(grid) + resolution = (resolution[1], max(resolution[2], 5 + ncellregions + nbregions)) + # create UnicodePlots.Canvas CanvasType = UnicodePlots.BrailleCanvas # should this be a changeable parameter ? canvas = CanvasType( @@ -141,7 +146,6 @@ function gridplot!(ctx, TP::Type{UnicodePlotsType}, ::Type{Val{2}}, grid) # color cell midpoints with cell regions color cellregions = grid[CellRegions] - ncellregions = num_cellregions(grid) cmap = region_cmap(max(2, ncellregions)) ctx[:cmap] = cmap cell_colors = [ @@ -192,7 +196,6 @@ function gridplot!(ctx, TP::Type{UnicodePlotsType}, ::Type{Val{2}}, grid) end # plot boundary faces with bregion_cmap colors - nbregions = num_bfaceregions(grid) bcmap = bregion_cmap(nbregions) ctx[:bcmap] = bcmap bcolors = [ @@ -504,10 +507,19 @@ function vectorplot!(ctx, TP::Type{UnicodePlotsType}, ::Type{Val{2}}, grid, func # find bounding box coords = grid[Coordinates] - ex = extrema(view(coords, 1, :)) - ey = extrema(view(coords, 2, :)) - - aspect = ctx[:aspect] * resolution[1] / resolution[1] + xlimits = ctx[:xlimits] + ylimits = ctx[:ylimits] + if xlimits[1] < xlimits[2] + ex = xlimits + else + ex = extrema(view(coords, 1, :)) + end + if ylimits[1] < ylimits[2] + ey = ylimits + else + ey = extrema(view(coords, 2, :)) + end + aspect = ctx[:aspect] if (true) # auto scale feature, do we want this? wx = ex[2] - ex[1] @@ -522,9 +534,10 @@ function vectorplot!(ctx, TP::Type{UnicodePlotsType}, ::Type{Val{2}}, grid, func # we need an integer resolution resolution = @. Int(round(resolution)) + @info 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]) + rc, rv = vectorsample(grid, func; gridscale = ctx[:gridscale], rasterpoints = ((resolution[1] - 1) / 2, resolution[2] - 1), offset = ctx[:offset], xlimits = ex, ylimits = ey) qc, qv = quiverdata(rc, rv; vscale = ctx[:vscale], vnormalize = ctx[:vnormalize], vconstant = ctx[:vconstant]) # construct canvas @@ -536,7 +549,6 @@ function vectorplot!(ctx, TP::Type{UnicodePlotsType}, ::Type{Val{2}}, grid, func ) # plot arrows - scale = minimum(resolution) / maximum(ctx[:rasterpoints]) / 300 narrows = size(qv, 2) vscale = ctx[:vscale] # vscale steers arrow thickness if vscale <= 0.25 diff --git a/src/common.jl b/src/common.jl index 4bfa21c..0d0a949 100644 --- a/src/common.jl +++ b/src/common.jl @@ -257,7 +257,7 @@ function vectorsample( tol = reltol * extent # point spacing - spacing = [extent / rasterpoints[i] for i in 1:dim] + spacing = [(cminmax[i][2] - cminmax[i][1]) / rasterpoints[i] for i in 1:dim] # index range ijkmax = ones(Int, 3) From 00a46a1bbaa355ceab4796ecbe4b77d252088ad2 Mon Sep 17 00:00:00 2001 From: chmerdon Date: Fri, 24 Apr 2026 09:00:39 +0200 Subject: [PATCH 10/17] vectorplot selects arrow thickness based on norm --- ext/GridVisualizeUnicodePlotsExt.jl | 69 ++++++++++++++++------------- 1 file changed, 39 insertions(+), 30 deletions(-) diff --git a/ext/GridVisualizeUnicodePlotsExt.jl b/ext/GridVisualizeUnicodePlotsExt.jl index 99061dd..fc36694 100644 --- a/ext/GridVisualizeUnicodePlotsExt.jl +++ b/ext/GridVisualizeUnicodePlotsExt.jl @@ -500,6 +500,44 @@ end scalarplot!(ctx, TP::Type{UnicodePlotsType}, ::Type{Val{3}}, grids, parentgrid, funcs) = @warn "3D scalarplot is not implemented for the UnicodePlots backend" +arrows_thin = ['↙', '↓', '↘', '→', '↗', '↑', '↖', '←'] +arrows_medium = ['🡯', '🡫', '🡮', '🡪', '🡭', '🡩', '🡬', '🡨'] +arrows_thick = ['🡷', '🡳', '🡶', '🡲', '🡵', '🡱', '🡴', '🡰'] +arrows_max = ['🢇', '🢃', '🢆', '🢂', '🢅', '🢁', '🢄', '🢀'] + +function select_arrow(angle, norm, scale) + if norm * scale < 1.0e-2 + return '•' # use a dot for very small vectors + end + if angle > -7 * π / 8 && angle <= -5 * π / 8 + a = 1 + elseif angle > -5 * π / 8 && angle <= -3 * π / 8 + a = 2 + elseif angle > -3 * π / 8 && angle <= -π / 8 + a = 3 + elseif angle > -π / 8 && angle <= π / 8 + a = 4 + elseif angle > π / 8 && angle <= 3 * π / 8 + a = 5 + elseif angle > 3 * π / 8 && angle <= 5 * π / 8 + a = 6 + elseif angle > 5 * π / 8 && angle <= 7 * π / 8 + a = 7 + else + a = 8 + end + if norm * scale <= 0.25 + return arrows_thin[a] + elseif norm * scale <= 0.5 + return arrows_medium[a] + elseif norm * scale <= 0.75 + return arrows_thick[a] + else + return arrows_max[a] + end +end + + function vectorplot!(ctx, TP::Type{UnicodePlotsType}, ::Type{Val{2}}, grid, func) layout = ctx[:layout] @@ -534,7 +572,6 @@ function vectorplot!(ctx, TP::Type{UnicodePlotsType}, ::Type{Val{2}}, grid, func # we need an integer resolution resolution = @. Int(round(resolution)) - @info resolution # query vector field raster points rc, rv = vectorsample(grid, func; gridscale = ctx[:gridscale], rasterpoints = ((resolution[1] - 1) / 2, resolution[2] - 1), offset = ctx[:offset], xlimits = ex, ylimits = ey) @@ -551,15 +588,6 @@ function vectorplot!(ctx, TP::Type{UnicodePlotsType}, ::Type{Val{2}}, grid, func # plot arrows 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 @@ -568,26 +596,7 @@ function vectorplot!(ctx, TP::Type{UnicodePlotsType}, ::Type{Val{2}}, grid, func 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 + char = select_arrow(angle, anorm / maxnorm, vscale) UnicodePlots.annotate!(canvas, qc[1, a], qc[2, a], char, uint_color, false) end From f913861e8007888dee34983a121c4152f495e3e5 Mon Sep 17 00:00:00 2001 From: chmerdon Date: Fri, 24 Apr 2026 09:13:26 +0200 Subject: [PATCH 11/17] one more thickness level for unicode arrows in vectorplot --- ext/GridVisualizeUnicodePlotsExt.jl | 19 +++++++++++-------- 1 file changed, 11 insertions(+), 8 deletions(-) diff --git a/ext/GridVisualizeUnicodePlotsExt.jl b/ext/GridVisualizeUnicodePlotsExt.jl index fc36694..db30994 100644 --- a/ext/GridVisualizeUnicodePlotsExt.jl +++ b/ext/GridVisualizeUnicodePlotsExt.jl @@ -500,10 +500,11 @@ end scalarplot!(ctx, TP::Type{UnicodePlotsType}, ::Type{Val{3}}, grids, parentgrid, funcs) = @warn "3D scalarplot is not implemented for the UnicodePlots backend" -arrows_thin = ['↙', '↓', '↘', '→', '↗', '↑', '↖', '←'] -arrows_medium = ['🡯', '🡫', '🡮', '🡪', '🡭', '🡩', '🡬', '🡨'] -arrows_thick = ['🡷', '🡳', '🡶', '🡲', '🡵', '🡱', '🡴', '🡰'] -arrows_max = ['🢇', '🢃', '🢆', '🢂', '🢅', '🢁', '🢄', '🢀'] +arrows_verythin = ['↙', '↓', '↘', '→', '↗', '↑', '↖', '←'] +arrows_thin = ['🡯', '🡫', '🡮', '🡪', '🡭', '🡩', '🡬', '🡨'] +arrows_medium = ['🡷', '🡳', '🡶', '🡲', '🡵', '🡱', '🡴', '🡰'] +arrows_thick = ['🡿', '🡻', '🡾', '🡺', '🡽', '🡹', '🡼', '🡸'] +arrows_verythick = ['🢇', '🢃', '🢆', '🢂', '🢅', '🢁', '🢄', '🢀'] function select_arrow(angle, norm, scale) if norm * scale < 1.0e-2 @@ -526,14 +527,16 @@ function select_arrow(angle, norm, scale) else a = 8 end - if norm * scale <= 0.25 + if norm * scale <= 0.2 + return arrows_verythin[a] + elseif norm * scale <= 0.4 return arrows_thin[a] - elseif norm * scale <= 0.5 + elseif norm * scale <= 0.6 return arrows_medium[a] - elseif norm * scale <= 0.75 + elseif norm * scale <= 0.8 return arrows_thick[a] else - return arrows_max[a] + return arrows_verythick[a] end end From 863974ad6bcd893ab27f37605ffa548fe935f0f4 Mon Sep 17 00:00:00 2001 From: chmerdon Date: Fri, 24 Apr 2026 10:20:59 +0200 Subject: [PATCH 12/17] solved some scaling issues, use nice_repr for coordinate limit labels --- ext/GridVisualizeUnicodePlotsExt.jl | 61 ++++++++++++++++++----------- 1 file changed, 39 insertions(+), 22 deletions(-) diff --git a/ext/GridVisualizeUnicodePlotsExt.jl b/ext/GridVisualizeUnicodePlotsExt.jl index db30994..2483583 100644 --- a/ext/GridVisualizeUnicodePlotsExt.jl +++ b/ext/GridVisualizeUnicodePlotsExt.jl @@ -229,12 +229,12 @@ function gridplot!(ctx, TP::Type{UnicodePlotsType}, ::Type{Val{2}}, grid) region_legend!(plt, "regions", y0 + 3, bcolors) # corner coordinates - 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[])) + UnicodePlots.label!(plt, :b, ctx[:xlabel]) + UnicodePlots.label!(plt, :bl, UnicodePlots.nice_repr(ex[1], plt), UnicodePlots.ansi_color(UnicodePlots.BORDER_COLOR[])) + UnicodePlots.label!(plt, :br, UnicodePlots.nice_repr(ex[2], plt), UnicodePlots.ansi_color(UnicodePlots.BORDER_COLOR[])) + UnicodePlots.label!(plt, :l, 1, UnicodePlots.nice_repr(ey[2], plt), UnicodePlots.ansi_color(UnicodePlots.BORDER_COLOR[])) + UnicodePlots.label!(plt, :l, round(Int, (resolution[2] + 1) / 2), ctx[:ylabel]) + UnicodePlots.label!(plt, :l, resolution[2], UnicodePlots.nice_repr(ey[1], plt), UnicodePlots.ansi_color(UnicodePlots.BORDER_COLOR[])) # plot ctx[:figure] = plt @@ -331,7 +331,7 @@ function gridplot!(ctx, TP::Type{UnicodePlotsType}, ::Type{Val{1}}, grid) # corner coordinates UnicodePlots.label!(plt, :bl, string(Float16(ex[1])), UnicodePlots.ansi_color(UnicodePlots.BORDER_COLOR[])) - UnicodePlots.label!(plt, :b, "x") + UnicodePlots.label!(plt, :b, ctx[:xlabel]) UnicodePlots.label!(plt, :br, string(Float16(ex[2])), UnicodePlots.ansi_color(UnicodePlots.BORDER_COLOR[])) # plot @@ -352,9 +352,10 @@ function scalarplot!( nfuncs = length(funcs) 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] + resolution = @. Int(round(ctx[:size] ./ (12, 6) ./ (layout[2], 4 * layout[1]))) # reduce pixel count in the terminal (size is then compatible to other plots) + @info resolution + ylim = ctx[:limits] if ylim[1] > ylim[2] # try to find limits automatically ylim = (minimum([minimum(func) for func in funcs]), maximum([maximum(func) for func in funcs])) @@ -409,6 +410,7 @@ function scalarplot!( xscale, yscale, xlabel = String(ctx[:xlabel]), + ylabel = ctx[:ylabel], name, height = resolution[2], width = resolution[1], @@ -426,6 +428,7 @@ function scalarplot!( ) end end + ctx[:figure] = plt return reveal(ctx, TP) @@ -443,7 +446,7 @@ function scalarplot!( func = funcs[1] layout = ctx[:layout] - resolution = ctx[:size] ./ 6 ./ (layout[2], layout[1]) # reduce pixel count in the terminal + resolution = ctx[:size] ./ (12, 6) ./ (layout[2], layout[1]) # reduce pixel count in the terminal ylim = ctx[:limits] colormap = ctx[:colormap] @@ -456,14 +459,15 @@ function scalarplot!( ex = extrema(view(coords, 1, :)) ey = extrema(view(coords, 2, :)) + aspect = ctx[:aspect] 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) + resolution = (resolution[1] * aspect, Int(ceil(resolution[2] / rescale))) else - resolution = (resolution[1] / rescale, resolution[2]) + resolution = (Int(ceil(resolution[1] * aspect / rescale)), resolution[2]) end end @@ -478,10 +482,10 @@ function scalarplot!( I = zeros(Float64, num_nodes(xgrid_plot)) interpolate!(I, xgrid_plot, func, grids[1]; eps = 1.0e-14, not_in_domain_value = NaN, trybrute = true) - ctx[:figure] = UnicodePlots.heatmap( + plt = UnicodePlots.heatmap( reshape(I, (resolution[1], resolution[2]))', - xlabel = "x", - ylabel = "y", + xlabel = ctx[:xlabel], + ylabel = ctx[:ylabel], xfact = (ex[2] - ex[1]) / (resolution[1] - 1), yfact = (ey[2] - ey[1]) / (resolution[2] - 1), xoffset = ex[1], @@ -495,17 +499,22 @@ function scalarplot!( border = ctx[:border] ) + ctx[:figure] = plt + 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" + +# unicode arrows for vector plot arrows_verythin = ['↙', '↓', '↘', '→', '↗', '↑', '↖', '←'] arrows_thin = ['🡯', '🡫', '🡮', '🡪', '🡭', '🡩', '🡬', '🡨'] arrows_medium = ['🡷', '🡳', '🡶', '🡲', '🡵', '🡱', '🡴', '🡰'] arrows_thick = ['🡿', '🡻', '🡾', '🡺', '🡽', '🡹', '🡼', '🡸'] arrows_verythick = ['🢇', '🢃', '🢆', '🢂', '🢅', '🢁', '🢄', '🢀'] +# helper function that selects the right arrow for a given vector direction and norm function select_arrow(angle, norm, scale) if norm * scale < 1.0e-2 return '•' # use a dot for very small vectors @@ -605,7 +614,17 @@ function vectorplot!(ctx, TP::Type{UnicodePlotsType}, ::Type{Val{2}}, grid, func end # generate plot - plt = UnicodePlots.Plot(canvas; title = ctx[:title], border = ctx[:border]) + plt = UnicodePlots.Plot( + canvas; title = ctx[:title], border = ctx[:border], + xfact = (ex[2] - ex[1]) / (resolution[1] - 1), + yfact = (ey[2] - ey[1]) / (resolution[2] - 1), + xlabel = ctx[:xlabel], + ylabel = ctx[:ylabel], + xoffset = ex[1], + yoffset = ey[1], + compact_labels = false, + labels = true + ) # add colormap plt.cmap.bar = ctx[:colorbar] == :none ? false : true @@ -615,12 +634,10 @@ function vectorplot!(ctx, TP::Type{UnicodePlotsType}, ::Type{Val{2}}, grid, func # 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[])) + UnicodePlots.label!(plt, :bl, UnicodePlots.nice_repr(ex[1], plt), UnicodePlots.ansi_color(UnicodePlots.BORDER_COLOR[])) + UnicodePlots.label!(plt, :br, UnicodePlots.nice_repr(ex[2], plt), UnicodePlots.ansi_color(UnicodePlots.BORDER_COLOR[])) + UnicodePlots.label!(plt, :l, 1, UnicodePlots.nice_repr(ey[2], plt), UnicodePlots.ansi_color(UnicodePlots.BORDER_COLOR[])) + UnicodePlots.label!(plt, :l, resolution[2], UnicodePlots.nice_repr(ey[1], plt), UnicodePlots.ansi_color(UnicodePlots.BORDER_COLOR[])) ctx[:figure] = plt From 507074db6c996ea26fdd74cff1d448adb20bf828 Mon Sep 17 00:00:00 2001 From: chmerdon Date: Fri, 24 Apr 2026 10:42:32 +0200 Subject: [PATCH 13/17] fixed scaling of 1d scalarplot again, removed info --- ext/GridVisualizeUnicodePlotsExt.jl | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/ext/GridVisualizeUnicodePlotsExt.jl b/ext/GridVisualizeUnicodePlotsExt.jl index 2483583..161d658 100644 --- a/ext/GridVisualizeUnicodePlotsExt.jl +++ b/ext/GridVisualizeUnicodePlotsExt.jl @@ -352,8 +352,7 @@ function scalarplot!( nfuncs = length(funcs) layout = ctx[:layout] - resolution = @. Int(round(ctx[:size] ./ (12, 6) ./ (layout[2], 4 * layout[1]))) # reduce pixel count in the terminal (size is then compatible to other plots) - @info resolution + resolution = @. Int(round(ctx[:size] ./ 6 ./ (layout[2], 2 * layout[1]))) # reduce pixel count in the terminal (size is then compatible to other plots) ylim = ctx[:limits] if ylim[1] > ylim[2] From ce9cf168da89e604384d371846137a9c4999d3f3 Mon Sep 17 00:00:00 2001 From: chmerdon Date: Fri, 24 Apr 2026 12:49:28 +0200 Subject: [PATCH 14/17] 2d scalarplot shows isolines when levels is an array and respects colorlevels --- ext/GridVisualizeUnicodePlotsExt.jl | 26 +++++++++++++++++++++++++- 1 file changed, 25 insertions(+), 1 deletion(-) diff --git a/ext/GridVisualizeUnicodePlotsExt.jl b/ext/GridVisualizeUnicodePlotsExt.jl index 161d658..f9ccaf7 100644 --- a/ext/GridVisualizeUnicodePlotsExt.jl +++ b/ext/GridVisualizeUnicodePlotsExt.jl @@ -6,7 +6,8 @@ Extension module for UnicodePlots.jl module GridVisualizeUnicodePlotsExt import GridVisualize: initialize!, gridplot!, scalarplot!, vectorplot!, bregion_cmap, region_cmap, reveal, streamplot! -using GridVisualize: UnicodePlotsType, GridVisualizer, SubVisualizer, vectorsample, quiverdata +using GridVisualize: UnicodePlotsType, GridVisualizer, SubVisualizer, vectorsample, quiverdata, isolevels +using GridVisualizeTools: marching_triangles 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, red, green, blue @@ -481,6 +482,9 @@ function scalarplot!( I = zeros(Float64, num_nodes(xgrid_plot)) interpolate!(I, xgrid_plot, func, grids[1]; eps = 1.0e-14, not_in_domain_value = NaN, trybrute = true) + # adjust colormap to desired number of colorlevels + colormap = get(colorschemes[ctx[:colormap]], range(0.0, 1.0, length = max(2, 1 + ctx[:colorlevels]))) + plt = UnicodePlots.heatmap( reshape(I, (resolution[1], resolution[2]))', xlabel = ctx[:xlabel], @@ -498,6 +502,26 @@ function scalarplot!( border = ctx[:border] ) + # isolines (only when given as an array) + if typeof(ctx[:levels]) <: AbstractArray + levels, ~, ~ = isolevels(ctx, funcs) + points = marching_triangles(grids[1], func, levels; gridscale = 1.0) + if typeof(ctx[:color]) <: String || typeof(ctx[:color]) <: Symbol + color = UnicodePlots.ansi_color(Symbol(ctx[:color])) + elseif typeof(ctx[:color]) <: RGB + color = ( + Int(round(ctx[:color].r * 255)), + Int(round(ctx[:color].g * 255)), + Int(round(ctx[:color].b * 255)), + ) + else + color = ctx[:color] + end + for j in 1:2:(length(points) - 1) + UnicodePlots.lineplot!(plt, [points[j][1], points[j + 1][1]], [points[j][2], points[j + 1][2]], color = color) + end + end + ctx[:figure] = plt return reveal(ctx, TP) From b63ae67ed7a557ecc2e9ad3556f4cc3cfd0a1f8e Mon Sep 17 00:00:00 2001 From: chmerdon Date: Fri, 24 Apr 2026 14:37:39 +0200 Subject: [PATCH 15/17] fixed auto resizing --- ext/GridVisualizeUnicodePlotsExt.jl | 18 +++++++++--------- 1 file changed, 9 insertions(+), 9 deletions(-) diff --git a/ext/GridVisualizeUnicodePlotsExt.jl b/ext/GridVisualizeUnicodePlotsExt.jl index f9ccaf7..f27e447 100644 --- a/ext/GridVisualizeUnicodePlotsExt.jl +++ b/ext/GridVisualizeUnicodePlotsExt.jl @@ -80,13 +80,13 @@ function gridplot!(ctx, TP::Type{UnicodePlotsType}, ::Type{Val{2}}, grid) # determine resolution (divided by 10, to reduce pixel count in the terminal) layout = ctx[:layout] - resolution = ctx[:size] ./ 12 ./ (layout[2], layout[1]) + resolution = ctx[:size] ./ 12 ./ (layout[2], 2 * layout[1]) aspect = ctx[:aspect] 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])) + wy = (ey[2] - ey[1]) * 2 + rescale = wx / wy * (resolution[1] / resolution[2]) if rescale > 1 resolution = (resolution[1] * aspect, Int(ceil(resolution[2] / rescale))) else @@ -446,7 +446,7 @@ function scalarplot!( func = funcs[1] layout = ctx[:layout] - resolution = ctx[:size] ./ (12, 6) ./ (layout[2], layout[1]) # reduce pixel count in the terminal + resolution = ctx[:size] ./ 12 ./ (layout[2], layout[1]) # reduce pixel count in the terminal ylim = ctx[:limits] colormap = ctx[:colormap] @@ -462,8 +462,8 @@ function scalarplot!( aspect = ctx[:aspect] 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])) + wy = (ey[2] - ey[1]) + rescale = wx / wy * (resolution[1] / resolution[2]) if rescale > 1 resolution = (resolution[1] * aspect, Int(ceil(resolution[2] / rescale))) else @@ -576,7 +576,7 @@ end 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 + resolution = ctx[:size] ./ 12 ./ (layout[2], 2 * layout[1]) # reduce pixel count in the terminal # find bounding box coords = grid[Coordinates] @@ -596,8 +596,8 @@ function vectorplot!(ctx, TP::Type{UnicodePlotsType}, ::Type{Val{2}}, grid, func 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])) + wy = (ey[2] - ey[1]) * 2 + rescale = wx / wy * (resolution[1] / resolution[2]) if rescale > 1 resolution = (resolution[1] * aspect, Int(ceil(resolution[2] / rescale))) else From 41f0f2b8fd84980cafcb9319798f475703e69679 Mon Sep 17 00:00:00 2001 From: chmerdon Date: Fri, 24 Apr 2026 14:40:26 +0200 Subject: [PATCH 16/17] last commit missed 1d scalarplot --- ext/GridVisualizeUnicodePlotsExt.jl | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/ext/GridVisualizeUnicodePlotsExt.jl b/ext/GridVisualizeUnicodePlotsExt.jl index f27e447..fe8972e 100644 --- a/ext/GridVisualizeUnicodePlotsExt.jl +++ b/ext/GridVisualizeUnicodePlotsExt.jl @@ -353,7 +353,7 @@ function scalarplot!( nfuncs = length(funcs) layout = ctx[:layout] - resolution = @. Int(round(ctx[:size] ./ 6 ./ (layout[2], 2 * layout[1]))) # reduce pixel count in the terminal (size is then compatible to other plots) + resolution = @. Int(round(ctx[:size] ./ 12 ./ (layout[2], 2 * layout[1]))) # reduce pixel count in the terminal (size is then compatible to other plots) ylim = ctx[:limits] if ylim[1] > ylim[2] From 55d98ff05d0c793e20c6c434f22cd0e0d0761c27 Mon Sep 17 00:00:00 2001 From: chmerdon Date: Fri, 24 Apr 2026 16:19:45 +0200 Subject: [PATCH 17/17] fixed rescaling again --- ext/GridVisualizeUnicodePlotsExt.jl | 53 +++++++++++------------------ 1 file changed, 20 insertions(+), 33 deletions(-) diff --git a/ext/GridVisualizeUnicodePlotsExt.jl b/ext/GridVisualizeUnicodePlotsExt.jl index fe8972e..35f14b1 100644 --- a/ext/GridVisualizeUnicodePlotsExt.jl +++ b/ext/GridVisualizeUnicodePlotsExt.jl @@ -80,19 +80,14 @@ function gridplot!(ctx, TP::Type{UnicodePlotsType}, ::Type{Val{2}}, grid) # determine resolution (divided by 10, to reduce pixel count in the terminal) layout = ctx[:layout] - resolution = ctx[:size] ./ 12 ./ (layout[2], 2 * layout[1]) + resolution = ctx[:size] ./ (48, 24) ./ (layout[2], layout[1]) aspect = ctx[:aspect] - if (true) # auto scale feature, do we want this? - wx = ex[2] - ex[1] - wy = (ey[2] - ey[1]) * 2 - rescale = wx / wy * (resolution[1] / 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 + # rescale resolution + wx = ex[2] - ex[1] + wy = ey[2] - ey[1] + rescale = 2 * wx / wy * (resolution[2] / (resolution[1])) / aspect + resolution = (resolution[1] * rescale, resolution[2]) # we need an integer resolution resolution = @. Int(round(resolution)) @@ -259,7 +254,7 @@ function gridplot!(ctx, TP::Type{UnicodePlotsType}, ::Type{Val{1}}, grid) 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)) + resolution = (Int(round(ctx[:size][1] / 12 / layout[2])), max(7, 5 + ncellregions + nbregions)) # create UnicodePlots.Canvas CanvasType = UnicodePlots.BrailleCanvas # should this be a changeable parameter ? @@ -460,16 +455,12 @@ function scalarplot!( ey = extrema(view(coords, 2, :)) aspect = ctx[:aspect] - 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] * aspect, Int(ceil(resolution[2] / rescale))) - else - resolution = (Int(ceil(resolution[1] * aspect / rescale)), resolution[2]) - end - end + + # rescale resolution + wx = ex[2] - ex[1] + wy = ey[2] - ey[1] + rescale = wx / wy * (resolution[2] / (resolution[1])) / aspect + resolution = (resolution[1] * rescale, resolution[2]) # we need an integer resolution resolution = @. Int(round(resolution)) @@ -576,7 +567,7 @@ end function vectorplot!(ctx, TP::Type{UnicodePlotsType}, ::Type{Val{2}}, grid, func) layout = ctx[:layout] - resolution = ctx[:size] ./ 12 ./ (layout[2], 2 * layout[1]) # reduce pixel count in the terminal + resolution = ctx[:size] ./ (48, 24) ./ (layout[2], layout[1]) # find bounding box coords = grid[Coordinates] @@ -592,18 +583,14 @@ function vectorplot!(ctx, TP::Type{UnicodePlotsType}, ::Type{Val{2}}, grid, func else ey = extrema(view(coords, 2, :)) end + aspect = ctx[:aspect] - if (true) # auto scale feature, do we want this? - wx = ex[2] - ex[1] - wy = (ey[2] - ey[1]) * 2 - rescale = wx / wy * (resolution[1] / 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 + # rescale resolution + wx = ex[2] - ex[1] + wy = ey[2] - ey[1] + rescale = 2 * wx / wy * (resolution[2] / (resolution[1])) / aspect + resolution = (resolution[1] * rescale, resolution[2]) # we need an integer resolution resolution = @. Int(round(resolution))