-- Leo's gemini proxy

-- Connecting to eluum.net:1965...

-- Connected

-- Sending request

-- Meta line: 20 text/gemini

Unicode Plotting in Julia


Having recently discovered gemini, I have been trying to think about what kind content I could contribute. I was slightly concerned about the lack of embedded images, as I generally like to do technical stuff with visualizations, but then I remembered something I had read in the Julia Plots documentation a while back and got an idea.


Julia is an open source programming language for scientific computing. It takes inspiration from matlab, python, and lisp (even though it isn't written with s expressions).


The Julia Programming Language


One interesting thing about Julia is that the plotting library, called Plots, can render figures using multiple backends. This is useful because the same figure can be embedded in a webpage, or saved to a variety of image formats. What caught my interest with respect to gemini is the UnicodePlots backend, which renders figures using unicode for display in terminals. This should be perfect for gemini articles!


UnicodePlots documentation


Here is a simple line plot example.


using Plots
using UnicodePlots

# set the backend to use UnicodePlots
unicodeplots()

# sine wave plot
plot(range(0, 2π, 100), sin)

            ┌────────────────────────────────────────┐
    1.05987 │⠀⡇⠀⠀⠀⠀⠀⠀⡠⠴⠒⠢⢄⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀│ y1
            │⠀⡇⠀⠀⠀⠀⢠⠚⠀⠀⠀⠀⠀⠑⡄⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀│
            │⠀⡇⠀⠀⠀⡠⠃⠀⠀⠀⠀⠀⠀⠀⠈⢢⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀│
            │⠀⡇⠀⠀⡰⠁⠀⠀⠀⠀⠀⠀⠀⠀⠀⠈⢢⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀│
            │⠀⡇⠀⡰⠁⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⢧⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀│
            │⠀⡇⡰⠃⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠈⢆⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀│
            │⠀⣧⠃⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠈⡆⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀│
            │⠤⡯⠤⠤⠤⠤⠤⠤⠤⠤⠤⠤⠤⠤⠤⠤⠤⠤⠤⠼⡤⠤⠤⠤⠤⠤⠤⠤⠤⠤⠤⠤⠤⠤⠤⠤⠤⠤⡤⠤│
            │⠀⡇⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠸⡀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⢠⠃⠀│
            │⠀⡇⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠱⡀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⢠⠊⠀⠀│
            │⠀⡇⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠣⡀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⢀⠎⠀⠀⠀│
            │⠀⡇⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⢣⡀⠀⠀⠀⠀⠀⠀⠀⠀⠀⢀⠎⠀⠀⠀⠀│
            │⠀⡇⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠱⡀⠀⠀⠀⠀⠀⠀⠀⢠⠊⠀⠀⠀⠀⠀│
            │⠀⡇⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠙⢄⠀⠀⠀⠀⠀⡤⠊⠀⠀⠀⠀⠀⠀│
   -1.05987 │⠀⡇⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠑⠢⠤⠖⠊⠀⠀⠀⠀⠀⠀⠀⠀│
            └────────────────────────────────────────┘
            ⠀-0.188496⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀6.47168⠀

Wow! Who even needs Jupyter notebooks. The documentation covers a variety of plot types that are available. Here is a contour plot.


# define surface function
pole(x, y, z, ϵ) = 1 ./ (abs.(x + y*im - z) + ϵ)
surface(x, y) = pole(x, y, 0.5 + 0.75im, 0.1) + pole(x, y, 0.25 + 0.25im, 0.2)

# create contour plot
contour(range(0, 1, 100), range(0, 1, 100), surface, xlabel = "real", ylabel = "imaginary", levels = 10)

             ┌────────────────────────────────────────┐  10
           1 │⠀⠀⣠⠚⠁⠀⠀⠀⠀⠀⢀⠤⠚⠉⠁⠀⢀⣀⣀⣀⣀⣀⣀⠀⠀⠉⠒⢄⡀⠀⠀⠀⠀⠘⢦⡀⠀⠀⠀⠀│ ┌──┐
             │⣠⠎⠁⠀⠀⠀⠀⠀⡠⠎⠁⠀⢀⡠⠔⠉⣁⡠⠤⠤⠤⠤⣀⡉⠑⠦⡀⠀⠈⠢⡀⠀⠀⠀⠀⠱⡄⠀⠀⠀│ │▄▄│
             │⠁⠀⠀⠀⠀⠀⢠⠞⠁⠀⠀⡰⠊⠀⡴⠊⡥⢒⣮⣭⣭⣵⡲⣍⠲⡄⠘⢦⠀⠀⠘⡄⠀⠀⠀⠀⠸⡄⠀⠀│ │▄▄│
             │⠀⠀⠀⠀⠀⢠⠋⠀⠀⠀⣰⠁⠀⡜⠀⡞⢰⢱⣽⣿⣿⣯⡟⡎⡇⢸⠀⠈⡇⠀⠀⢹⠀⠀⠀⠀⠀⢣⠀⠀│ │▄▄│
             │⠀⠀⠀⠀⢠⠇⠀⠀⠀⠀⡇⠀⠀⢧⠀⠣⡘⢬⣺⠿⠿⣟⠵⣡⠃⡸⠀⠀⡇⠀⠀⢸⠀⠀⠀⠀⠀⢸⠀⠀│ │▄▄│
             │⠀⠀⠀⢀⡎⠀⠀⠀⠀⠀⡇⠀⠀⠈⢢⡀⠙⠒⠬⠭⠭⠖⠊⣁⠔⠁⢀⡞⠀⠀⠀⡞⠀⠀⠀⠀⠀⢸⠀⠀│ │▄▄│
             │⠀⠀⢀⡜⠀⠀⠀⠀⠀⠀⡇⠀⠀⠀⠀⠈⠑⠒⠢⠔⠒⠒⠉⠁⢀⡴⠋⠀⠀⠀⡼⠁⠀⠀⠀⠀⠀⡇⠀⠀│ │▄▄│
   imaginary │⠀⠀⡜⠀⠀⠀⠀⠀⠀⡴⠁⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⣀⠤⠖⠁⠀⠀⠀⢠⠞⠀⠀⠀⠀⠀⠀⡼⠀⠀⠀│ │▄▄│
             │⠀⡜⠀⠀⠀⠀⢀⡴⠋⠀⠀⠀⠀⠀⠀⠀⠀⠀⣠⠖⠊⠁⠀⠀⠀⠀⢀⡔⠁⠀⠀⠀⠀⠀⠀⡸⠁⠀⠀⠀│ │▄▄│
             │⢰⠁⠀⠀⠀⡰⠃⠀⠀⢀⣀⡀⠀⠀⠀⠀⠀⡸⠁⠀⠀⠀⠀⠀⠀⡴⠉⠀⠀⠀⠀⠀⠀⢀⡜⠁⠀⠀⠀⠀│ │▄▄│
             │⢸⠀⠀⠀⢰⠁⠀⡰⠋⢁⣀⠉⠳⡀⠀⠀⢠⠇⠀⠀⠀⠀⠀⡴⠋⠀⠀⠀⠀⠀⠀⠀⣠⠊⠀⠀⠀⠀⠀⠀│ │▄▄│
             │⠘⡄⠀⠀⠸⡄⠀⢣⡀⠣⠼⢀⡰⠃⠀⢀⠎⠀⠀⠀⠀⣠⠎⠀⠀⠀⠀⠀⠀⠀⢀⠜⠁⠀⠀⠀⠀⠀⠀⠀│ │▄▄│
             │⠀⠘⢆⠀⠀⠘⠢⢄⡈⠉⠉⠉⣀⡤⠔⠁⠀⠀⢀⡠⠚⠁⠀⠀⠀⠀⠀⠀⢀⠔⠃⠀⠀⠀⠀⠀⠀⠀⠀⠀│ │▄▄│
             │⠀⠀⠈⠑⠦⣀⡀⠀⠈⠉⠉⠉⠀⠀⠀⣀⡠⠔⠋⠀⠀⠀⠀⠀⠀⠀⣀⠖⠁⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀│ │▄▄│
           0 │⡀⠀⠀⠀⠀⠀⠉⠙⠒⠒⠒⠒⠒⠊⠉⠀⠀⠀⠀⠀⠀⠀⠀⣀⠤⠋⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀│ └──┘
             └────────────────────────────────────────┘  2
             ⠀0⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀real⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀1⠀

Unfortunately the color information is lost, making the colorbar on the right useless. Another interesting plotting function is isosurface, which plots a level set for a function ℝ³ → ℝ. You can think of it as a 3d contour plot with a single contour. In 2d the contours are 1 dimensional lines, in 3d they are 2 dimensional surfaces. Here is the example from the documentation, which draws a torus.


# iso surface
torus(x, y, z, r = 0.2, R = 0.5) = (√(x^2 + y^2) - R)^2 + z^2 - r^2
isosurface(-1:.1:1, -1:.1:1, -1:.1:1, torus, cull = true, zoom = 2, elevation = 50)

    ┌────────────────────────────────────────┐
    │⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀│
    │⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀│
    │⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⢀⢀⢀⠠⢄⢄⠄⠄⡠⡠⠤⡀⡀⡀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀│
    │⠀⠀⠀⠀⠀⠀⠀⠀⠀⡀⠔⠌⠜⠀⠡⠠⠁⠡⠠⠁⠈⠄⠌⠈⠄⠌⠀⠪⠠⠤⡀⡀⠀⠀⠀⠀⠀⠀⠀⠀│
    │⠀⠀⠀⠀⠀⠀⡠⠔⠅⠌⠈⠄⠌⠀⡁⡀⠨⡀⠄⠠⠡⠠⡀⠥⠠⠈⠀⠡⠠⠁⠡⠱⠢⡀⠀⠀⠀⠀⠀⠀│
    │⠀⠀⠀⠀⢀⣜⠃⡁⠄⢊⠈⠄⡰⠐⡀⢂⡞⢈⡰⡨⡂⢆⡁⣱⠔⢁⠘⢀⠠⠁⡑⠠⢈⠘⣲⡀⠀⠀⠀⠀│
    │⠀⠀⠀⠀⡚⠥⠁⡀⠂⢂⠈⠄⡖⡫⠗⠋⠉⠀⠀⠀⠀⠀⠈⠉⠉⠱⢝⠱⠠⠁⡐⠐⢀⠈⢌⢧⠀⠀⠀⠀│
    │⠀⠀⠀⠀⡟⠤⠁⡀⠂⢂⢈⠄⢮⡇⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⢸⡿⠠⡁⡐⠐⢀⠈⢤⢚⠀⠀⠀⠀│
    │⠀⠀⠀⠀⢽⠗⠅⡀⠂⢂⢀⠂⢂⠓⡢⡄⣀⠀⠀⠀⠀⠀⢀⡀⢀⢰⠂⡑⠐⡀⡐⠐⠀⠨⢔⡟⠀⠀⠀⠀│
    │⠀⠀⠀⠀⠈⠭⠄⠌⠰⠀⡀⠂⢂⠀⡐⠐⠌⠔⠑⠅⠡⠊⠢⠡⠂⢂⠀⡐⠐⣀⠐⠠⡁⡃⡑⠁⠀⠀⠀⠀│
    │⠀⠀⠀⠀⠀⠀⠈⠨⠅⠄⠌⠀⡆⢀⠐⠐⢀⠐⠐⠀⠄⠂⠂⡀⠂⡂⡀⠂⢂⠀⡂⢐⠔⠈⠀⠀⠀⠀⠀⠀│
    │⠀⠀⠀⠀⠀⠀⠀⠀⠀⠈⠢⢥⢀⡂⡃⠇⠃⡁⡡⠨⡈⡨⠈⠬⠨⠢⢈⢠⠑⠒⠈⠀⠀⠀⠀⠀⠀⠀⠀⠀│
    │⠀⠀⠀⢠⠀⠀⠀⠀⠀⠀⠀⠀⠀⠈⠈⠋⠓⠂⠊⠒⠂⠚⠘⠚⠙⠉⠁⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀│
    │⠀⠀⣀⠼⢄⡀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀│
    │⠔⠉⠀⠀⠀⠈⠑⠄⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀│
    └────────────────────────────────────────┘

isosurface in particular has a lot of potential for making cool stuff. The documentation also includes some information about the low-level interface the library uses for drawing, which could be used for creative purposes as well. I'm already thinking about ways to do more general 3d rendering, which would be a fun project.


I'm impressed by how well unicode plotting works out of the box in Julia. This library can easily be used to add visualizations to gemini articles, and there are definitely many more possibilities to explore.


Full Code

-- Response ended

-- Page fetched on Mon May 20 16:23:16 2024