Hot summer brings high temperatures. In Europe, we are okay at least with the number of digits, while those using Fahrenheit are now above 100.
Fun aside, many of us wanted to show numbers outside the 0-9 range, and here came Anton displaying numbers between 0-99 on a SPIKE hub. I really loved his approach, and as both the FLL and WRO season is on a bit of a pause, I have time to play around.
In this article, I will show you a method to display numbers on a 5×5 LED display from 0-399, also sharing the Python code that you can copy and use.

Displaying single-digit numbers
Numbers between 0-9 are not really tough as LEGO already came up with a digit set between 0-9 that I simply copied from the LEGO design using the center 3×5 space. Pybricks does have an approach that renders 0-9 chars between 3×5-4×5-5×5 design that I found a bit wacky and hard to read.
Displaying two-digit numbers
Displaying two-digit numbers is not supported by LEGO, yet both Anton and Pybricks came up with a different solution for numbers between 10-99.
While Pybricks used a consistent approach, splitting the display into 2×5 areas with a separating gap and displaying both tens and ones in a new slim number set. This approach is, as mentioned, consistent and brings further advantages.
On the other hand, Anton came up with the idea of splitting the display into 2×5 and 3×5 parts, displaying the tens with a new slim number set dimmed and the ones with the standard 3×5 font in full brightness.
This was a brilliant and inspiring move, as despite the limited display of SPIKE Hub’s 5×5 LED display, we can use different brightness to separate digits.
I loved both approaches and wanted to combine them, yet assumed that for two digits, the tens position is more relevant. Therefore, I preferred to make that brighter and bigger.

Displaying three-digit numbers
The Pybricks idea was inspiring to take the next logical step for numbers between 100-199.
Simply using the first column dimmed gave a simple extension to the Pybricks+Anton mode, splitting 1×5 – 2×5 – 2×5 sections, separating them by brightness in a dim – bright – dim pattern.
The step to extend this to 200-499 is a bit odd, yet my primary motive was to display orientation between 0-360 is not yet fulfilled. What if we use the first digit in a bit of a wacky mode? Instead of using the 1×5 column as a placeholder for “100,” I decided to use a small “1,” displaying as many pixels as there are hundreds.
Respectively: 200 will be denoted by 2 pixels, 300 by 3 pixels, and 400 by 4 pixels. Five hundred would clash with a hundred, which, for the sake of simplicity, I still wanted to keep as straightforward as possible.
Displaying negative numbers
Pybricks had already ingeniously made steps to display -1 to -99 by simply displaying an extra dimmed pixel in the gap area.
Negative one-digit numbers are much more visible when using the original numbers shifted to the right, with a bright negative sign on the left.
Negative two-digit numbers are much more visible using the slim numbers, still condensed, and the ones digit dimmed, with a bright negative sign on the left.
Following up on this concept, we have an easy solution for -100 to -199 by just overlaying the minus sign with the one sign in the hundreds place.
Extending this wacky usage to up to -499 to -199 is quite easy: simply move the minus sign below the number of 100 multipliers. I admit this might not be straightforward, yet it is still useful, so I decided to keep it.
Creating and decoding images using Pybricks
When I started to play with icons, it seemed logical to use the original LEGO approach, creating a two-dimensional array of brightness values between 0-100. This seemed quite excessive, so I quickly moved to a two-dimensional array between 0-10 to make it easier and also experimented with the string-based approach of Anton: “00900:09090:00900:00900:09990” or even “00a00:0a0a0:00a00:00a00:0aaa0” to use the hex to display 10*10=100 brightness.
def display_number(value):
_PB_DIGITS_5X3 = [
[0b111,0b101,0b101,0b101,0b111],
[0b010,0b110,0b010,0b010,0b111],
[0b111,0b001,0b111,0b100,0b111],
[0b111,0b001,0b111,0b001,0b111],
[0b101,0b101,0b111,0b001,0b001],
[0b111,0b100,0b111,0b001,0b111],
[0b111,0b100,0b111,0b101,0b111],
[0b111,0b001,0b010,0b100,0b100],
[0b111,0b101,0b111,0b101,0b111],
[0b111,0b101,0b111,0b001,0b111]
]
_PB_DIGITS_5X2 = [
[0b11,0b11,0b11,0b11,0b11],
[0b01,0b11,0b01,0b01,0b01],
[0b11,0b01,0b11,0b10,0b11],
[0b11,0b01,0b11,0b01,0b11],
[0b10,0b11,0b11,0b01,0b01],
[0b11,0b10,0b11,0b01,0b11],
[0b11,0b10,0b11,0b11,0b11],
[0b11,0b01,0b01,0b01,0b01],
[0b11,0b11,0b00,0b11,0b11],
[0b11,0b11,0b11,0b01,0b11],
]
_PB_MINUS_SIGN = [0b0,0b0,0b111,0b0,0b0]
_PB_PLUS_SIGN = [0b0,0b010,0b111,0b010,0b0]
_PB_EXCLAMATION_SIGN = [0b1,0b1,0b1,0b0,0b1]
def decode(input, brightness, shift):
return Matrix(
[
[
(((line>>(4-i-shift))&1)*brightness if 5>i+shift else 0)
for i in range(5)
] for line in input
])
def decodedigit(digit, is_normal, brightness, shift):
if is_normal: return decode(_PB_DIGITS_5X3[digit], brightness, shift)
else: return decode(_PB_DIGITS_5X2[digit], brightness, shift)
However remembered to check the approach from Pybricks, and that is the current preferred approach, simply adding a bit mask constant “0b010,0b110,0b010,0b010,0b111” getting rid of any extra spaces and giving the display function a chance to adding the shift and dim parameters.
Fun and next steps
Combining my hobbies is always fun. This project gave me a fantastic opportunity to work with LEGO, robotics, fonts, and typography, so it gave me an awesome time. Hope this will give some fun and help to some of your next projects as well.
As a next step, I am submitting a feature request to Pybricks to improve the numbering system for all of us. Please feel free to watch or join the discussion as there might be further options to enhance this solution.











































