pyplot.cm instance is producing different results for same values but different data type

Question:

This question is in continuation of the solution provided by tcaswell (answer #2) for my question: Is there a way to convert pyplot.imshow() object to numpy array?

Consider the following python code:

import pylab
import numpy as np

a = np.array( ( 30, 129 ) , dtype = np.float32 )
b = np.array( ( 30, 129 ) , dtype = np.int32 )
my_cm = pylab.cm.get_cmap('jet')
a_mapped_data = my_cm( a )
b_mapped_data = my_cm( b )

I am using a small array to save space, but this is what is seen even when large arrays are used.

The results:

>>> a
array([  30.,  129.], dtype=float32)

>>> b
array([ 30, 129])

>>> a_mapped_data
array([[ 0.5,  0. ,  0. ,  1. ],
       [ 0.5,  0. ,  0. ,  1. ]])

>>> b_mapped_data
array([[ 0.        ,  0.        ,  1.        ,  1.        ],
       [ 0.5028463 ,  1.        ,  0.46489564,  1.        ]])

I don’t seem to understand the behavior here. Even though the values are same, cm.get_map() instance is producing different results for numpy.int32 and numpy.float32 data types. Is there something wrong with the code above? Please help out with this. I need to plot 2D arrays of type numpy.float.

I am using python 2.7.3 32bit on Windows7 x64 Home Basic

Asked By: Yash

||

Answers:

From the docstring of my_cm.__call__:

*X* is either a scalar or an array (of any dimension).
If scalar, a tuple of rgba values is returned, otherwise
an array with the new shape = oldshape+(4,). If the X-values
are integers, then they are used as indices into the array.
If they are floating point, then they must be in the
interval (0.0, 1.0).
Alpha must be a scalar between 0 and 1, or None.
If bytes is False, the rgba values will be floats on a
0-1 scale; if True, they will be uint8, 0-255.

Note the difference between how floats and ints are treated.

Answered By: Warren Weckesser

The script below performs a color map on the input data and the map is converted to image as is, without using pylab.imshow or pylab.pcolor and without any scales or borders.

import pylab
import numpy as np

a = np.random.random( (512, 512) )*100
# a is a 2D array of random data not in the range of 0.0 to 1.0

# normalize the data
normed_a = ( a - a.min() )/( a.max() - a.min() )

# now create an instance of pylab.cm.get_cmap()
my_cm = pylab.cm.get_cmap('jet_r')

# create the map
mapped_a = my_cm( normed_a )

# to display the map, opencv is being used
# import opencv
import cv2 as cv

# convert mapped data to 8 bit unsigned int
mapped_au8 = (255 * mapped_a).astype('uint8')

# show the image
cv.imshow( 'a', mapped_au8 )
cv.waitKey( 0 )
cv.destroyAllWindows()

EDIT : Return type cm.get_cmap instance is of RGBA format but OpenCV by default operates on BGR format. Hence before displaying any image obtained by converting return values of cm.get_cmap() instance as in the above code, convert it to BGR format ( The ALPHA channel is anyway stripped by default in opencv before the image is displayed so dont bother to convert it into BGRA unless necessary ). The code below gives a better explanation:

mapped_au8 = (255 * mapped_a).astype('uint8')

#convert mapped_au8 into BGR fromat before display
mapped_u8 = cv.cvtColor( mapped_au8, cv.COLOR_RGBA2BGR )

# show the image
cv.imshow( 'a', mapped_au8 )
cv.waitKey( 0 )
cv.destroyAllWindows()

This answer was posted as an edit to the question pyplot.cm instance is producing different results for same values but different data type by the OP Yash under CC BY-SA 3.0.

Answered By: vvvvv
Categories: questions Tags: , ,
Answers are sorted by their score. The answer accepted by the question owner as the best is marked with
at the top-right corner.