Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
11 changes: 7 additions & 4 deletions docs/src/dev.md
Original file line number Diff line number Diff line change
Expand Up @@ -33,19 +33,22 @@ Plot(canvas)
The following types of `Canvas` are implemented:

- **BrailleCanvas**:
This type of canvas is probably the one with the highest resolution for `Unicode` plotting. It essentially uses the Unicode characters of the [Braille](https://en.wikipedia.org/wiki/Braille) symbols as pixels. This effectively turns every character into eight pixels that can individually be manipulated using binary operations.
This type of canvas is probably one of the two with the highest resolution for `Unicode` plotting. It essentially uses the Unicode characters of the [Braille](https://en.wikipedia.org/wiki/Braille) symbols as pixels. This effectively turns every character into eight pixels that can individually be manipulated using binary operations.

- **OctantCanvas**:
This type of canvas is the other with the highest resolution for `Unicode` plotting. It essentially uses the Unicode characters of the [octant](https://unicode.org/charts/PDF/Unicode-16.0/U160-1CC00.pdf) symbols as pixels. This effectively turns every character into eight pixels that can individually be manipulated using binary operations. `Unicode` octants require support for Unicode 16 which was released in 2024. Some terminal emulators draw these characters directly, others use a font for rendering. If neither supports it then this canvas will not work. If `OctantCanvas` is working, then it should look similar to `BrailleCanvas`.

- **BlockCanvas**:
This canvas is also `Unicode` based. It has half the resolution of the BrailleCanvas. In contrast to `BrailleCanvas`, the pixels don't have visible spacing between them. This canvas effectively turns every character into four pixels that can individually be manipulated using binary operations.
This canvas is also `Unicode` based. It has half the resolution of the `BrailleCanvas` or `OctantCanvas`. In contrast to `BrailleCanvas`, the pixels don't have visible spacing between them. This canvas effectively turns every character into four pixels that can individually be manipulated using binary operations.

- **HeatmapCanvas**:
This canvas is also `Unicode` based. It has half the resolution of the `BlockCanvas`. This canvas effectively turns every character into two color pixels, using the foreground and background terminal colors. As such, the number of rows of the canvas is half the number of `y` coordinates being displayed.
This canvas is also `Unicode` based. It has half the resolution of the `BlockCanvas` or `OctantCanvas`. This canvas effectively turns every character into two color pixels, using the foreground and background terminal colors. As such, the number of rows of the canvas is half the number of `y` coordinates being displayed.

- **AsciiCanvas** and **DotCanvas**:
These two canvas utilizes only standard `ASCII` character for drawing. Naturally, it doesn't look quite as nice as the Unicode-based ones. However, in some situations it might yield better results. Printing plots to a file is one of those situations.

- **DensityCanvas**:
Unlike the `BrailleCanvas`, the density canvas does not simply mark a "pixel" as set. Instead it increments a counter per character that keeps track of the frequency of pixels drawn in that character. Together with a variable that keeps track of the maximum frequency, the canvas can thus draw the density of data-points.
Unlike the `BrailleCanvas` or `OctantCanvas`, the density canvas does not simply mark a "pixel" as set. Instead it increments a counter per character that keeps track of the frequency of pixels drawn in that character. Together with a variable that keeps track of the maximum frequency, the canvas can thus draw the density of data-points.

- **BarplotGraphics**:
This graphics area is special in that it does not support any pixel manipulation. It is essentially the barplot without decorations but the numbers. It does only support one method `addrow!` which allows the user to add additional bars to the graphics object.
Expand Down
2 changes: 1 addition & 1 deletion docs/src/index.md
Original file line number Diff line number Diff line change
Expand Up @@ -22,7 +22,7 @@ lineplot([-1, 2, 3, 7], [-1, 2, 9, 4], title="Example", name="my line", xlabel="

There are other types of `Canvas` available (see section [Low-level Interface](https://github.com/JuliaPlots/UnicodePlots.jl#low-level-interface)).

In some situations, such as printing to a file, using `AsciiCanvas`, `DotCanvas` or `BlockCanvas` might lead to better results:
In some situations, such as printing to a file, using `AsciiCanvas`, `DotCanvas`, `BlockCanvas` or `OctantCanvas` might lead to better results:

```@example intro
plt = lineplot([-1, 2, 3, 7], [-1, 2, 9, 4], title="Example", name="my line",
Expand Down
2 changes: 2 additions & 0 deletions src/UnicodePlots.jl
Original file line number Diff line number Diff line change
Expand Up @@ -23,6 +23,7 @@ export Plot,
BoxplotGraphics,
GraphicsArea,
BrailleCanvas,
OctantCanvas,
DensityCanvas,
HeatmapCanvas,
BlockCanvas,
Expand Down Expand Up @@ -84,6 +85,7 @@ include("graphics/imagegraphics.jl")
include("canvas.jl")
include("canvas/lookupcanvas.jl")
include("canvas/braillecanvas.jl")
include("canvas/octantcanvas.jl")
include("canvas/densitycanvas.jl")
include("canvas/blockcanvas.jl")
include("canvas/asciicanvas.jl")
Expand Down
306 changes: 306 additions & 0 deletions src/canvas/octantcanvas.jl
Original file line number Diff line number Diff line change
@@ -0,0 +1,306 @@
"""
The `OctantCanvas` is also Unicode-based.
It has the same resolution as `BrailleCanvas`.
In contrast to BrailleCanvas, the pixels don't have visible spacing between them.
This canvas effectively turns every character into eight pixels that can individually be manipulated using binary operations.
"""
struct OctantCanvas{YS <: Function, XS <: Function} <: LookupCanvas
grid::Transpose{UInt16, Matrix{UInt16}}
colors::Transpose{ColorType, Matrix{ColorType}}
visible::Bool
blend::Bool
yflip::Bool
xflip::Bool
pixel_height::Int
pixel_width::Int
origin_y::Float64
origin_x::Float64
height::Float64
width::Float64
min_max::NTuple{2, UnicodeType}
yscale::YS
xscale::XS
end

const OCTANT_SIGNS = [
0b00000001 0b00000010
0b00000100 0b00001000
0b00010000 0b00100000
0b01000000 0b10000000
]

const N_OCTANT = grid_type(OctantCanvas)(256)

# The array is stored according to the octant bit pattern:
# 0 1
# 2 3
# 4 5
# 6 7
const OCTANT_DECODE = Char[
0x000000A0, # NO-BREAK SPACE
0x0001CEA8, # LEFT HALF UPPER ONE QUARTER BLOCK
0x0001CEAB, # RIGHT HALF UPPER ONE QUARTER BLOCK
0x0001FB82, # UPPER ONE QUARTER BLOCK
0x0001CD00, # BLOCK OCTANT-3
0x00002598, # QUADRANT UPPER LEFT
0x0001CD01, # BLOCK OCTANT-23
0x0001CD02, # BLOCK OCTANT-123
0x0001CD03, # BLOCK OCTANT-4
0x0001CD04, # BLOCK OCTANT-14
0x0000259D, # QUADRANT UPPER RIGHT
0x0001CD05, # BLOCK OCTANT-124
0x0001CD06, # BLOCK OCTANT-34
0x0001CD07, # BLOCK OCTANT-134
0x0001CD08, # BLOCK OCTANT-234
0x00002580, # UPPER HALF BLOCK
0x0001CD09, # BLOCK OCTANT-5
0x0001CD0A, # BLOCK OCTANT-15
0x0001CD0B, # BLOCK OCTANT-25
0x0001CD0C, # BLOCK OCTANT-125
0x0001FBE6, # MIDDLE LEFT ONE QUARTER BLOCK
0x0001CD0D, # BLOCK OCTANT-135
0x0001CD0E, # BLOCK OCTANT-235
0x0001CD0F, # BLOCK OCTANT-1235
0x0001CD10, # BLOCK OCTANT-45
0x0001CD11, # BLOCK OCTANT-145
0x0001CD12, # BLOCK OCTANT-245
0x0001CD13, # BLOCK OCTANT-1245
0x0001CD14, # BLOCK OCTANT-345
0x0001CD15, # BLOCK OCTANT-1345
0x0001CD16, # BLOCK OCTANT-2345
0x0001CD17, # BLOCK OCTANT-12345
0x0001CD18, # BLOCK OCTANT-6
0x0001CD19, # BLOCK OCTANT-16
0x0001CD1A, # BLOCK OCTANT-26
0x0001CD1B, # BLOCK OCTANT-126
0x0001CD1C, # BLOCK OCTANT-36
0x0001CD1D, # BLOCK OCTANT-136
0x0001CD1E, # BLOCK OCTANT-236
0x0001CD1F, # BLOCK OCTANT-1236
0x0001FBE7, # MIDDLE RIGHT ONE QUARTER BLOCK
0x0001CD20, # BLOCK OCTANT-146
0x0001CD21, # BLOCK OCTANT-246
0x0001CD22, # BLOCK OCTANT-1246
0x0001CD23, # BLOCK OCTANT-346
0x0001CD24, # BLOCK OCTANT-1346
0x0001CD25, # BLOCK OCTANT-2346
0x0001CD26, # BLOCK OCTANT-12346
0x0001CD27, # BLOCK OCTANT-56
0x0001CD28, # BLOCK OCTANT-156
0x0001CD29, # BLOCK OCTANT-256
0x0001CD2A, # BLOCK OCTANT-1256
0x0001CD2B, # BLOCK OCTANT-356
0x0001CD2C, # BLOCK OCTANT-1356
0x0001CD2D, # BLOCK OCTANT-2356
0x0001CD2E, # BLOCK OCTANT-12356
0x0001CD2F, # BLOCK OCTANT-456
0x0001CD30, # BLOCK OCTANT-1456
0x0001CD31, # BLOCK OCTANT-2456
0x0001CD32, # BLOCK OCTANT-12456
0x0001CD33, # BLOCK OCTANT-3456
0x0001CD34, # BLOCK OCTANT-13456
0x0001CD35, # BLOCK OCTANT-23456
0x0001FB85, # UPPER THREE QUARTERS BLOCK
0x0001CEA3, # LEFT HALF LOWER ONE QUARTER BLOCK
0x0001CD36, # BLOCK OCTANT-17
0x0001CD37, # BLOCK OCTANT-27
0x0001CD38, # BLOCK OCTANT-127
0x0001CD39, # BLOCK OCTANT-37
0x0001CD3A, # BLOCK OCTANT-137
0x0001CD3B, # BLOCK OCTANT-237
0x0001CD3C, # BLOCK OCTANT-1237
0x0001CD3D, # BLOCK OCTANT-47
0x0001CD3E, # BLOCK OCTANT-147
0x0001CD3F, # BLOCK OCTANT-247
0x0001CD40, # BLOCK OCTANT-1247
0x0001CD41, # BLOCK OCTANT-347
0x0001CD42, # BLOCK OCTANT-1347
0x0001CD43, # BLOCK OCTANT-2347
0x0001CD44, # BLOCK OCTANT-12347
0x00002596, # QUADRANT LOWER LEFT
0x0001CD45, # BLOCK OCTANT-157
0x0001CD46, # BLOCK OCTANT-257
0x0001CD47, # BLOCK OCTANT-1257
0x0001CD48, # BLOCK OCTANT-357
0x0000258C, # LEFT HALF BLOCK
0x0001CD49, # BLOCK OCTANT-2357
0x0001CD4A, # BLOCK OCTANT-12357
0x0001CD4B, # BLOCK OCTANT-457
0x0001CD4C, # BLOCK OCTANT-1457
0x0000259E, # QUADRANT UPPER RIGHT AND LOWER LEFT
0x0001CD4D, # BLOCK OCTANT-12457
0x0001CD4E, # BLOCK OCTANT-3457
0x0001CD4F, # BLOCK OCTANT-13457
0x0001CD50, # BLOCK OCTANT-23457
0x0000259B, # QUADRANT UPPER LEFT AND UPPER RIGHT AND LOWER LEFT
0x0001CD51, # BLOCK OCTANT-67
0x0001CD52, # BLOCK OCTANT-167
0x0001CD53, # BLOCK OCTANT-267
0x0001CD54, # BLOCK OCTANT-1267
0x0001CD55, # BLOCK OCTANT-367
0x0001CD56, # BLOCK OCTANT-1367
0x0001CD57, # BLOCK OCTANT-2367
0x0001CD58, # BLOCK OCTANT-12367
0x0001CD59, # BLOCK OCTANT-467
0x0001CD5A, # BLOCK OCTANT-1467
0x0001CD5B, # BLOCK OCTANT-2467
0x0001CD5C, # BLOCK OCTANT-12467
0x0001CD5D, # BLOCK OCTANT-3467
0x0001CD5E, # BLOCK OCTANT-13467
0x0001CD5F, # BLOCK OCTANT-23467
0x0001CD60, # BLOCK OCTANT-123467
0x0001CD61, # BLOCK OCTANT-567
0x0001CD62, # BLOCK OCTANT-1567
0x0001CD63, # BLOCK OCTANT-2567
0x0001CD64, # BLOCK OCTANT-12567
0x0001CD65, # BLOCK OCTANT-3567
0x0001CD66, # BLOCK OCTANT-13567
0x0001CD67, # BLOCK OCTANT-23567
0x0001CD68, # BLOCK OCTANT-123567
0x0001CD69, # BLOCK OCTANT-4567
0x0001CD6A, # BLOCK OCTANT-14567
0x0001CD6B, # BLOCK OCTANT-24567
0x0001CD6C, # BLOCK OCTANT-124567
0x0001CD6D, # BLOCK OCTANT-34567
0x0001CD6E, # BLOCK OCTANT-134567
0x0001CD6F, # BLOCK OCTANT-234567
0x0001CD70, # BLOCK OCTANT-1234567
0x0001CEA0, # RIGHT HALF LOWER ONE QUARTER BLOCK
0x0001CD71, # BLOCK OCTANT-18
0x0001CD72, # BLOCK OCTANT-28
0x0001CD73, # BLOCK OCTANT-128
0x0001CD74, # BLOCK OCTANT-38
0x0001CD75, # BLOCK OCTANT-138
0x0001CD76, # BLOCK OCTANT-238
0x0001CD77, # BLOCK OCTANT-1238
0x0001CD78, # BLOCK OCTANT-48
0x0001CD79, # BLOCK OCTANT-148
0x0001CD7A, # BLOCK OCTANT-248
0x0001CD7B, # BLOCK OCTANT-1248
0x0001CD7C, # BLOCK OCTANT-348
0x0001CD7D, # BLOCK OCTANT-1348
0x0001CD7E, # BLOCK OCTANT-2348
0x0001CD7F, # BLOCK OCTANT-12348
0x0001CD80, # BLOCK OCTANT-58
0x0001CD81, # BLOCK OCTANT-158
0x0001CD82, # BLOCK OCTANT-258
0x0001CD83, # BLOCK OCTANT-1258
0x0001CD84, # BLOCK OCTANT-358
0x0001CD85, # BLOCK OCTANT-1358
0x0001CD86, # BLOCK OCTANT-2358
0x0001CD87, # BLOCK OCTANT-12358
0x0001CD88, # BLOCK OCTANT-458
0x0001CD89, # BLOCK OCTANT-1458
0x0001CD8A, # BLOCK OCTANT-2458
0x0001CD8B, # BLOCK OCTANT-12458
0x0001CD8C, # BLOCK OCTANT-3458
0x0001CD8D, # BLOCK OCTANT-13458
0x0001CD8E, # BLOCK OCTANT-23458
0x0001CD8F, # BLOCK OCTANT-123458
0x00002597, # QUADRANT LOWER RIGHT
0x0001CD90, # BLOCK OCTANT-168
0x0001CD91, # BLOCK OCTANT-268
0x0001CD92, # BLOCK OCTANT-1268
0x0001CD93, # BLOCK OCTANT-368
0x0000259A, # QUADRANT UPPER LEFT AND LOWER RIGHT
0x0001CD94, # BLOCK OCTANT-2368
0x0001CD95, # BLOCK OCTANT-12368
0x0001CD96, # BLOCK OCTANT-468
0x0001CD97, # BLOCK OCTANT-1468
0x00002590, # RIGHT HALF BLOCK
0x0001CD98, # BLOCK OCTANT-12468
0x0001CD99, # BLOCK OCTANT-3468
0x0001CD9A, # BLOCK OCTANT-13468
0x0001CD9B, # BLOCK OCTANT-23468
0x0000259C, # QUADRANT UPPER LEFT AND UPPER RIGHT AND LOWER RIGHT
0x0001CD9C, # BLOCK OCTANT-568
0x0001CD9D, # BLOCK OCTANT-1568
0x0001CD9E, # BLOCK OCTANT-2568
0x0001CD9F, # BLOCK OCTANT-12568
0x0001CDA0, # BLOCK OCTANT-3568
0x0001CDA1, # BLOCK OCTANT-13568
0x0001CDA2, # BLOCK OCTANT-23568
0x0001CDA3, # BLOCK OCTANT-123568
0x0001CDA4, # BLOCK OCTANT-4568
0x0001CDA5, # BLOCK OCTANT-14568
0x0001CDA6, # BLOCK OCTANT-24568
0x0001CDA7, # BLOCK OCTANT-124568
0x0001CDA8, # BLOCK OCTANT-34568
0x0001CDA9, # BLOCK OCTANT-134568
0x0001CDAA, # BLOCK OCTANT-234568
0x0001CDAB, # BLOCK OCTANT-1234568
0x00002582, # LOWER ONE QUARTER BLOCK
0x0001CDAC, # BLOCK OCTANT-178
0x0001CDAD, # BLOCK OCTANT-278
0x0001CDAE, # BLOCK OCTANT-1278
0x0001CDAF, # BLOCK OCTANT-378
0x0001CDB0, # BLOCK OCTANT-1378
0x0001CDB1, # BLOCK OCTANT-2378
0x0001CDB2, # BLOCK OCTANT-12378
0x0001CDB3, # BLOCK OCTANT-478
0x0001CDB4, # BLOCK OCTANT-1478
0x0001CDB5, # BLOCK OCTANT-2478
0x0001CDB6, # BLOCK OCTANT-12478
0x0001CDB7, # BLOCK OCTANT-3478
0x0001CDB8, # BLOCK OCTANT-13478
0x0001CDB9, # BLOCK OCTANT-23478
0x0001CDBA, # BLOCK OCTANT-123478
0x0001CDBB, # BLOCK OCTANT-578
0x0001CDBC, # BLOCK OCTANT-1578
0x0001CDBD, # BLOCK OCTANT-2578
0x0001CDBE, # BLOCK OCTANT-12578
0x0001CDBF, # BLOCK OCTANT-3578
0x0001CDC0, # BLOCK OCTANT-13578
0x0001CDC1, # BLOCK OCTANT-23578
0x0001CDC2, # BLOCK OCTANT-123578
0x0001CDC3, # BLOCK OCTANT-4578
0x0001CDC4, # BLOCK OCTANT-14578
0x0001CDC5, # BLOCK OCTANT-24578
0x0001CDC6, # BLOCK OCTANT-124578
0x0001CDC7, # BLOCK OCTANT-34578
0x0001CDC8, # BLOCK OCTANT-134578
0x0001CDC9, # BLOCK OCTANT-234578
0x0001CDCA, # BLOCK OCTANT-1234578
0x0001CDCB, # BLOCK OCTANT-678
0x0001CDCC, # BLOCK OCTANT-1678
0x0001CDCD, # BLOCK OCTANT-2678
0x0001CDCE, # BLOCK OCTANT-12678
0x0001CDCF, # BLOCK OCTANT-3678
0x0001CDD0, # BLOCK OCTANT-13678
0x0001CDD1, # BLOCK OCTANT-23678
0x0001CDD2, # BLOCK OCTANT-123678
0x0001CDD3, # BLOCK OCTANT-4678
0x0001CDD4, # BLOCK OCTANT-14678
0x0001CDD5, # BLOCK OCTANT-24678
0x0001CDD6, # BLOCK OCTANT-124678
0x0001CDD7, # BLOCK OCTANT-34678
0x0001CDD8, # BLOCK OCTANT-134678
0x0001CDD9, # BLOCK OCTANT-234678
0x0001CDDA, # BLOCK OCTANT-1234678
0x00002584, # LOWER HALF BLOCK
0x0001CDDB, # BLOCK OCTANT-15678
0x0001CDDC, # BLOCK OCTANT-25678
0x0001CDDD, # BLOCK OCTANT-125678
0x0001CDDE, # BLOCK OCTANT-35678
0x00002599, # QUADRANT UPPER LEFT AND LOWER LEFT AND LOWER RIGHT
0x0001CDDF, # BLOCK OCTANT-235678
0x0001CDE0, # BLOCK OCTANT-1235678
0x0001CDE1, # BLOCK OCTANT-45678
0x0001CDE2, # BLOCK OCTANT-145678
0x0000259F, # QUADRANT UPPER RIGHT AND LOWER LEFT AND LOWER RIGHT
0x0001CDE3, # BLOCK OCTANT-1245678
0x00002586, # LOWER THREE QUARTERS BLOCK
0x0001CDE4, # BLOCK OCTANT-1345678
0x0001CDE5, # BLOCK OCTANT-2345678
0x00002588, # FULL BLOCK
]

@inline x_pixel_per_char(::Type{<:OctantCanvas}) = 2
@inline y_pixel_per_char(::Type{<:OctantCanvas}) = 4

@inline lookup_encode(::OctantCanvas) = OCTANT_SIGNS
@inline lookup_decode(::OctantCanvas) = OCTANT_DECODE
@inline lookup_offset(::OctantCanvas) = N_OCTANT

OctantCanvas(args...; kw...) =
CreateLookupCanvas(OctantCanvas, (0b00000000, 0b11111111), args...; kw...)
4 changes: 4 additions & 0 deletions test/runtests.jl
Original file line number Diff line number Diff line change
Expand Up @@ -111,6 +111,10 @@ macro binf(ex)
return :(@inferred(Plot{BrailleCanvas{ID, ID}}, $ex)) |> esc
end

macro oinf(ex)
return :(@inferred(Plot{OctantCanvas{ID, ID}}, $ex)) |> esc
end

macro hinf(ex)
return :(@inferred(Plot{HeatmapCanvas{ID, ID}}, $ex)) |> esc
end
Expand Down
2 changes: 1 addition & 1 deletion test/tst_scatterplot.jl
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,7 @@ end

@testset "boundaries" begin
# tests that the two points are drawn correctly on the canvas
for canvas in (BrailleCanvas, AsciiCanvas, DotCanvas)
for canvas in (BrailleCanvas, OctantCanvas, AsciiCanvas, DotCanvas)
for width in (20:10:60), height in (10:5:30)
p = scatterplot(1:2, reverse(1:2); height, width, canvas)
@test first(p.graphics.grid) != UnicodePlots.blank(p.graphics)
Expand Down
Loading