Reputation: 281
I am looking for a way to color objects based on the colors of nearby objects, and from what I've read it looks like linear interpolation is the thing to do.
I have looked through a lot (all?) of the posts on SO about linear interpolation for color in Python but haven't been able to make any of it work with my code.
I want to try and keep this as simple as possible for now. If I had a gradient that went from purple to white and two objects, how could I tell python: if object 1 is purple, make object 2 a lighter purple ?
Looking at this post, a function lerp is defined by:
def lerp(color1, color2, frac):
return color1 * (1 - frac) + color2 * frac
But I don't understand how to apply it. This post has a ton of suggestions, but it doesn't seem resolved, although it does contain a lot of interesting information about additive and subtractive coloring methods. I understand coloring is complex, and I don't want to make a redundant post, so I am hoping to really emphasize that I am looking for the most simple, rudimentary method to do something very simple, like make an object a lighter shade of purple if it is next to an object that is a darker purple.
For this example, I've created 3 polygons and colored them all magenta:
import matplotlib.pyplot as plt
from shapely.geometry import Point, LineString
# functions for plotting
def plot_coords(coords, color):
pts = list(coords)
x, y = zip(*pts)
# print(color)
plt.plot(x,y, color='k', linewidth=1)
plt.fill_between(x, y, facecolor=color)
def plot_polys(polys, color):
for poly, color in zip(polys, color):
plot_coords(poly.exterior.coords, color)
x = 0
y = 0
# make some points
points = [Point(x, y),
Point((x + 2), y),
Point((x - 2), y)]
#buffer points by 2 to make circles
circles = []
for point in points:
circles.append(point.buffer(2))
# plot 3 magenta circles
plot_polys(circles, "m"*3)
How could I use the above lerp function (or a different one) to color my circles on a gradient?
Note: I know I could use a pre-made palette from matplotlib, but my longer term goal is to understand the arithmetic that is controlling the color changes.
Thanks for your help!
Upvotes: 0
Views: 1875
Reputation: 25093
In the following, I don't use circles or polygons, just plain curves but I'm sure you'll get my point.
My 3 points, that is…
The color interpolation works in a straightforward manner if we can use real numbers for the color components, hence we define our colors in the RGB
space, using matplotlib.colors.to_rgb
.
The interpolation must be done on each, separate component of the two colors.
Eventually, we can specify a different color for each curve, using as our parameter the time shift of the sines.
I added also a thin black line to "close" the drawing, just for aesthetics.
If you can adapt this to your problem, OK, otherwise just ask!
import numpy as np
import matplotlib.pyplot as plt
# point no. 1
from matplotlib.colors import to_rgb
mgt, wht = to_rgb('magenta'), to_rgb('white')
# point no.2
def mix(col0, col1, ratio):
return tuple(cmp0*ratio+cmp1*(1-ratio)
for cmp0, cmp1 in zip(col0, col1))
t = np.linspace(0, 2*np.pi, 629)
# point no. 3, the phase shifts but also the interpolation ratios
for phase_shift in np.linspace(0, 1, 31):
plt.plot(t, np.sin(t-phase_shift), color=mix(wht, mgt, phase_shift))
plt.plot(t, np.sin(t-phase_shift), color='k', lw=0.4)
plt.show()
PS It's better if in production you check that 0 ≤ ratio ≤ 1
, isn't it?
UNTESTED
def lerp(color1, color2, frac):
from matplotlib.colors import to rgb
c1, c2 = (to_rgb(color) for color in (color1, color2))
return tuple(x1*(1-frac) + x2*frac for x1, x2 in zip(c1, c2))
...
plot_polys(circles, [lerp("m", "white", frac) for frac in (0, 0.4, 0.8)])
Upvotes: 2