This somewhat depends on what platform you are on. The most common way to do this is by printing ANSI escape sequences. For a simple example, here's some Python code from the Blender build scripts:
class bcolors:
HEADER = '\033[95m'
OKBLUE = '\033[94m'
OKCYAN = '\033[96m'
OKGREEN = '\033[92m'
WARNING = '\033[93m'
FAIL = '\033[91m'
ENDC = '\033[0m'
BOLD = '\033[1m'
UNDERLINE = '\033[4m'
To use code like this, you can do something like:
print(bcolors.WARNING + "Warning: No active frommets remain. Continue?" + bcolors.ENDC)
Or, with Python 3.6+:
print(f"{bcolors.WARNING}Warning: No active frommets remain. Continue?{bcolors.ENDC}")
This will work on unixes including OS X, Linux and Windows (provided you use ANSICON, or in Windows 10 provided you enable VT100 emulation). There are ANSI codes for setting the color, moving the cursor, and more.
If you are going to get complicated with this (and it sounds like you are if you are writing a game), you should look into the "curses" module, which handles a lot of the complicated parts of this for you. The Python Curses HowTO is a good introduction.
If you are not using extended ASCII (i.e., not on a PC), you are stuck with the ASCII characters below 127, and '#' or '@' is probably your best bet for a block. If you can ensure your terminal is using a IBM extended ASCII character set, you have many more options. Characters 176, 177, 178 and 219 are the "block characters".
Some modern text-based programs, such as "Dwarf Fortress", emulate text mode in a graphical mode, and use images of the classic PC font. You can find some of these bitmaps that you can use on the Dwarf Fortress Wiki see (user-made tilesets).
The Text Mode Demo Contest has more resources for doing graphics in text mode.
Answer from joeld on Stack OverflowThis somewhat depends on what platform you are on. The most common way to do this is by printing ANSI escape sequences. For a simple example, here's some Python code from the Blender build scripts:
class bcolors:
HEADER = '\033[95m'
OKBLUE = '\033[94m'
OKCYAN = '\033[96m'
OKGREEN = '\033[92m'
WARNING = '\033[93m'
FAIL = '\033[91m'
ENDC = '\033[0m'
BOLD = '\033[1m'
UNDERLINE = '\033[4m'
To use code like this, you can do something like:
print(bcolors.WARNING + "Warning: No active frommets remain. Continue?" + bcolors.ENDC)
Or, with Python 3.6+:
print(f"{bcolors.WARNING}Warning: No active frommets remain. Continue?{bcolors.ENDC}")
This will work on unixes including OS X, Linux and Windows (provided you use ANSICON, or in Windows 10 provided you enable VT100 emulation). There are ANSI codes for setting the color, moving the cursor, and more.
If you are going to get complicated with this (and it sounds like you are if you are writing a game), you should look into the "curses" module, which handles a lot of the complicated parts of this for you. The Python Curses HowTO is a good introduction.
If you are not using extended ASCII (i.e., not on a PC), you are stuck with the ASCII characters below 127, and '#' or '@' is probably your best bet for a block. If you can ensure your terminal is using a IBM extended ASCII character set, you have many more options. Characters 176, 177, 178 and 219 are the "block characters".
Some modern text-based programs, such as "Dwarf Fortress", emulate text mode in a graphical mode, and use images of the classic PC font. You can find some of these bitmaps that you can use on the Dwarf Fortress Wiki see (user-made tilesets).
The Text Mode Demo Contest has more resources for doing graphics in text mode.
There is also the Python termcolor module. Usage is pretty simple:
from termcolor import colored
print(colored('hello', 'red'), colored('world', 'green'))
It may not be sophisticated enough, however, for game programming and the "colored blocks" that you want to do...
To get the ANSI codes working on windows, first run
os.system('color')
linux - How to display rgb hex colors on terminal using python? - Unix & Linux Stack Exchange
How to set python font color in terminal ?
A Python module for terminal colors.
How do I print colored output to the terminal in Python? - Stack Overflow
Yes, there are, but not all terminals support it, some do it differently than others, you need to figure out what your terminal's capabilities are... In other words: it's possible, but you don't want to do it yourself.
The standard way of doing it is hence using a library, in the Python casr that would probably be Rich or Textual, depending on whether you just want pretty colorful text or also prompts, buttons, tables etc.
Solution for feature-rich/modern terminals (emulators and virtual consoles)
All the terminals that I currently have installed (Gnome Terminal, Xterm, Alacritty, Linux's virtual console) on my system support the escaped sequences:
- Set foreground color:
\033[38;2;{r};{g};{b}m - Set background color:
\033[48;2;{r};{g};{b}m
where {r}, {g}, {b} are placeholders for the specific RGB (channel) values. (I found these escape sequences documented in this very helpful and concise Gist https://gist.github.com/fnky/458719343aabd01cfb17a3a4f7296797.)
In python you can implement functions to change the foreground and background colors using these escape sequences:
SET_FOREGROUND_ESCAPE = "\033[38;2;{r};{g};{b}m"
SET_BACKGROUND_ESCAPE = "\033[48;2;{r};{g};{b}m"
def set_foreground(r, g, b):
print(SET_FOREGROUND_ESCAPE.format(r=r, g=g, b=b), end="")
def set_background(r, g, b):
print(SET_BACKGROUND_ESCAPE.format(r=r, g=g, b=b), end="")
# Example usage: print red text on a cyan background
set_foreground(255, 0, 0)
set_background( 0, 255, 255)
print("Red on Cyan")
To work with hex codes, you need a function that converts hex codes to RGB tuples:
def hex_to_rgb(rgb_hex):
# Unpack the 24-bit `rgb_hex` integer to a RGB tuple of 3 8-bit integers
return ( rgb_hex>>16 , # r is stored in the most significant 8 bits
(rgb_hex>> 8)&0b1111_1111, # g is stored in the "middle" 8 bits
rgb_hex &0b1111_1111) # b is stored in the least significant 8 bits
# Example usage
RED_HEX = 0xFF0000
CYAN_HEX = 0x00FFFF
assert hex_to_rgb(RED_HEX ) == (255, 0, 0)
assert hex_to_rgb(CYAN_HEX) == ( 0, 255, 255)
This conversion function allows us to implement the new functions set_foreground_hex and set_background_hex as counterparts to set_foreground and set_background:
def set_foreground_hex(rgb_hex):
set_foreground(*hex_to_rgb(rgb_hex))
def set_background_hex(rgb_hex):
set_background(*hex_to_rgb(rgb_hex))
Now we can set the foreground and background color using hex codes:
set_foreground_hex(0xFF0000)
set_background_hex(0x00FFFF)
print("Red on Cyan")
(You should bake rgb_to_hex and set_fore-/background directly into set_fore-/background_hex if you want performance/resource-efficiency because function call overhead is high in Python.)
Importantly, this also worked on the terminal that you get when you don't have a desktop environment installed (but the Arch Linux wiki gives me reason to believe that the kernel translates the 24-bit color to 256 color codes), meaning that this code will work in homelab/datacenter contexts, provided you are running a relatively new kernel version.
Minimal/old terminals
As pointed out in the question, the traditional way of setting the color in a terminal is to provide a color_code ranging from 0 to 255 in the escape sequences:
- Set foreground color code
\033[38;5;{color_code}m - Set background color code
\033[48;5;{color_code}m
These may be the only escape sequences supported by minimal or old terminals, despite having not encountered this situation personally.
As seen in this Wikipedia article section
- the color codes
0- 7are "Standard" colors - the color codes
8-15are "High-intensity" colors - the middle 216 codes provide more colors
- and the last 24 codes provide more grayscale shades
Assuming that we know the exact RGB values for some or all of these codes, we can convert a RGB value to a color code by finding the nearest matching code:
import math
term_color_code_rgb_values = []
def populate_term_color_code_rgb_values():
...
populate_term_color_code_rgb_values()
def calc_color_dist(r1, g1, b1, r2, g2, b2):
# Euclidean distance between <r1, g1, b1> and <r2, g2, b2>.
# Better color distance metrics exist!
r_delta = r2 - r1
g_delta = g2 - g1
b_delta = b2 - b1
return math.sqrt(r_delta*r_delta + g_delta*g_delta + b_delta*b_delta)
def find_nearest_term_color_code_from_rgb(r, g, b):
# Linearly search for the nearest color code.
# A faster algorithm could be implemented!
min_color_dist = 0xFFFF_FFFF_FFFF # arbitrary large number
nearest_color_code = -1
for color_code, (r2, g2, b2) in enumerate(term_color_code_rgb_values):
rgb_unknown = r2 == -1
if rgb_unknown:
continue
color_dist = calc_color_dist(r, g, b, r2, g2, b2)
if color_dist < min_color_dist:
min_color_dist = color_dist
nearest_color_code = color_code
return nearest_color_code
# `set_fore-/background_color_code_from_rgb_hex` use similar
# logic to the other functions for setting the fore- and background.
def set_foreground_color_code_from_rgb_hex(rgb_hex):
return print(
"\033[38;5;{color_code}m".format(
color_code=find_nearest_term_color_code_from_rgb(
rgb_hex>>16 ,
(rgb_hex>> 8)&0b1111_1111,
rgb_hex &0b1111_1111)))
def set_background_color_code_from_rgb_hex(rgb_hex):
return print(
"\033[48;5;{color_code}m".format(
color_code=find_nearest_term_color_code_from_rgb(
rgb_hex>>16 ,
(rgb_hex>> 8)&0b1111_1111,
rgb_hex &0b1111_1111)))
set_foreground_color_code_from_rgb_hex(0xFF0000)
set_background_color_code_from_rgb_hex(0x00FFFF)
print("Red on Cyan")
To complete the above code we need to implement populate_term_color_code_rgb_values to populate term_color_code_rgb_values with RGB tuples (we set the empty value (-1, -1, -1) if the exact RGB value for the color code cannot be computed). From personal experimentation, it appears that the first 16 "Standard" and "High-intensity" color codes map to different RGB values depending on the terminal, whereas the remaining 216 color codes and the last 24 grayscale color codes stay the same, so we will only compute RGB values in the latter 2 cases.
The 216 color codes adhere to the formula:
color_code = (r_0to5*6^2 + g_0to5*6^1 + b_0to5*6^0) + 16
r/g/b_0to5 can each have one of 6 values from 0 to 5: r/g/b_0to5 in {0, 1, 2, 3, 4, 5} == True. There are 6 possible values for each variable because the total number of possible combinations equals 216: 6*6*6 = 6^3 = 216. To convert the color codes in this 216 range to RGB we must:
- Subtract the offset of
16 - Extract
r/g/b_0to5 - Map the
r/g/b_0to5values that vary between0and5to values between0and255(inclusive)
Naively, you might think that the mapping in step 3 uses even spacing. E.g.:
0 -> 0*255/5
1 -> 1*255/5
2 -> 2*255/5
3 -> 3*255/5
4 -> 4*255/5
5 -> 5*255/5
In reality, the interval between the first and second value is 95 and the remaining values are spaced by an interval of 40 (as verified by experimentation):
0 -> 0
1 -> 95
2 -> 95 + 40
3 -> 95 + 80
4 -> 95 + 120
5 -> 95 + 160
With the mapping, we can now implement the code to populate term_color_code_rgb_values for the 216 codes:
if 16 <= color_code < 256-24:
color_code -= 16
color_code, b_0to5 = divmod(color_code, 6)
color_code, g_0to5 = divmod(color_code, 6)
color_code, r_0to5 = divmod(color_code, 6)
map_0to5_to_0to255 = [0, 0+95,
40+95,
80+95,
120+95,
160+95]
term_color_code_rgb_values.append((
map_0to5_to_0to255[r_0to5],
map_0to5_to_0to255[g_0to5],
map_0to5_to_0to255[b_0to5]))
The last 24 grayscale color codes are easier compute:
- Subtract the offset of
256-24for thecode_code - Compute the the grayscale value
10*(color_code+1) - 2
if color_code >= 256-24:
color_code -= 256-24
grayscale_0to255 = 10*(color_code+1) - 2
term_color_code_rgb_values.append(
(grayscale_0to255, grayscale_0to255, grayscale_0to255))
The final implementation of populate_term_color_code_rgb_values is as follows:
term_color_code_rgb_values = []
def populate_term_color_code_rgb_values():
for color_code in range(256):
if 16 <= color_code < 256-24:
color_code -= 16
color_code, b_0to5 = divmod(color_code, 6)
color_code, g_0to5 = divmod(color_code, 6)
color_code, r_0to5 = divmod(color_code, 6)
map_0to5_to_0to255 = [0, 0+95,
40+95,
80+95,
120+95,
160+95]
term_color_code_rgb_values.append((
map_0to5_to_0to255[r_0to5],
map_0to5_to_0to255[g_0to5],
map_0to5_to_0to255[b_0to5]))
elif color_code >= 256-24:
color_code -= 256-24
grayscale_0to255 = 10*(color_code+1) - 2
term_color_code_rgb_values.append(
(grayscale_0to255, grayscale_0to255, grayscale_0to255))
else:
term_color_code_rgb_values.append((-1, -1, -1))
Very old/minimal terminals
Very old or minimal terminals may only support the first 8 or 16 color codes. As mentioned, the exact RGB values for these color codes are implementation-dependent. That being said, they follow a consistent scheme where:
- The most significant bit is set if the color is "high-intensity"
- The least significant bit is set if the color has a red component
- The 2nd least significant bit is set if the color has a green component
- The 3rd least significant bit is set if the color has a blue component
Code Binary is_high_intensity has_r has_g has_ b
0 0b0000 0 0 0 0 Standard Black
1 0b0001 0 1 0 0 Standard Red
2 0b0010 0 0 1 0 Standard Green
3 0b0011 0 1 1 0 Standard Yellow
4 0b0100 0 0 0 1 Standard Blue
5 0b0101 0 1 0 1 Standard Magenta
6 0b0110 0 0 1 1 Standard Cyan
7 0b0111 0 1 1 1 Standard White
8 0b1000 1 0 0 0 High-Intensity Black
9 0b1001 1 1 0 0 High-Intensity Red
10 0b1010 1 0 1 0 High-Intensity Green
11 0b1011 1 1 1 0 High-Intensity Yellow
12 0b1100 1 0 0 1 High-Intensity Blue
13 0b1101 1 1 0 1 High-Intensity Magenta
14 0b1110 1 0 1 1 High-Intensity Cyan
15 0b1111 1 1 1 1 High-Intensity White
With a bit of bit-shifting we can easily extract this information:
for color_code in range(16):
is_high_intensity = color_code>>3
has_r = color_code &1
has_g = (color_code>>1)&1
has_b = (color_code>>2)&1
The calculation for the exact RGB value of the color code is dependent on the terminal. On virtual consoles I observed that the CGA color palette is used. The following code works for CGA:
rgb = (has_r*0xAA + is_high_intensity*0x55,
has_g*0xAA + is_high_intensity*0x55,
has_b*0xAA + is_high_intensity*0x55)
For Xterm the following works:
factor = 0xFF if is_high_intensity else 0xCD
rgb = (has_r*factor, has_g*factor, has_b*factor)
The Gnome Terminal does not seem to follow a formula and seems to have uniquely chosen values for each of the 16 color codes.
Depending on your use cases you could change populate_term_color_code_rgb_values to use one of these computations or a best-guess average.
Detecting terminal capabilities
There are many ways to obtain information about the color model that a terminal supports. The Arch Linux wiki page has a lot of information on the topic. An autodetection implementation could do something like (pseudocode):
if 24-bit color escape sequence support
use "\033[38;2;{r};{g};{b}m" and "\033[48;2;{r};{g};{b}m"
else if $( tput --colors ) == 256
use 216 and grayscale color code to RGB mapping
else
use first 16 color codes to CGA RGB mapping
Many commands such as ls and grep use the flag --colors=auto|always|never. It's probably worth checking out how they implement auto though the coreutils codebase is not the most readable IMO.
For an initial implementation of a command line application I would just turn colors off by default and let the user optional specify which capabilities their terminal supports. Autodetection is rabbit hole that you can go down once you have something working.
Notes
- I wrote this answer because I wanted to document the information that I found somewhere
calc_color_distcould/should use a better color distance metric. See the Color Difference Wikipedia article
Hi,
When I run a python program that needs some debugging, the errors displayed on terminal screen mainly show up in some kind of reddish burgundy with low contrast with the black background when backlight is low.
Is there a way to set the font color to white or blue for all python output in terminal ?
Actually I have found a hack that is to pipe the output of the python command to a command that changes the ANSI color code emitted: python cmd.py |& change_color , but I'd prefer not to be compelled to use that if possible
Thanks for your help !
Hey, r/Python community!
I wanted to share an amazing discovery I made recently. There's a fantastic module out there for adding colors to your terminal in Python!
This module, called Chromify, offers a wide range of options to bring your terminal to life with vibrant colors. You can play around with different color formats like RGB, hex, hsl, hsv, CMYK, and CSS. It even includes over 200 predefined colors that you can easily use.
Chromify also provides useful additional classes and functions like color conversion, horizontal and vertical gradients, cursor control, styles, and special characters.
It's incredible how easy it is to use Chromify in your Python projects and elevate the visual experience of the terminal. I encourage you to give it a try and explore all the possibilities it offers!
You can find Chromify on PyPi, and its repository on GitHub for more information and to start experimenting with colors in your terminal. I'm sure you'll love it!
I hope this information is helpful to the r/Python community. Have fun exploring Chromify and adding a special touch to your Python projects with terminal colors!
Good luck and happy coding! ๐
- PyFinder -- PyPi AI Finder ๐ค
Source: https://pypi.org/project/Chromify/ -- pip install Chromify
Would the Python termcolor module do? This would be a rough equivalent for some uses.
from termcolor import colored
print colored('hello', 'red'), colored('world', 'green')
The example is right from this post, which has a lot more. Here is a part of the example from docs
import sys
from termcolor import colored, cprint
text = colored('Hello, World!', 'red', attrs=['reverse', 'blink'])
print(text)
cprint('Hello, World!', 'green', 'on_red')
A specific requirement was to set the color, and presumably other terminal attributes, so that all following prints are that way. While I stated in the original post that this is possible with this module I now don't think so. See the last section for a way to do that.
However, most of the time we print short segments of text in color, a line or two. So the interface in these examples may be a better fit than to 'turn on' a color, print, and then turn it off. (Like in the Perl example shown.) Perhaphs you can add optional argument(s) to your print function for coloring the output as well, and in the function use module's functions to color the text. This also makes it easier to resolve occasional conflicts between formatting and coloring. Just a thought.
Here is a basic approach to set the terminal so that all following prints are rendered with a given color, attributes, or mode.
Once an appropriate ANSI sequence is sent to the terminal, all following text is rendered that way. Thus if we want all text printed to this terminal in the future to be bright/bold red, print ESC[ followed by the codes for "bright" attribute (1) and red color (31), followed by m
# print "\033[1;31m" # this would emit a new line as well
import sys
sys.stdout.write("\033[1;31m")
print "All following prints will be red ..."
To turn off any previously set attributes use 0 for attribute, \033[0;35m (magenta).
To suppress a new line in python 3 use print('...', end=""). The rest of the job is about packaging this for modular use (and for easier digestion).
File colors.py
RED = "\033[1;31m"
BLUE = "\033[1;34m"
CYAN = "\033[1;36m"
GREEN = "\033[0;32m"
RESET = "\033[0;0m"
BOLD = "\033[;1m"
REVERSE = "\033[;7m"
I recommend a quick read through some references on codes. Colors and attributes can be combined and one can put together a nice list in this package. A script
import sys
from colors import *
sys.stdout.write(RED)
print "All following prints rendered in red, until changed"
sys.stdout.write(REVERSE + CYAN)
print "From now on change to cyan, in reverse mode"
print "NOTE: 'CYAN + REVERSE' wouldn't work"
sys.stdout.write(RESET)
print "'REVERSE' and similar modes need be reset explicitly"
print "For color alone this is not needed; just change to new color"
print "All normal prints after 'RESET' above."
If the constant use of sys.stdout.write() is a bother it can be be wrapped in a tiny function, or the package turned into a class with methods that set terminal behavior (print ANSI codes).
Some of the above is more of a suggestion to look it up, like combining reverse mode and color. (This is available in the Perl module used in the question, and is also sensitive to order and similar.)
A convenient list of escape codes is surprisingly hard to find, while there are many references on terminal behavior and how to control it. The Wiki page on ANSI escape codes has all information but requires a little work to bring it together. Pages on Bash prompt have a lot of specific useful information. Here is another page with straight tables of codes. There is much more out there.
This can be used alongside a module like termocolor.
I suggest sty. It's similar to colorama, but less verbose and it supports 8bit and 24bit colors. You can also extend the color register with your own colors.
Examples:
from sty import fg, bg, ef, rs
foo = fg.red + 'This is red text!' + fg.rs
bar = bg.blue + 'This has a blue background!' + bg.rs
baz = ef.italic + 'This is italic text' + rs.italic
qux = fg(201) + 'This is pink text using 8bit colors' + fg.rs
qui = fg(255, 10, 10) + 'This is red text using 24bit colors.' + fg.rs
# Add custom colors:
from sty import Style, RgbFg
fg.orange = Style(RgbFg(255, 150, 50))
buf = fg.orange + 'Yay, Im orange.' + fg.rs
print(foo, bar, baz, qux, qui, buf, sep='\n')

Demo:
