Try using colorsys:

import colorsys
colorsys.hsv_to_rgb(0.5, 0.5, 0.4)

Output:

(0.2, 0.4, 0.4)

An example could be:

import matplotlib
import matplotlib.pyplot as plt
import colorsys

h, s, v = 0.83, 1.0, 0.50
# RGB values are from 0 to 1, NOT from 0 to 255
r, g, b = colorsys.hsv_to_rgb(h, s, v)
print(r, g, b)

rect1 = matplotlib.patches.Rectangle((-200, -100), 400, 200, color=[r, g, b])
plt.axes().add_patch(rect1)
plt.show()

To see why you may be having troubles in displaying color using imshow, refer to: Printing one color using imshow

Answer from Mateo Lara on Stack Overflow
๐ŸŒ
Matplotlib
matplotlib.org โ€บ 2.1.2 โ€บ api โ€บ _as_gen โ€บ matplotlib.colors.hsv_to_rgb.html
matplotlib.colors.hsv_to_rgb โ€” Matplotlib 2.1.2 documentation
convert hsv values in a numpy array to rgb values all values assumed to be in range [0, 1] ยฉ Copyright 2002 - 2012 John Hunter, Darren Dale, Eric Firing, Michael Droettboom and the Matplotlib development team; 2012 - 2017 The Matplotlib development team. Last updated on Feb 08, 2018.
๐ŸŒ
Matplotlib
matplotlib.org โ€บ 2.1.1 โ€บ api โ€บ _as_gen โ€บ matplotlib.colors.hsv_to_rgb.html
matplotlib.colors.hsv_to_rgb โ€” Matplotlib 2.1.1 documentation
convert hsv values in a numpy array to rgb values all values assumed to be in range [0, 1] ยฉ Copyright 2002 - 2012 John Hunter, Darren Dale, Eric Firing, Michael Droettboom and the Matplotlib development team; 2012 - 2017 The Matplotlib development team. Last updated on Dec 11, 2017.
Find elsewhere
๐ŸŒ
Matplotlib
matplotlib.org โ€บ 2.1.0 โ€บ api โ€บ _as_gen โ€บ matplotlib.colors.hsv_to_rgb.html
matplotlib.colors.hsv_to_rgb โ€” Matplotlib 2.1.0 documentation
convert hsv values in a numpy array to rgb values all values assumed to be in range [0, 1] ยฉ Copyright 2002 - 2012 John Hunter, Darren Dale, Eric Firing, Michael Droettboom and the Matplotlib development team; 2012 - 2017 The Matplotlib development team. Last updated on Oct 13, 2017.
Top answer
1 of 9
64

That function expects decimal for s (saturation) and v (value), not percent. Divide by 100.

>>> import colorsys

# Using percent, incorrect
>>> test_color = colorsys.hsv_to_rgb(359,100,100)
>>> test_color
(100, -9900.0, -9900.0)

# Using decimal, correct
>>> test_color = colorsys.hsv_to_rgb(1,1,1)
>>> test_color
(1, 0.0, 0.0)

If you would like the non-normalized RGB tuple, here is a function to wrap the colorsys function.

def hsv2rgb(h,s,v):
    return tuple(round(i * 255) for i in colorsys.hsv_to_rgb(h,s,v))

Example functionality

>>> hsv2rgb(0.5,0.5,0.5)
(64, 128, 128)
2 of 9
27

If you like performance, it's best to avoid imports and use your own optimized code

Here's GIMP's code ported to python, tested at 99% acuracy, and improved for performance:
(this code happens to match colorsys almost exactly)

scalar = float # a scale value (0.0 to 1.0)
def hsv_to_rgb( h:scalar, s:scalar, v:scalar, a:scalar ) -> tuple:
    if s:
        if h == 1.0: h = 0.0
        i = int(h*6.0); f = h*6.0 - i
        
        w = v * (1.0 - s)
        q = v * (1.0 - s * f)
        t = v * (1.0 - s * (1.0 - f))
        
        if i==0: return (v, t, w, a)
        if i==1: return (q, v, w, a)
        if i==2: return (w, v, t, a)
        if i==3: return (w, q, v, a)
        if i==4: return (t, w, v, a)
        if i==5: return (v, w, q, a)
    else: return (v, v, v, a)

output:

>>> hsv_to_rgb( 359/360.0, 1.0, 1.0, 1.0 )
(1.0, 0.0, 0.016666666666666607, 1.0)

Using an if-chain like above is actually faster than using elif

Using a wrapper, like in Cyber's answer, takes a few extra steps for the interpreter to perform.
To add, the for loop in Cyber's example is a real performance killer when used like that

If you want slightly more performance, simply do this:
(I won't say this is the best possible performance, but it's certainly better)

scalar = float # a scale value (0.0 to 1.0)
def hsv_to_rgb( h:scalar, s:scalar, v:scalar, a:scalar ) -> tuple:
    a = int(255*a)
    if s:
        if h == 1.0: h = 0.0
        i = int(h*6.0); f = h*6.0 - i
        
        w = int(255*( v * (1.0 - s) ))
        q = int(255*( v * (1.0 - s * f) ))
        t = int(255*( v * (1.0 - s * (1.0 - f)) ))
        v = int(255*v)
        
        if i==0: return (v, t, w, a)
        if i==1: return (q, v, w, a)
        if i==2: return (w, v, t, a)
        if i==3: return (w, q, v, a)
        if i==4: return (t, w, v, a)
        if i==5: return (v, w, q, a)
    else: v = int(255*v); return (v, v, v, a)

^ this guarantees int() output with a range of 255 (the input is still the same)

>>> hsv_to_rgb( 359/360.0, 1.0, 1.0, 1.0 )
(255, 0, 4, 255)

NOTE: this code tests just as accurate as colorsys to GIMP (99% correct):

TIP: stay away from 3rd-party where possible, try the direct approach if you can.
exculusions: compiled C extensions such as PIL or NumPy, or ctypes wrappers such as PyOpenGL (uses the DLL)