JuliaMono - a monospaced font for scientific and technical computing

specimen image 1

JuliaMono is a monospaced typeface designed for programming and in other text editing environments that require a wide range of specialist and technical Unicode characters. It was intended as an experiment to be presented at the 2020 JuliaCon conference in Lisbon, Portugal.

JuliaMono is:

This site uses JuliaMono for all text; if your browser can’t[3] (or you didn’t allow it to) download and display web fonts, you’ll only see the font in action in the images. You’ll see three large dots here when/if the font has been successfully downloaded:

(  )

To download and install JuliaMono, see the instructions here.

Type anything here. Nobody’s looking.

Screenshots

Editing code in Juno.

screenshot of Juno editor screenshot of Juno editor

And in VS Code.

screenshot of VS code editor screenshot of VS code editor

And in Vim:

screenshot of VIM editor screenshot of VIM editor

And in Emacs:

screenshot of emacs editor screenshot of emacs editor

Examples

specimen image 2 specimen image 3

The following examples will be rendered in JuliaMono by your browser (if it’s successfully downloaded the web font versions), so I hope what you see here is close to what I made.

The CSS markup applied to the following code uses two weights of the typeface, JuliaMono-Regular and JuliaMono-Medium, which is a smidgeon bolder:

using Zygote: @adjoint
function ignore(f)
  try return f()
        catch e; return 0; end
end
@adjoint function ignore(f)
  try Zygote._pullback(__context__, f)
  catch e
    0, ȳ -> nothing
  end
end

There are different weights of JuliaMono, so you can control the amount of contrast you have in your highlighted code: JuliaMono-Regular, JuliaMono-Light, JuliaMono-Medium, JuliaMono-Bold, JuliaMono-ExtraBold, and JuliaMono-Black. [4]

(There are also versions of two of the fonts with “Latin” in the name: these are stripped down versions supporting just the basic MacRoman/Windows1252 “Latin” character sets. You probably don't want to use these - they're intended for use mainly as place-holders, of interest if you want to have more control over font loading times in web browser-based applications.)

In the hands of a virtuoso (such as Dr Zygmunt Szpak, the author of the following Julia code fragment[5]), the range of available Unicode characters can be quite expressive:

function T(𝛉::AbstractArray,
           𝒞::Tuple{AbstractArray,
           Vararg{AbstractArray}},
           𝒟::Tuple{AbstractArray, Vararg{AbstractArray}})
    ⊗ = kron
    l = length(𝛉)
    𝐈ₗ = SMatrix{l,l}(1.0I)
    𝐈ₘ = SMatrix{1,1}(1.0I)
    𝐓 = @SMatrix zeros(l,l)
    N = length(𝒟[1])
    ℳ, ℳʹ = 𝒟
    Λ₁, Λ₂ = 𝒞
    𝚲ₙ = @MMatrix zeros(4,4)
    𝐞₁ = @SMatrix [1.0; 0.0; 0.0]
    𝐞₂ = @SMatrix [0.0; 1.0; 0.0]
    for n = 1:N
        index = SVector(1,2)
        𝚲ₙ[1:2,1:2] .=  Λ₁[n][index,index]
        𝚲ₙ[3:4,3:4] .=  Λ₂[n][index,index]
        𝐦    = hom(ℳ[n])
        𝐦ʹ   = hom(ℳʹ[n])
        𝐔ₙ   = (𝐦 ⊗ 𝐦ʹ)
        ∂ₓ𝐮ₙ = [(𝐞₁ ⊗ 𝐦ʹ) (𝐞₂ ⊗ 𝐦ʹ) (𝐦 ⊗ 𝐞₁) (𝐦 ⊗ 𝐞₂)]
        𝐁ₙ   = ∂ₓ𝐮ₙ * 𝚲ₙ * ∂ₓ𝐮ₙ'
        𝚺ₙ   = 𝛉' * 𝐁ₙ * 𝛉
        𝚺ₙ⁻¹ = inv(𝚺ₙ)
        𝐓₁   = @SMatrix zeros(Float64,l,l)
        for k = 1:l
            𝐞ₖ = 𝐈ₗ[:,k]
            ∂𝐞ₖ𝚺ₙ = (𝐈ₘ ⊗ 𝐞ₖ') * 𝐁ₙ * (𝐈ₘ ⊗ 𝛉) + (𝐈ₘ ⊗ 𝛉') * 𝐁ₙ * (𝐈ₘ ⊗ 𝐞ₖ)
            # Accumulating the result in 𝐓₁ allocates memory,
            # even though the two terms in the
            # summation are both SArrays.
            𝐓₁ = 𝐓₁ + 𝐔ₙ * 𝚺ₙ⁻¹ * (∂𝐞ₖ𝚺ₙ) * 𝚺ₙ⁻¹ * 𝐔ₙ' * 𝛉 * 𝐞ₖ'
        end
        𝐓 = 𝐓 + 𝐓₁
    end
    𝐓
end

Languages

Here are some samples of various languages[6] :

Ancient Greek Ἄδμηθ’, ὁρᾷς γὰρ τἀμὰ πράγμαθ’ ὡς ἔχει, λέξαι θέλω σοι πρὶν θανεῖν ἃ βούλομαι.
Bulgarian Я, пазачът Вальо уж бди, а скришом хапва кюфтенца зад щайгите.
Catalan «Dóna amor que seràs feliç!». Això, il·lús company geniüt, ja és un lluït rètol blavís d’onze kWh.
Czech Zvlášť zákeřný učeň s ďolíčky běží podél zóny úlů
Danish Quizdeltagerne spiste jordbær med fløde, mens cirkusklovnen Walther spillede på xylofon.
English Sphinx of black quartz, judge my vow.
Estonian Põdur Zagrebi tšellomängija-följetonist Ciqo külmetas kehvas garaažis
Finnish Charles Darwin jammaili Åken hevixylofonilla Qatarin yöpub Zeligissä.
French Voix ambiguë d’un cœur qui au zéphyr préfère les jattes de kiwi.
Georgian სწრაფი ყავისფერი მელა ახტება ზარმაც ძაღლს.
German Victor jagt zwölf Boxkämpfer quer über den großen Sylter Deich.
Greek Ταχίστη αλώπηξ βαφής ψημένη γη, δρασκελίζει υπέρ νωθρού κυνός.
Guarani Hĩlandiagua kuñanguéra oho peteĩ saʼyju ypaʼũme Gavõme omboʼe hag̃ua ingyleñeʼẽ mitãnguérare neʼẽndyʼỹ.
Hungarian Jó foxim és don Quijote húszwattos lámpánál ülve egy pár bűvös cipőt készít.
IPA [ɢʷɯʔ.nas.doːŋ.kʰlja] [ŋan.ȵʑi̯wo.ɕi̯uĕn.ɣwa]
Icelandic Kæmi ný öxi hér, ykist þjófum nú bæði víl og ádrepa.
Irish Ċuaiġ bé ṁórṡáċ le dlúṫspád fíorḟinn trí hata mo ḋea-ṗorcáin ḃig.
Latvian Muļķa hipiji mēģina brīvi nogaršot celofāna žņaudzējčūsku.
Lithuanian Įlinkdama fechtuotojo špaga sublykčiojusi pragręžė apvalų arbūzą.
Macedonian Ѕидарски пејзаж: шугав билмез со чудење џвака ќофте и кељ на туѓ цех.
Norwegian Jeg begynte å fortære en sandwich mens jeg kjørte taxi på vei til quiz
Polish Pchnąć w tę łódź jeża lub ośm skrzyń fig.
Portuguese Luís argüia à Júlia que «brações, fé, chá, óxido, pôr, zângão» eram palavras do português.
Romanian Înjurând pițigăiat, zoofobul comandă vexat whisky și tequila.
Russian Широкая электрификация южных губерний даст мощный толчок подъёму сельского хозяйства.
Scottish Mus d’fhàg Cèit-Ùna ròp Ì le ob.
Serbian Ајшо, лепото и чежњо, за љубав срца мога дођи у Хаџиће на кафу.
Spanish Benjamín pidió una bebida de kiwi y fresa; Noé, sin vergüenza, la más champaña del menú.
Swedish Flygande bäckasiner söka hwila på mjuka tuvor.
Turkish Pijamalı hasta yağız şoföre çabucak güvendi.
Ukrainian Чуєш їх, доцю, га? Кумедна ж ти, прощайся без ґольфів!

Unicode coverage

Unicode sampler

One of the goals of JuliaMono is to include most of the characters that a typical programmer or monospaced-font user would reasonably expect to find. (Except for all those emojis - they are best handled by the operating system.) Here's a few less common ones:

specimen image 6

In JuliaMono, every character is the same width, because this is a monospaced typeface. Usually, typefaces with a lot of Unicode mathematical symbols are not monospaced, because they’re intended for use in prose and \( \LaTeX \) applications, rather than in programming code. You probably want ∑s in your code rather than \( \sum \)s, because the big ones will upset your formatting.

From a design perspective, forcing every character into the same size box is a problem. It’s like fitting every human being of whatever shape or size into identical airplane seats - some characters are bound to look uncomfortable. There’s never quite enough room for a nice-looking “m” or “w”.

The Julia package UnicodePlots.jl uses various Unicode characters to plot figures directly in a terminal window. [7]

UnicodePlots in action UnicodePlots in action

and the ImageInTerminal.jl package uses Unicode characters to display images in the terminal:

ImageInTerminal ImageInTerminal

It’s also a good idea to support box-drawing characters, such as the ones used for displaying DataFrames.jl output (terminal permitting):

julia> df = DataFrame(A=samples, B=glyphs)
df = 10×2 DataFrame
│ Row │ A              │ B                   │
│     │ String         │ String              │
├─────┼────────────────┼─────────────────────┤
│ 1   │ sample 1       │ ▁▂▁▁▂▄▅▁▄▁▁▅▆▂▇▅▂▇  │
│ 2   │ sample 2       │ ▁▂▄▁▁▃▁▆▂▆▃▁▂▃▂▇▄   │
│ 3   │ sample 3       │ ▁▆▇▁▃▇▇▆▅▅▄▇▇▅▅▇▄▂  │
│ 4   │ sample 4       │ ▅▁▄▁▆▃▁▃▇▂▂▇▅▇▃▆▃▁  │
│ 5   │ sample 5       │ ▆▂▁▂▇▆▃▅▅▄▆▇▄▇▆▁▇   │
│ 6   │ sample 6       │ ▁▁▇▂▂▇▃▅▂▂▆▂▄▄▁▄▂▇▆ │
│ 7   │ sample 7       │ ▂▃▂▁▁▇▁▂▆▂▁▇▁▄▃▂▁▄  │
│ 8   │ sample 8       │ ▄▄▁▂▄▁▅▁▅▁▂▂▇▂▁▃▄▄  │
│ 9   │ sample 9       │ ▁▁▁▂▁▆▃▄▄▁▂▂▃▂▁▅▁▆▃ │
│ 10  │ sample 10      │ ▁▇▄▂▅▃▇▁▇▇▆▄▇▅▄▂▄▅▄ │

(Can you spot the little used and sadly mathematically-unsupported “times” (×) character?)

For a comparison of JuliaMono with other math-capable monospaced fonts, visit mono-math.netlify.app, which shows how Unicode math symbols look.

JuliaMono is quite greedy[8], and contains quite a few Unicode glyphs.

silly barchart

(Of course, size isn’t everything - quality can beat quantity, and other fonts will offer different experiences[9]).

If you want to know whether you can use a Unicode character as an identifier in your Julia code, use the undocumented function Base.isidentifier(). So, for example, if you have the urge to use a dingbat (one of the classic Herman Zapf dingbat designs) as a variable name, you could look for something suitable in the output of this:

julia> for n in 0x2700:0x27bf
			Base.isidentifier(string(Char(n))) && print(Char(n))
	   end
✀✁✂✃✄✅✆✇✈✉✊✋✌✍✎✏✐✑✒✓✔✕✖✗✘✙✚✛✜✝✞✟✠✡✢✣✤✥✦✧✨✩✪✫✬✭✮✯✰✱✲✳✴✵✶✷✸✹✺
✻✼✽✾✿❀❁❂❃❄❅❆❇❈❉❊❋❌❍❎❏❐❑❒❓❔❕❖❗❘❙❚❛❜❝❞❟❠❡❢❣❤❥❦❧➔➕➖➗➘➙➚➛➜➝➞➟➠➡
➢➣➤➥➦➧➨➩➪➫➬➭➮➯➰➱➲➳➴➵➶➷➸➹➺➻➼➽➾➿

julia> ❤(s) = println("I ❤ $(s)")
❤ (generic function with 1 method)

julia> ❤("Julia")
I ❤ Julia

Contextual and stylistic alternates

specimen image 7

JuliaMono is an OpenType typeface. OpenType technology provides powerful text positioning, pattern matching, and glyph substitution features, which are essential for languages such as Arabic and Urdu. In English, OpenType features are often seen when letter pairs such as fi in certain fonts are replaced by a single glyph such as . These ligatures have been used ever since printing with moveable type was invented, replacing the occasional awkward character combination with a better-looking alternative.

To be honest, I’m not a big fan of their use in coding fonts (and I’m not the only one[10]). I like to see exactly what I’ve typed, rather than what the font has decided to replace it with.

The Julia language is designed to use Unicode characters, and so ligatures aren't always needed, but there are a few places where the obvious Unicode glyphs are not accepted by the language, and the ASCII-art substitutes can be improved by the judicious use of alternate glyphs. There are also a few places where some subtle tweaks can enhance the readability of the language without introducing ambiguity.

In JuliaMono, the following substitutions are applied when the contextual alternates feature is active:

typed

displayed

-> ->
=> =>
|> |>
<| <|
:: ::
<-- <--
--> -->
<--> <-->

You can see these in action in the following code fragment:[11]

julialang = true # (!= 0)
(x, y) -> (x + y)
f(p::Int) = p * p
@inbounds if f in (Base.:+, Base.:-)
    if any(x -> x <: AbstractArray{<:Number})
         nouns = Dict(
            Base.:+ => "addition",
            Base.:- => "subtraction",
        )
    end
end
df2 = df |>
    @groupby(_.a) |>
    @map({a = key(_), b = mean(_.b)}) |>
    DataFrame # <|

OpenType fonts also offer you the ability to choose different designs for certain characters. These are stored as a ‘stylistic set’.

All the options are stored in the font, and are often referred to by their internal four letter code (not the best user-oriented design, really). For example, the contextual alternates listed above are collectively stored in the calt feature.

Sometimes, an application will show the options more visually in a Typography panel[12], usually tucked away somewhere on a Font chooser dialog.

Here’s a list of the stylistic sets currently available in JuliaMono.

feature code

off

on

description

zero 0 0

slashed zero

ss01 g g

alternate g

ss02 @ @

alternate @

ss03 j j

alternate j

ss04 0 0

alternate 0

ss05 * *

lighter asterisk

ss06 a a

simple a

ss07 ` `

smaller grave

ss08 -> ->

distinct ligatures

ss09 f f

alternate f

ss10 r r

alternate r

ss11 ` `

thinner grave

ss12 ==== ====

joining equals

All this fancy technology is under the control of the application and the operating system you’re using. Ideally, they will provide an easy way for you to switch the various OpenType features on and off.

Browser-based editors such as Juno and VS Code support many OpenType features in their editor windows, but not in the terminal/console windows. They provide a settings area where you can type CSS or JSON selectors to control the appearance of features, and you’ll have to know the feature codes. Some features are opt in, others are opt out; this too can vary from application to application.

Terminal/console applications also vary a lot; on MacOS the Terminal and iTerm applications try to offer controls for OpenType features, with varying degrees of success. On Linux, some terminal applications such as Konsole and Kitty offer quite good support, but others such as Alacritty offer little or none, as yet. [13]

If the application allows, you should be able to switch the calt contextual ligatures off, particularly since quite a few people won’t like any of them in their code. For the following listing, I switch the calt set off using CSS (see here), and then enable some of the alternative stylistic sets: compare characters such as the 0, g, a, j, and @ with the previous listing:

julialang = true # (!= 0)
(x, y) -> (x + y)
f(p::Int) = p * p
@inbounds if f in (Base.:+, Base.:-)
    if any(x -> x <: AbstractArray{<:Number})
         nouns = Dict(
            Base.:+ => "addition",
            Base.:- => "subtraction",
        )
    end
end
df2 = df |>
    @groupby(_.a) |>
    @map({a = key(_), b = mean(_.b)}) |>
    DataFrame # <|

(I originally liked the idea of a more circular @ sign, but in practice it doesn’t work at small point sizes, as the details disappear. But I’ve kept it anyway.)

If you really don't like any ligatures

It's possible that you don't like even the few ligatures and alternate characters provided in JuliaMono. If switching them off isn't possible, or not drastic enough, you can strip them out of the font with the following terminal magic (courtesy of @fredrikekre):

$ cat Dockerfile
FROM python
RUN pip install fonttools
COPY run.sh /scripts/
ENTRYPOINT ["/scripts/run.sh"]

$ cat run.sh
#!/bin/bash
set -euo pipefail

VERSION="${1-}"

mkdir -p /juliamono-source
mkdir -p /juliamono-output
mkdir -p /juliamono

# Download release version
curl -L "https://github.com/cormullion/juliamono/releases/download/v${VERSION}/JuliaMono.tar.gz" | tar -xzvC /juliamono-source

# Strip glyphs
for f in /juliamono-source/*.ttf
do
    pyftsubset "$f" '*' --output-file=/juliamono-output/$(basename "$f")  --layout-features-=calt,liga
done

# Pack it up
tar -C /juliamono-output -czvf /juliamono/JuliaMono-${VERSION}.tar.gz $(ls /juliamono-output)

$ cat Makefile
.PHONY: image strip
VERSION := 0.021
image:
        docker build -t juliamono-strip:latest .

strip:
        docker run --rm -v ${PWD}:/juliamono juliamono-strip:latest "${VERSION}"

Private Use Areas (PUAs)

There are a few areas of the Unicode system that have been officially kept empty and are thus available to store characters that are not part of the standard. These are called the Private Use Areas, and there are three: \ue000 to \uf8ff, \UF0000 to \UFFFFD, and U100000 to U+10FFFD.

Each typeface can do its own thing in these areas. In JuliaMono you'll find these, among others, and if you ask nicely I might add some more:

private use area

The obvious drawback to using characters in a Private Use Area is that you have to have installed the font wherever you want to see them rendered correctly, unless they’ve been converted to outlines or bitmaps. If the font isn’t installed (eg on github), you have no idea what glyph - if any - will be displayed.

You can define these to be available at the Julia REPL. For example, say you want the Julia circles to be available in the terminal when you type \julialogo in a Julia session with the JuliaMono font active. Run this:

using REPL
REPL.REPLCompletions.latex_symbols["\\julialogo"] = "\ue800"

Now you can insert the logo in strings by typing \julialogo:

julia> println("Welcome to ")
Welcome to 

It’s usually possible to type Unicode values directly into text. This is a useful skill to have when you’re not using a capable REPL. On MacOS you hold the Option (⌥) key down while typing the four hex digits (make sure you’re using the Unicode Hex Input keyboard). On Windows I think you type the four hex digits followed by ALT then X. On Linux it might be ctrl-shift-u followed by the hex digits.

Thanks!

Thanks to: Thibaut Lienart for his Franklin.jl web site builder; to Jérémie Knüsel who provided invaluable suggestions and advice; to Dr Zygmunt Szpak for his cool maths code; to Simeon Schaub for the issues and PRs, and to others in the Julia community for help and suggestions.

Footnotes

[1]   “licence” Although not MIT-licensed like Julia, JuliaMono is licensed using the SIL Open Font licence, which allows the fonts to be used, studied, modified, freely redistributed, and even sold, without affecting anything they’re bundled with.
[2]   “Windows” For more information about if and how it works on Windows, read this, but I currently don't know enough about Windows font technology and how it differs from MacOS and Unix. Early reports said that the font didn't look good on Windows. This was because the format was CFF/PostScript OTF, which isn't hinted on Windows. A switch to TTF/TrueType OTF, which is hinted, was considered an improvement.
[3]   “downloading font problems” The problem might be something to do with the web security feature called CORS which prevents a web page accessing the resources it needs.
[4]   “masters” In fact there are four masters (Light, Regular, Bold, and Black), and the other instances are interpolated between them.
[5]   “maths in code” spotted here
[6]   “languages” Apologies for errors - I don’t speak most of these languages.
[7]   “terminals and line spacing” Terminal applications usually provide the option to vary the line spacing. For perfectly smooth Unicode plots, you can adjust this until the shaded glyphs are in tune. But for coding purposes you might want the line spacing increased (or decreased) from the default, depending on the trade-off between reading speed, font size, and how many lines of code you can cram in.
[8]   “greedy” referencing this classic Julia blog post
[9]   “better fonts...” Operator Mono and Fira are excellent typefaces... Try them! Also try IBM Plex Mono, Iosevka, Recursive, and Victor Mono, to name a few of my favourites. Like programming languages, every typeface has its strengths and weaknesses. Perhaps keep JuliaMono for font fallback purposes... ;)
[10]   “not the only one” Matthew Butterick says “hell no” to them. He also uses the phrase “well-intentioned amateur ligaturists” which isn’t a label I want to have. But more seriously, he says: “my main concern is typography that faces other human beings. So if you’re preparing your code for others to read — whether on screen or on paper — skip the ligatures.”
[11]   “alternate glyphs” Note that the substitute glyphs occupy the same width as the source glyphs they're replacing. While you could in theory use one of the thousands of Unicode arrows, such as →, as a replacement for the ‘stabby lambda’ (->), these are the width of a single character, and so you'd be changing the width of your string/line whenever you made the substitution.
[12]   “Typography panel” These vary widely in their abilities and functions: the MacOS Terminal app’s Typography panel is comprehensive but I’m not convinced that all the buttons are wired up yet...
[13]   “terminals again” Writers of terminal apps usually have their own ideas about how fonts and type should be managed and displayed. I haven’t yet found one that did everything that I wanted it to and nothing I didn’t expect it to. In the world of fonts, nothing is 100% correct, which can be frustrating. You can track some of the issues and discussions on github and elsewhere: here’s a VS Code issue; here are the Alacritty terminal developers working on it; here is the iTerm documentation talking about performance.