What exactly is happening under the hood in Normalized colour mapping in matlpotlib?

Viewed 42

I had to make a bar chart of the means of 4 different distributions with error bars in matplotlib where the colours of the bars would change interactively depending on the given Y (mean) value. I used 1.96 for a 95% confidence interval.

stderr = df.std(axis=1)/np.sqrt(n)
norm = Normalize(vmin=-1.96,vmax=1.96)
cmap = get_cmap('PuOr')
Z = (mean.values -y)/stderr.values
normed = norm(Z)

This ensures that the code works as intended. What I would like to know is what exactly is going on when the values in Z:

array([-1.11052123,  2.98511452,  1.0731187 ,  9.30156312])

are getting mapped to the values in normed:

masked_array(data=[0.21670377, 1.26150881, 0.77375477, 2.87284774],
         mask=False,
   fill_value=1e+20)

How exactly is it being mapped? I know from reading the documentation that the values are being mapped to the interval -1.96 to 1.96. What I'd like to know is how exactly 9.30 is mapped to 2.87.

1 Answers

In this case, the norm is just a linear transformation that maps vmin to 0 and vmax to 1. The values outside that range are mapped via the same linear transformation.

When calculating a color, the input values for cmap are considered to be between 0 and 1. If a value larger than 1 is encountered, it is simply mapped to the highest color.

Here is some code and plot to illustrate the behavior:

from matplotlib import pyplot as plt
import numpy as np

norm = plt.Normalize(vmin=-1.96, vmax=1.96)
Z = np.array([-1.11052123, 2.98511452, 1.0731187, 9.30156312])
zs = np.linspace(-3, 10, 50)

plt.imshow(np.linspace(-0.3, 3.2, 200).reshape(-1, 1), extent=[-3, -2.8, -0.3, 3.2], origin='lower',
           cmap='PuOr', vmin=0, vmax=1, aspect='auto')
plt.scatter(zs, norm(zs), c=zs, norm=norm, cmap='PuOr')
plt.vlines(Z, -2, norm(Z), color='crimson', ls='--')
plt.hlines(norm(Z), -3, Z, color='crimson', ls='--')
plt.vlines([-1.96, 1.96], -2, [norm(-1.96), norm(1.96)], color='dodgerblue', ls='--')
plt.hlines([0, 1], -3, [-1.96, 1.96],  color='dodgerblue', ls='--')
plt.ylim(ymin=-0.3)
plt.margins(x=0, tight=True)
plt.xlabel('Z', size=16)
plt.ylabel('norm(Z)', size=16)
plt.show()

illustrating plot

Related