Skip to content

Instantly share code, notes, and snippets.

@RoboDonut
Last active February 23, 2022 01:17
Show Gist options
  • Save RoboDonut/83ec5909621a6037f275799032e97563 to your computer and use it in GitHub Desktop.
Save RoboDonut/83ec5909621a6037f275799032e97563 to your computer and use it in GitHub Desktop.
# gradients based on http://bsou.io/posts/color-gradients-with-python
def hex_to_RGB(hex):
''' "#FFFFFF" -> [255,255,255] '''
# Pass 16 to the integer function for change of base
return [int(hex[i:i+2], 16) for i in range(1,6,2)]
def RGB_to_hex(RGB):
''' [255,255,255] -> "#FFFFFF" '''
# Components need to be integers for hex to make sense
RGB = [int(x) for x in RGB]
return "#"+"".join(["0{0:x}".format(v) if v < 16 else
"{0:x}".format(v) for v in RGB])
def color_dict(gradient):
''' Takes in a list of RGB sub-lists and returns dictionary of
colors in RGB and hex form for use in a graphing function
defined later on '''
return {"hex":[RGB_to_hex(RGB) for RGB in gradient],
"r":[RGB[0] for RGB in gradient],
"g":[RGB[1] for RGB in gradient],
"b":[RGB[2] for RGB in gradient]}
def linear_gradient(start_hex, finish_hex="#FFFFFF", n=10):
''' returns a gradient list of (n) colors between
two hex colors. start_hex and finish_hex
should be the full six-digit color string,
inlcuding the number sign ("#FFFFFF") '''
# Starting and ending colors in RGB form
s = hex_to_RGB(start_hex)
f = hex_to_RGB(finish_hex)
# Initilize a list of the output colors with the starting color
RGB_list = [s]
# Calcuate a color at each evenly spaced value of t from 1 to n
for t in range(1, n):
# Interpolate RGB vector for color at the current value of t
curr_vector = [
int(s[j] + (float(t)/(n-1))*(f[j]-s[j]))
for j in range(3)
]
# Add it to our list of output colors
RGB_list.append(curr_vector)
return color_dict(RGB_list)
def polylinear_gradient(colors, n):
''' returns a list of colors forming linear gradients between
all sequential pairs of colors. "n" specifies the total
number of desired output colors '''
# The number of colors per individual linear gradient
n_out = int(float(n) / (len(colors) - 1))
# returns dictionary defined by color_dict()
gradient_dict = linear_gradient(colors[0], colors[1], n_out)
if len(colors) > 1:
for col in range(1, len(colors) - 1):
next = linear_gradient(colors[col], colors[col+1], n_out)
for k in ("hex", "r", "g", "b"):
# Exclude first point to avoid duplicates
gradient_dict[k] += next[k][1:]
return gradient_dict
fact_cache = {}
def fact(n):
''' Memoized factorial function '''
try:
return fact_cache[n]
except(KeyError):
if n == 1 or n == 0:
result = 1
else:
result = n*fact(n-1)
fact_cache[n] = result
return result
def bernstein(t,n,i):
''' Bernstein coefficient '''
binom = fact(n)/float(fact(i)*fact(n - i))
return binom*((1-t)**(n-i))*(t**i)
def bezier_gradient(colors, n_out=100):
''' Returns a "bezier gradient" dictionary
using a given list of colors as control
points. Dictionary also contains control
colors/points. '''
# RGB vectors for each color, use as control points
RGB_list = [hex_to_RGB(color) for color in colors]
n = len(RGB_list) - 1
def bezier_interp(t):
''' Define an interpolation function
for this specific curve'''
# List of all summands
summands = [
map(lambda x: int(bernstein(t,n,i)*x), c)
for i, c in enumerate(RGB_list)
]
# Output color
out = [0,0,0]
# Add components of each summand together
for vector in summands:
for c in range(3):
out[c] += vector[c]
return out
gradient = [
bezier_interp(float(t)/(n_out-1))
for t in range(n_out)
]
# Return all points requested for gradient
return color_dict(gradient)
#color_dict = linear_gradient("#FFC300","#581845")
#color_dict=polylinear_gradient(("#07467A","#6D027C","#A0B800","#BD6D00","#07467A"), 500)
color_dict=bezier_gradient (("#07467A","#6D027C","#A0B800","#BD6D00","#07467A"),200)
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment