# Using UnicodePlots for pretty printing a type

**URL:** <https://discourse.julialang.org/t/using-unicodeplots-for-pretty-printing-a-type/19808>\
**Category:** General Usage\
**Tags:** question\
**Created:** [January 19, 2019, 9:27am UTC](https://discourse.julialang.org/t/using-unicodeplots-for-pretty-printing-a-type/19808 "2019-01-19T09:27:50Z")\
**Posts on this page:** 7\
**Page:** 1

<div class="post-metadata">

**Author:** ![Datseris](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/datseris/32/13406_2.png) [@Datseris](https://discourse.julialang.org/u/Datseris)\
**Post date:** [January 19, 2019, 9:27am UTC](https://discourse.julialang.org/t/using-unicodeplots-for-pretty-printing-a-type/19808/1 "2019-01-19T09:27:50Z")

</div>

Hi All,

We got a julia struct that represents a sparse matrix. In the literature this matrix is often represented with its plot (like with `imshow`) because it only has 0s or 1s.

We want to define custom show methods for it. I realized I can use UnicodePlots to overload `show` to display the unicode plot instead.I have achieved that, so for the following let’s imagine that I am able to define `show` for my type that uses UnicodePlots.

Here are my questions:

1. I still want to have a “short” definition of my type, to be used in tuples/arrays. Julia manual says that I define `show(io, mytype)` for this short definition and then `show(io, ::MIME"text/plain", mytype)` for the long definition. Is this actually correct? How does “text/plain” correspond to all platforms that UnicodePlots supports? I mean, I could show this unicode plot to jupyter, juno, repl, everywhere. Does `text/plain` correspond to the type I should be using? **ANSWER: Yes, I just use `text/plain`.**

2. Can I somehow deduce the character limit of the `io` ? How many characters can be fit in the single line? If yes, where is this in the documentation?

3. Is there a way to “detect” the character spacing and the line height from the `io` ? By this I mean, how many pixels on the screen does the width of one character span, and how many pixels does the height of a line span.

4. Lastly, is it possible to “deduce” if the `io` supports unicode characters or only ascii? Because UnicodePlots allows you to use only ascii if need be!

P.s.: This is how the matrix looks now when UnicodePlot-printed:

 ![image](https://global.discourse-cdn.com/julialang/original/3X/b/a/ba6cb8b64f2b58a42d3f9ecdfe292188e513c59c.png)

---

<div class="post-metadata">

**Author:** ![kristoffer.carlsson](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/kristoffer.carlsson/32/22_2.png) [@kristoffer.carlsson](https://discourse.julialang.org/u/kristoffer.carlsson)\
**Post date:** [January 19, 2019, 9:44am UTC](https://discourse.julialang.org/t/using-unicodeplots-for-pretty-printing-a-type/19808/2 "2019-01-19T09:44:37Z")

</div>

> [@Datseris](#):
>
> Can I somehow deduce the character limit of the `io` ?

```julia
julia> displaysize(stdout)
(30, 120)

```

---

<div class="post-metadata">

**Author:** ![Jean\_Michel](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/jean_michel/32/8282_2.png) [@Jean\_Michel](https://discourse.julialang.org/u/Jean_Michel)\
**Post date:** [January 19, 2019, 9:51am UTC](https://discourse.julialang.org/t/using-unicodeplots-for-pretty-printing-a-type/19808/3 "2019-01-19T09:51:39Z")

</div>

There was recently a thread on a related topic  
https://discourse.julialang.org/t/how-to-detect-in-show-that-you-are-computing-display-for-the-repl/18951  
The conclusion is that you check `:limit` to know if you prepare printing to the REPL.

---

<div class="post-metadata">

**Author:** ![Seif\_Shebl](https://avatars.discourse-cdn.com/v4/letter/s/eada6e/32.png) [@Seif\_Shebl](https://discourse.julialang.org/u/Seif_Shebl)\
**Post date:** [January 19, 2019, 11:31am UTC](https://discourse.julialang.org/t/using-unicodeplots-for-pretty-printing-a-type/19808/4 "2019-01-19T11:31:18Z")

</div>

I remember this is `spy(H)` in MATLAB with `H` being a sparse binary matrix (having only zeros and ones). Perhaps one of the plotting packages can implement this (if it is not already implemented)?

---

<div class="post-metadata">

**Author:** ![LaurentPlagne](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/laurentplagne/32/10103_2.png) [@LaurentPlagne](https://discourse.julialang.org/u/LaurentPlagne)\
**Post date:** [January 19, 2019, 1:16pm UTC](https://discourse.julialang.org/t/using-unicodeplots-for-pretty-printing-a-type/19808/5 "2019-01-19T13:16:07Z")

</div>

It is already available via Plots.jl (`spy(H)`). But I did not try it with UnicodePlots.

---

<div class="post-metadata">

**Author:** ![bennedich](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/bennedich/32/4894_2.png) [@bennedich](https://discourse.julialang.org/u/bennedich)\
**Post date:** [January 19, 2019, 11:32pm UTC](https://discourse.julialang.org/t/using-unicodeplots-for-pretty-printing-a-type/19808/6 "2019-01-19T23:32:05Z")

</div>

> [@Datseris](#):
>
> Is there a way to “detect” /…/ how many pixels on the screen does the width of one character span, and how many pixels does the height of a line span.

YES! I have developed an ingenious solution for this. Here’s how:

- Draw a bunch of random green and blue blocks in the terminal using Unicode Full Block characters (‘█’).
- Make one of these blocks red.
- Flush the stdout.
- Short sleep, this is important otherwise it won’t work (0.1 seconds seems enough).
- Now capture the screen. On Windows this is performed with ccalls to Windows GDI.
- Now we will search the screen for anything that’s red. Note: There may be false positives.
- For any potentially matching red pixels, expand the area to find the size of that block.
- Once you’ve found the size, search all around the red block to see if the surroundings exactly match the random green and blue blocks that you previously drew.
- Once everything matches, you have successfully detected the character dimensions.
- Finally, we will tidy up by using ANSI escape codes to erase all the blocks drawn.

* * *

![](https://global.discourse-cdn.com/julialang/original/3X/2/2/22e3726aff6c57c6f7e7957163ceee4510141fdd.gif)

* * *

And here’s the code (note: Windows only):

```julia
const USER, GDI = "user32.dll", "gdi32.dll"

function cc(library, method, args...)
    argtypes = Expr(:tuple, (args .|> a -> isbits(a) ? UInt32 : Ptr{UInt8})...)
    @eval ccall(($method, $library), UInt32, $argtypes, $(args...))
end

R = (ansi = 91, matches = (r,g,b) -> r > g+32 && r > b+32)
G = (ansi = 92, matches = (r,g,b) -> g > r+32 && g > b+32)
B = (ansi = 94, matches = (r,g,b) -> b > r+32 && b > g+32)
BLOCKS = (b = rand([G B], 3, 10); b[2,2] = R; b)
XRES, YRES = Tuple(0:1 .|> m -> cc(USER, "GetSystemMetrics", m))

function print_blocks()
    S = BLOCKS .|> b -> "\e[1;$(b.ansi)m█"
    print.(permutedims(hcat(S, [fill("\n", size(BLOCKS,1)-1); " "]), [2,1]))
    flush(stdout)
end

erase_blocks() = print("\e[2K\e[A"^(size(BLOCKS,1)-1), "\e[2K\e[G\e[m")

function get_screen_pixels()
    hdc_screen = cc(USER, "GetDC", 0)
    hdc_mem = cc(GDI, "CreateCompatibleDC", hdc_screen)
    hbitmap = cc(GDI, "CreateCompatibleBitmap", hdc_screen, XRES, YRES)
    cc(GDI, "SelectObject", hdc_mem, hbitmap)
    cc(GDI, "BitBlt", hdc_mem, 0, 0, XRES, YRES, hdc_screen, 0, 0, 0xcc0020)
    pixels = Vector{UInt32}(undef, XRES * YRES)
    bmi = UInt32[40, XRES, -YRES, (32<<16) + 1, 0, 0, 0, 0, 0, 0]
    cc(GDI, "GetDIBits", hdc_mem, hbitmap, 0, YRES, pixels, bmi, 0)
    pixels
end

function search_blocks(pixels)
    px(x, y) = pixels[x + XRES*(y-1)]
    rgb(x, y) = (c = px(x, y); ((c >> 16) & 0xff, (c >> 8) & 0xff, c & 0xff))
    block_matches_pixel(c, r, x, y) = BLOCKS[r,c].matches(rgb(x, y)...)
    block_matches(c, r, x, y, w, h) = all(1 ≤ u ≤ XRES && 1 ≤ v ≤ YRES &&
        block_matches_pixel(c, r, u, v) for u = x:x+w-1, v = y:y+h-1)

    for y = 2:YRES-1, x = 2:XRES-1
        # test if the 4 pixels around (x,y) match the top-left 4 blocks
        if all(block_matches_pixel(2-j, 2-k, x-j, y-k) for j=0:1, k=0:1)
            # match found! now calculate block size (w,h)
            w = h = 1
            while x+w ≤ XRES && block_matches_pixel(2, 2, x+w, y) w += 1 end
            while y+h ≤ YRES && block_matches_pixel(2, 2, x, y+h) h += 1 end

            # finally test if ALL blocks match color and block size
            w > 2 && h > 2 && all(block_matches(j, k, x+(j-2)*w, y+(k-2)*h, w, h) for j=1:size(BLOCKS,2), k=1:size(BLOCKS,1)) &&
                return (w=w, h=h)
        end
    end
    nothing
end

function get_character_dimensions()
    print_blocks()
    sleep(0.1) # short delay to ensure output is really flushed
    pixels = get_screen_pixels()
    erase_blocks()
    dims = search_blocks(pixels)
end

dims = get_character_dimensions()

println("Character dimensions: $(dims ≡ nothing ? "not found" : "$(dims.w) x $(dims.h) pixels")")

```

---

<div class="post-metadata">

**Author:** ![Datseris](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/datseris/32/13406_2.png) [@Datseris](https://discourse.julialang.org/u/Datseris)\
**Post date:** [January 19, 2019, 11:50pm UTC](https://discourse.julialang.org/t/using-unicodeplots-for-pretty-printing-a-type/19808/7 "2019-01-19T23:50:25Z")

</div>

this is so impressive, I am mindblown!!!
