A good match for graphical output using assembly would be the linux framebuffer.
I would write some C code to do the opening of /dev/fb0 and set up the memory map. But once you have done that, you can pass the memory address of your framebuffer to your assembly code.
The linux framebuffer is just a big array of pixels, and you write to them directly. Maybe skip fonts for now, and use assembly to draw some geometric shapes, maybe some graphs.
There is this short guide.
But if you google, you can probably find more complete guides to the linux framebuffer.
I think you need to run a lfb app when X11 is not active. So just quit your display manager. Typically with
/etc/init.d/lightdm stop or
You may need some extra privileges to open /dev/fb0 though. Run as root, or give your user account access to the 'video' group.
Lastly, I want to note that there is something else than assembly and C, which sets somewhere between them, and is called intrinsics.
The nice thing about intrinsics is that you can program at a level, almost as low as assembly, but you don't have to think about registers at all. You can just use C variables, and have the compiler do the job of mapping them to registers.
Intrinsics, unlike C, will give you direct access to the CPU's SIMD operations, which means that you can process 4 (SSE), 8 (AVX) or 16 (AVX512) integer/float values in a single operation. They are the most powerful instructions on your CPU.