This is a somewhat complicated question, see more discussion here: https://graphicdesign.stackexchange.com/questions/92984/how-can-i-tell-basic-color-a-hex-code-is-closest-to

I don't know of any library or implementation that already exists for this. If you really need this functionality though and don't need it to be insanely precise, what you can do is use a color table with the colors you want to classify, e.g.

    Black   #000000     (0,0,0)
    White   #FFFFFF     (255,255,255)
    Red     #FF0000     (255,0,0)
    Lime    #00FF00     (0,255,0)
    Blue    #0000FF     (0,0,255)
    Yellow  #FFFF00     (255,255,0)
    Cyan / Aqua     #00FFFF     (0,255,255)
    Magenta / Fuchsia   #FF00FF     (255,0,255)
    Silver  #C0C0C0     (192,192,192)
    Gray    #808080     (128,128,128)
    Maroon  #800000     (128,0,0)
    Olive   #808000     (128,128,0)
    Green   #008000     (0,128,0)
    Purple  #800080     (128,0,128)
    Teal    #008080     (0,128,128)
    Navy    #000080     (0,0,128)

(from https://www.rapidtables.com/web/color/RGB_Color.html)

And calculate which of these the given hex color is closest to. This isn't going to be completely accurate because of the way we perceive specific colors on the spectrum, but I don't think this problem has a general solution anyways so approximation may be the only path forward.

Answer from Tyler Aldrich on Stack Overflow
🌐
SchemeColor
schemecolor.com › python-logo-colors.php
Python Logo Colors with Hex & RGB Codes
The Python Logo Colors with Hex & RGB Codes has 5 colors which are Nature Blue (#4B8BBE), Philadelphia (#306998), Kournikova (#FFE873), Bright Sun (#FFD43B) and Storm Dust (#646464).
🌐
GeeksforGeeks
geeksforgeeks.org › python › create-random-hex-color-code-using-python
Create Random Hex Color Code Using Python - GeeksforGeeks
July 23, 2025 - import random # Generating a random number in between 0 and 2^24 color = random.randrange(0, 2**24) # Converting that number from base-10 (decimal) to base-16 (hexadecimal) hex_color = hex(color) std_color = "#" + hex_color[2:] print(std_color) ...
🌐
Color Hex
color-hex.com › color-palette › 5949
Python Color Palette
Python color palette created by serena that consists #a4c330,#b3c330,#c2c330,#c3bd30,#c3b530 colors.
🌐
Jakob-bagterp
jakob-bagterp.github.io › colorist-for-python › reference › extended-colors › hex
Print Text with Hex Color Codes - Colorist for Python 🌈
The easiest way to print text with 24-bit RGB colors in terminal output using Hex codes and Colorist for Python. This documentation includes code examples.
🌐
Happycodeclub
happycodeclub.com › python-using-hex-colour-codes
Python : Using Hex Colour Codes – Happy Code Club
July 17, 2020 - In this project you’ll create a dictionary of colors which maps hard to recollect shade codes into friendly names. Python turtle have predefined shades such as ‘red’ and ‘white’ but you may also use hex color codes (you could have visible these within the HTML & CSS course.)Using ...
🌐
Webucator
webucator.com › home › articles › python › python color constants module
Python Color Constants Module | Webucator
August 24, 2021 - class RGB(Color): def hex_format(self): return '#{:02X}{:02X}{:02X}'.format(self.red,self.green,self.blue) Stores these constants in an OrderedDict. The colors are shown in the table below and the full code is shown below that.
🌐
IColorPalette
icolorpalette.com › color › python-blue
Python Blue Hex Code #3776AB — RGB, CMYK & HSL Color Values | iColorPalette
Color PickerColor MixerColor SchemesColor NamesColor ConvertersGaming Color CodesAll ColorsShades of a ColorWhat Colors Go WithSeasonal PalettesSkin Tone PaletteWCAG ... Python Blue hex code is #3776AB. RGB: 55, 118, 171 · HSL: 207°, 51%, 44% ·
Find elsewhere
🌐
Jakob-bagterp
jakob-bagterp.github.io › colorist-for-python › user-guide › extended-colors › hex
How to Add Hex Colors to Text - Colorist for Python 🌈
The 24-bit Hex color model covers over 16 million colors, and each color can be defined with a code in hexadecimal, for instance #00aaff or sometimes shortened to #0af, that can be broken down into a RGB value:
🌐
HolyPython
holypython.com › home › python visualization tutorial › colors with python
Colors with Python | HolyPython.com
March 27, 2021 - You can also use Matplotlib’s ListedColormap function to create custom colormaps from lists. ListedColormap(["darkorange", "gold", "lawngreen", "lightseagreen"]) ... You can also convert any Hex code to an RGB value since Hex is just a shorter representation of RGB colors.
🌐
Python Graph Gallery
python-graph-gallery.com › the python graph gallery › colors › available colors in matplotlib
Available colors in Matplotlib
1 week ago - as a string representing a hexadecimal color code (e.g., #FF0000 or #e9edc9), which allows you to specify any color
🌐
Html Colors
htmlcolors.com › brand-color › python
Python Color | Html Colors
Python have 3 hex colors that represent their brand, and they are ffde57, 4584b6, 646464.
Top answer
1 of 2
3

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.

2 of 2
0

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

  1. the color codes 0- 7 are "Standard" colors
  2. the color codes 8-15 are "High-intensity" colors
  3. the middle 216 codes provide more colors
  4. 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:

  1. Subtract the offset of 16
  2. Extract r/g/b_0to5
  3. Map the r/g/b_0to5 values that vary between 0 and 5 to values between 0 and 255 (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:

  1. Subtract the offset of 256-24 for the code_code
  2. 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_dist could/should use a better color distance metric. See the Color Difference Wikipedia article
🌐
GeeksforGeeks
geeksforgeeks.org › python › matplotlib-colors-to_hex-in-python
Matplotlib.colors.to_hex() in Python - GeeksforGeeks
July 12, 2025 - import matplotlib.pyplot as plt from matplotlib import colors import numpy as np # dummy data to build the grid data = np.random.rand(10, 10) * 20 # converting into hex color code hex_color=matplotlib.colors.to_hex([ 0.47, 0.0, 1.0 ]) # create ...
🌐
BrandPalettes
brandpalettes.com › home › technology & software › python
Python logo colors - HEX, RGB, CMYK and Pantone
The Python logo palette has 5 colors: Cyan-Blue Azure (#4B8BBE), Lapis Lazuli (#306998), Shandy (#FFE873), Sunglow (#FFD43B) and Granite Gray (#646464). Copy the complete palette in HEX, RGB, CMYK and Pantone formats.
🌐
W3Schools
w3schools.com › colors › colors_hexadecimal.asp
Colors HEX
To display white, set all color parameters to ff, like this: #ffffff. Hexadecimal color values are supported in all browsers.
🌐
Government Analysis Function
analysisfunction.civilservice.gov.uk › policy-store › codes-for-accessible-colours
Using our colour palettes in Microsoft, R and Python – Government Analysis Function
May 10, 2023 - Add in the the hex code ‘#BFBFBF’ to the hex code box at the bottom and click ‘OK’. Repeat steps 7 to 11 until all of the non focus object are the same colour. ... The Analysis Standards and Pipelines (ASAP) team have also created packages in Python and R for the colour palettes.
🌐
Design Pieces
designpieces.com › palette › python-color-palette-hex-and-rgb
Python Color Palette (Hex and RGB) — Design Pieces
Code · CSS · HTML · JavaScript · Ruby · Software · Software · Adobe Illustrator · Adobe Photoshop · Google Analytics · Instagram · Wordpress · English · English · English · Español · Français · Updated 1/28/17 · The brand color palette for Python is made up of 3 colors. Python Mustard Hex: #ffde57 RGB: 255, 222, 87 ·