-1

I would like to sample RGB or HSV colors interpolating from green to blue. However, I want that the mean of the gaussian should be green so that the majority of the set will be dominated by greenish colors. In the end, I want to achieve that when you interpolate from green to blue or red, you start deviating from the crowd. Something like this but the majority should be green..

enter image description here

ece çalıkuş
  • 139
  • 1
  • 3
  • 15
  • I'm not sure what you're asking, but if you're plotting data have a read of the reasoning behind the new default colormaps in matplotlib http://matplotlib.org/users/dflt_style_changes.html – Peter Gibson Mar 28 '17 at 05:53
  • I need data samples in RGB or other color format which fit the distribution i described above. – ece çalıkuş Mar 28 '17 at 06:12
  • Doesn't the ``cmap=cm.jet`` colorbar has its mean at green? So ``cmap(val)`` where val is your sample drawn from gaussian distribution should return what you want. – alexblae Mar 28 '17 at 07:47

2 Answers2

0

One option is the following.
You would first need a colormap which has green in its center. If none of the available standard colormaps works for you, you can built your own colormap. In the simplest case, it would consist of three colors (blue, green, red)

colors = ["blue", "green", "red"]
cmap = matplotlib.colors.LinearSegmentedColormap.from_list("name", colors)

You can then use a normalization instance with its center at the center of the normal distribution. Here we choose it to be at 0; therefore the normalization limits need to be symmetrical about zero.

norm = matplotlib.colors.Normalize(vmin=-3, vmax=3)

Now, having a normal distributed variable x you may sample from the colormap as

sample = cmap(norm(x))

In order to plot this, find a complete example below:

import matplotlib
import matplotlib.pyplot as plt
import numpy as np


n = 600
x = np.random.normal(size=n)
y = np.random.rand(n)

colors = ["blue", "green", "red"]
cmap = matplotlib.colors.LinearSegmentedColormap.from_list("name", colors)
norm = matplotlib.colors.Normalize(vmin=-3, vmax=3)
fig, (ax, ax2) = plt.subplots(nrows=2, figsize=(6,3), 
      gridspec_kw={"height_ratios":[1,3]}, sharex=True)
ax.axis("off")
ax.hist(x, bins=21, edgecolor="k")
sc = ax2.scatter(x,y,s=15, c=x, cmap=cmap, norm=norm)
fig.colorbar(sc, ax=ax2)
cax = fig.colorbar(sc, ax=ax)
cax.ax.set_visible(False)
plt.show()

enter image description here

ImportanceOfBeingErnest
  • 321,279
  • 53
  • 665
  • 712
  • what does the y-axis signify? – Crispin Mar 28 '17 at 09:38
  • The y axis is just used to stretch the points out in space. If they were all on a line, you wouldn't be able to distinguish them anymore. The relevant dimension is the x dimension, which is coded in space and color according to the colormap. – ImportanceOfBeingErnest Mar 28 '17 at 09:42
0

This can be achieved using the HSV color space, for which pure green is at H=120 degrees. You can create a bivariate normal distribution in H-V space of num points centered about a mean and distributed according to the covariance matrix cov:

import numpy as np

num = 1000
mean = [120,0.5] # [hue,value] 
cov = [[20,0],[0,0.01]]
hv = np.random.multivariate_normal(mean,cov,num)

Next, we modulo the matrix so that points beyond the boundaries are looped back in:

hv[:,0] %= 360
hv[:,1] %= 1

Next, we borrow from here to create an RGB map in HS space (V=1):

from matplotlib.colors import hsv_to_rgb
import matplotlib.pyplot as plt

V, H = np.mgrid[0:1:100j, 0:1:300j]

S = np.ones_like(V)
HSV = np.dstack((H,S,V))
RGB = hsv_to_rgb(HSV)

plt.imshow(RGB, origin="lower", extent=[0, 360, 0, 1], aspect=150)

Finally, overlay our distribution onto H-S space:

plt.scatter(hv[:,0],hv[:,1])
plt.show()

enter image description here You can play around with cov to achieve the desired distribution. For example, cov = [[80,0.7],[0.1,0.006]] gives us

enter image description here

Also, you can easily extend this example to three dimensions to consider changes in saturation.

Community
  • 1
  • 1
Crispin
  • 2,070
  • 1
  • 13
  • 16