Metro Sign Build Log 3: Working with LED Display Libraries



Hope you enjoyed getting your components together! If this seems like a project you want to take on, or you just want to see how mine goes, consider subscribing on Substack so you don’t miss a build log!


Now that we have our MatrixPortal working, let’s get some text up on our LED panels! We’re going to be using two key libraries to draw text (and later icons) on the panels: adafruit_matrixportal.matrix and displayio. Displaying content on the panels using these libraries involves creating and displaying displayio groups, which can nest in each other to form more complex displays. We’re going to create a group for each of the text areas we want to create down the line, but for now we only need to create a root group as our largest group container, and a label group for our first text label. I followed this guide and chose to create a new file to run all the displayio functions. In addition to the displayio library, you’re going to want a few more:

  • terminalio: this drives the default font for text
  • adafruit_display_text.label: this creates the text labels needed to display text

Creating our display_manager class

Now we can create our new display_manager class and set up initialization:

class display_manager(displayio.Group):
    def __init__(
        self.display = display
        # set up label groups
        self.root_group = displayio.Group()

        self._label_group = displayio.Group(x=4, y=8)

We’re initializing the display, then creating two nested displayio.Groups, our root_group at the top level and our label_group at the bottom level. We’re going to add our text labels to our label_group, then display our root_group. This structure allows us to continue adding different groups to our root_group and display them all at once. Note that we’ve passed in some optional parameters in our label_group that will pin the group to specific x and y coordinates; this isn’t necessary now, but will be later for shifting our different label groups around each other!

Now we need to actually add our text label to our label_group:

# set up text label
self.label_text = Label(terminalio.FONT)
self.label_text.color = 0xFFFFFF

Here we’re spinning up our new label and setting the color to white in hexadecimal. We also have to add our label to our label_group, and we should be good to go!

The other function we need to create is a way to actually update the text label we just created; let’s make a new function that intakes a string and displays that string. Note that displayio doesn’t do any formatting, so long strings will just run off of the panel!

def update_label(self, input_text):
    self.label_text.text = input_text

One more function you’ll want is a way to refresh the display; this is super simple:

# refresh the root group on the display
def refresh_display(self):

Calling our new display_manager in

NOTE: don’t forget to import our file into our file!

Back in our file, we’ll pass in a Matrix display object as part of our display initialization. I’ll be honest, I was doing this in a very convoluted way on my first iteration, going deeper into the libraries than necessary; the MatrixPortal M4 tutorial covers the hierarchy well if you want to learn more about the different levels of display and network classes under the main MatrixPortal library. Notice the optional width and height parameters we pass into the matrix; this is what merges our two LED panels into one display.

matrix = Matrix(width=128, height=32, bit_depth=2, tile_rows=1)
display_manager = display_manager.display_manager(matrix.display)

Now that we have our display_manager object, we can call the update_text function and refresh the display to actually display text on our panels! Sharing the full code for both and at the end of the post.


We’ve met our Hello World! criteria! In the next log, we’ll tackle our first API implementation so we can get some real Metro data on our panel. If you have any improvement suggestions, questions, or you can’t get the code to work, leave a comment or let me know on Twitter; appreciate your feedback!

Code Examples